Compare commits
7 commits
cb742395cc
...
426925c6a7
Author | SHA1 | Date | |
---|---|---|---|
426925c6a7 | |||
253dc4ba37 | |||
417536f1b5 | |||
978da38001 | |||
ec5ff47449 | |||
c6cb3dd6c3 | |||
787a24c6dc |
4 changed files with 123 additions and 40 deletions
|
@ -1,13 +0,0 @@
|
||||||
# You can override the included template(s) by including variable overrides
|
|
||||||
# SAST customization: https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings
|
|
||||||
# Secret Detection customization: https://docs.gitlab.com/ee/user/application_security/secret_detection/#customizing-settings
|
|
||||||
# Dependency Scanning customization: https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#customizing-the-dependency-scanning-settings
|
|
||||||
# Note that environment variables can be set in several places
|
|
||||||
# See https://docs.gitlab.com/ee/ci/variables/#cicd-variable-precedence
|
|
||||||
stages:
|
|
||||||
- test
|
|
||||||
sast:
|
|
||||||
stage: test
|
|
||||||
include:
|
|
||||||
- template: Security/SAST.gitlab-ci.yml
|
|
||||||
|
|
53
README.md
53
README.md
|
@ -12,13 +12,52 @@ More specifically, it:
|
||||||
(marked with an empty `[ ] ` at the beginning of their line)
|
(marked with an empty `[ ] ` at the beginning of their line)
|
||||||
* adds an entry for today's date if none exists yet and populates it with due/overdue tasks from `taskwarrior`
|
* adds an entry for today's date if none exists yet and populates it with due/overdue tasks from `taskwarrior`
|
||||||
|
|
||||||
|
To accomplish this it borrows a little from the [todo.txt](http://todotxt.org/) syntax ---
|
||||||
|
namely the idea of (A) (B) (C) prioritization and `x task done syntax`
|
||||||
|
(i.e. starting a line with `x ` or `[x] ` means it represents an accomplished task).
|
||||||
|
|
||||||
All three of these operations *only* operate on entries which are marked with a special title (`todotxt` by default),
|
All three of these operations *only* operate on entries which are marked with a special title (`todotxt` by default),
|
||||||
though this can be changed through a regex option.
|
though this can be changed through a regex option.
|
||||||
That means, it is also entirely possible to have other entries (with the same date) which will simply be ignored by the script.
|
That means, it is also entirely possible to have other entries (with the same date) which will simply be ignored by the script.
|
||||||
|
|
||||||
To accomplish this it borrows a little from the [todo.txt](http://todotxt.org/) syntax ---
|
Lastly, it transfers what I call 'ideas' to `taskwarrior`.
|
||||||
namely the idea of (A) (B) (C) prioritization and `x task done syntax`
|
These are small tidbits and notions I jot down during the day (hence, 'ideas')
|
||||||
(i.e. starting a line with `x ` or `[x] ` means it represents an accomplished task).
|
and marked as such by starting the line either with `idea: ` or the `taskwarrior` equivalent `+idea `.
|
||||||
|
I want them transferred to `taskwarrior` so they don't get lost overall,
|
||||||
|
but they should be
|
||||||
|
a) not bound to a specific date, even when written in a specific `jrnl` entry, and
|
||||||
|
b) specifically marked as vague ideas in `taskwarrior`.
|
||||||
|
For now, they will be applied the fixed tags `+idea +maybe` in `taskwarrior` and simply
|
||||||
|
transferred date-less.
|
||||||
|
|
||||||
|
An example `jrnl` file:
|
||||||
|
|
||||||
|
```jrnl
|
||||||
|
[2021-10-30 10:16] todotxt
|
||||||
|
This is just a test entry. It shows how tasks in todo blocks are handled.
|
||||||
|
[ ] This is an incomplete task - it will be transferred directly to tw.
|
||||||
|
[x] This is a completed task - it will be logged as completed in tw.
|
||||||
|
[ ] (A) This is an incomplete task which will get assigned high priority in taskwarrior.
|
||||||
|
x This is also a completed task, as long as the x is the first thing on the line with a space behind.
|
||||||
|
x All four of these tasks will be transferred to tw, and their lines deleted from this file.
|
||||||
|
|
||||||
|
idea: This is an idea and it will be transferred to tw with corresponding tags, then deleted from this file.
|
||||||
|
|
||||||
|
This is not a task but a normal line and will remain in the file.
|
||||||
|
xAs will this,
|
||||||
|
[ ]As will this.
|
||||||
|
|
||||||
|
[ ] This will be transferred again, however.
|
||||||
|
|
||||||
|
[2021-10-29 10:16] Another entry
|
||||||
|
This is a regular jrnl entry, since it is missing the correct title.
|
||||||
|
By default it looks for `todotxt` titles,
|
||||||
|
but the title can be freely set for the script (`-b` option).
|
||||||
|
jrnlwarrior will not look for incomplete or completed tasks within this block at all.
|
||||||
|
[x] This is a completed task, but it will not be transferred to taskwarrior.
|
||||||
|
[ ] Neither will this incomplete task.
|
||||||
|
+idea This idea however *will* be transferred, since ideas are looked for in *all* entries.
|
||||||
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
@ -49,21 +88,21 @@ lines to be removed from the file and any to-do entries added to the file.
|
||||||
It will not change your `jrnl` file in any way.
|
It will not change your `jrnl` file in any way.
|
||||||
|
|
||||||
If you want to switch off one of the three ways this script connects the two,
|
If you want to switch off one of the three ways this script connects the two,
|
||||||
you can use the `-L`, `-I`, `-T` options which turn off logging, adding, or creating entries respectively.
|
you can use the `-L`, `-I`, `-T`, `-D` options which turn off [*L*]ogging completed to `taskwarrior`, [*I*]nserting incomplete to `taskwarrior`, creating new `jrnl` entries for [*T*]oday's tasks, or moving hatched i[*D*]eas to `taskwarrior` respectively.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./jrnlwarrior.py -I -T
|
./jrnlwarrior.py -DIT
|
||||||
```
|
```
|
||||||
|
|
||||||
The above invocation will *only* log completed tasks to `taskwarrior`.
|
The above invocation will *only* log completed tasks to `taskwarrior`.
|
||||||
Adding new to-dos and creating today entries is turned off.
|
Adding new to-dos, ideas and creating today entries is turned off.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./jrnlwarrior.py -T
|
./jrnlwarrior.py -T
|
||||||
```
|
```
|
||||||
|
|
||||||
This will create a one-way connection to `taskwarrior`,
|
This will create a one-way connection to `taskwarrior`,
|
||||||
by transferring both new and completed tasks to the program.
|
by transferring both new and completed tasks and ideas to the program.
|
||||||
However, tasks to be done today will not be transferred back to this file.
|
However, tasks to be done today will not be transferred back to this file.
|
||||||
|
|
||||||
## Scope
|
## Scope
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from subprocess import Popen, PIPE, check_output
|
import subprocess
|
||||||
import options as opts
|
import options as opts
|
||||||
import json
|
import json
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
@ -35,11 +35,15 @@ def process_file(options):
|
||||||
fname = options.jrnl_fname
|
fname = options.jrnl_fname
|
||||||
lines_to_delete = []
|
lines_to_delete = []
|
||||||
today_exists = False
|
today_exists = False
|
||||||
|
curdate = ""
|
||||||
with open(fname) as file:
|
with open(fname) as file:
|
||||||
line_number = 0
|
line_number = 0
|
||||||
for line in file:
|
for line in file:
|
||||||
line_number += 1
|
line_number += 1
|
||||||
|
|
||||||
|
if handle_idea(line, options):
|
||||||
|
lines_to_delete.append(line_number)
|
||||||
|
|
||||||
todo_block = get_todo_block_date(line, options.todo_block_title)
|
todo_block = get_todo_block_date(line, options.todo_block_title)
|
||||||
if todo_block == False:
|
if todo_block == False:
|
||||||
curdate = ""
|
curdate = ""
|
||||||
|
@ -91,7 +95,7 @@ def log_completed_to_taskwarrior(task_string, date, options):
|
||||||
if options.dryrun:
|
if options.dryrun:
|
||||||
print(cmd)
|
print(cmd)
|
||||||
return
|
return
|
||||||
Popen(cmd)
|
subprocess.run(cmd)
|
||||||
|
|
||||||
|
|
||||||
def handle_open_tasks(line, date, options):
|
def handle_open_tasks(line, date, options):
|
||||||
|
@ -119,7 +123,34 @@ def add_incomplete_to_taskwarrior(task_string, date, options):
|
||||||
if options.dryrun:
|
if options.dryrun:
|
||||||
print(cmd)
|
print(cmd)
|
||||||
return
|
return
|
||||||
Popen(cmd)
|
subprocess.run(cmd)
|
||||||
|
|
||||||
|
|
||||||
|
def handle_idea(line, options):
|
||||||
|
completed_task = re.search(
|
||||||
|
rf"^{options.regex_task_idea} (.*)",
|
||||||
|
line,
|
||||||
|
)
|
||||||
|
if completed_task and options.taskwarrior_add_ideas:
|
||||||
|
add_idea_to_taskwarrior(completed_task[1], options)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def add_idea_to_taskwarrior(idea_string, options):
|
||||||
|
overrides = options.taskwarrior_overrides
|
||||||
|
cmd = [
|
||||||
|
"task",
|
||||||
|
*overrides,
|
||||||
|
"add",
|
||||||
|
"+idea",
|
||||||
|
"+maybe",
|
||||||
|
idea_string,
|
||||||
|
]
|
||||||
|
if options.dryrun:
|
||||||
|
print(cmd)
|
||||||
|
return
|
||||||
|
subprocess.run(cmd)
|
||||||
|
|
||||||
|
|
||||||
def get_prio_string(task_string):
|
def get_prio_string(task_string):
|
||||||
|
@ -160,21 +191,23 @@ def is_today(cur_date):
|
||||||
|
|
||||||
|
|
||||||
def add_today(fname, options):
|
def add_today(fname, options):
|
||||||
cmd = ["task", "+TODAY or +OVERDUE", "export"]
|
cmd = ["task", *options.taskwarrior_overrides, "+TODAY or +OVERDUE", "export"]
|
||||||
|
due_json = json.loads(subprocess.run(cmd, capture_output=True).stdout)
|
||||||
|
|
||||||
tasks = f"[{TODAY} 09:00] {options.todo_block_title}\n"
|
tasks = f"[{TODAY} 09:00] {options.todo_block_title}\n"
|
||||||
for task in json.loads(check_output(cmd)):
|
for task in due_json:
|
||||||
tasks += f"{task['description']}\n"
|
tasks += f"{task['description']}\n"
|
||||||
|
tasks += "\n"
|
||||||
|
|
||||||
if options.dryrun:
|
if options.dryrun:
|
||||||
print(f"\nWRITING TODAY:\n{tasks}")
|
print(f"\nWRITING TODAY:\n{tasks}")
|
||||||
return
|
return
|
||||||
|
|
||||||
repl_file = fname + ".bak"
|
repl_fname = fname + ".bak"
|
||||||
with open(fname) as read_file, open(repl_file, "w") as write_file:
|
with open(fname, "r") as read_file, open(repl_fname, "w") as write_file:
|
||||||
write_file.write(tasks + "\n")
|
write_file.write(tasks)
|
||||||
for line in read_file:
|
write_file.write(read_file.read())
|
||||||
write_file.write(line)
|
os.rename(repl_fname, fname)
|
||||||
os.rename(repl_file, fname)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
34
options.py
34
options.py
|
@ -1,4 +1,5 @@
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
import argparse
|
import argparse
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from typing import List
|
from typing import List
|
||||||
|
@ -6,13 +7,15 @@ from typing import List
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Options:
|
class Options:
|
||||||
# can be changed
|
jrnl_fname: str = field(
|
||||||
jrnl_fname: str = f"{os.path.expanduser('~')}/documents/records/todo.md"
|
default_factory=lambda: f"{os.environ.get('XDG_DATA_HOME', os.environ.get('HOME'))}/jrnl/journal.txt"
|
||||||
|
)
|
||||||
todo_block_title: str = "todotxt"
|
todo_block_title: str = "todotxt"
|
||||||
dryrun: bool = False
|
dryrun: bool = False
|
||||||
taskwarrior_log_completed: bool = True
|
taskwarrior_log_completed: bool = True
|
||||||
taskwarrior_add_incomplete: bool = True
|
taskwarrior_add_incomplete: bool = True
|
||||||
taskwarrior_fill_today: bool = True
|
taskwarrior_fill_today: bool = True
|
||||||
|
taskwarrior_add_ideas: bool = True
|
||||||
|
|
||||||
# can not yet be changed
|
# can not yet be changed
|
||||||
taskwarrior_overrides: List = field(
|
taskwarrior_overrides: List = field(
|
||||||
|
@ -24,13 +27,18 @@ class Options:
|
||||||
)
|
)
|
||||||
regex_task_completed: str = r"(?:x|\[x\])"
|
regex_task_completed: str = r"(?:x|\[x\])"
|
||||||
regex_task_incomplete: str = r"\[ \]"
|
regex_task_incomplete: str = r"\[ \]"
|
||||||
|
regex_task_idea: str = r"(?:idea:|\+idea)"
|
||||||
|
|
||||||
|
|
||||||
def init():
|
def init():
|
||||||
opt = Options()
|
opt = Options()
|
||||||
parse_cmdline_args(opt)
|
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
create_cmdline_args(parser)
|
||||||
|
parse_cmdline_args(parser, opt)
|
||||||
if opt.dryrun:
|
if opt.dryrun:
|
||||||
dryrun_show_options(opt)
|
dryrun_show_options(opt)
|
||||||
|
validate_opts(opt)
|
||||||
return opt
|
return opt
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,8 +46,7 @@ def dryrun_show_options(options):
|
||||||
print(options)
|
print(options)
|
||||||
|
|
||||||
|
|
||||||
def parse_cmdline_args(options):
|
def create_cmdline_args(parser):
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-n", "--dryrun", help="only simulate and print changes", action="store_true"
|
"-n", "--dryrun", help="only simulate and print changes", action="store_true"
|
||||||
)
|
)
|
||||||
|
@ -63,6 +70,15 @@ def parse_cmdline_args(options):
|
||||||
help="don't add today's todo items as entry to file",
|
help="don't add today's todo items as entry to file",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-D",
|
||||||
|
"--noidea",
|
||||||
|
help="don't add ideas as maybe items to taskwarrior",
|
||||||
|
action="store_true",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_cmdline_args(parser, options):
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if args.dryrun:
|
if args.dryrun:
|
||||||
|
@ -71,6 +87,8 @@ def parse_cmdline_args(options):
|
||||||
options.taskwarrior_log_completed = False
|
options.taskwarrior_log_completed = False
|
||||||
if args.noincomplete:
|
if args.noincomplete:
|
||||||
options.taskwarrior_add_incomplete = False
|
options.taskwarrior_add_incomplete = False
|
||||||
|
if args.noidea:
|
||||||
|
options.taskwarrior_add_ideas = False
|
||||||
if args.nofilltoday:
|
if args.nofilltoday:
|
||||||
options.taskwarrior_fill_today = False
|
options.taskwarrior_fill_today = False
|
||||||
if args.file:
|
if args.file:
|
||||||
|
@ -79,3 +97,9 @@ def parse_cmdline_args(options):
|
||||||
options.todo_block_title = args.blocktitle
|
options.todo_block_title = args.blocktitle
|
||||||
|
|
||||||
return options
|
return options
|
||||||
|
|
||||||
|
|
||||||
|
def validate_opts(options):
|
||||||
|
if not os.path.isfile(options.jrnl_fname):
|
||||||
|
print(f"{options.jrnl_fname} does not seem to be a file. Aborting.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
Loading…
Reference in a new issue