diff options
| -rw-r--r-- | README.md | 4 | ||||
| -rw-r--r-- | main.go | 95 | ||||
| -rw-r--r-- | main_test.go | 18 |
3 files changed, 54 insertions, 63 deletions
@@ -48,7 +48,3 @@ At program start, and every minute thereafter: - if there were any lines that we did not see during this read of the file, but that we saw previously, remove them from the scheduler The lines will be formatted like a cron file, but instead of a command, we will simply have the name of the task to be created. - -## Future work - -It turns out jobs can be added AND removed by an ID that is returned from the Add function. It could be interesting to add/remove based on the last seen map (with the job IDs), instead of completely recreating all the jobs if the input file changes. @@ -26,6 +26,8 @@ type InputLine struct { type TaskAddingJob struct { Schedule cron.Schedule Task cron.Job + EntryID cron.EntryID // this doesn't fit super well, but we'll figure that out soon I guess + Delete bool } type Task struct { @@ -39,7 +41,7 @@ func (t Task) Run() { } } -var lastSeenInput = map[InputLine]TaskAddingJob{} +var jobsFromInput = map[InputLine]TaskAddingJob{} var todoistToken string var httpClient = http.Client{ Timeout: 10 * time.Second, @@ -57,25 +59,36 @@ func main() { log.Printf("Started watching '%s'", p) c := cron.New() + c.Start() for { - input, err := readInput(p) + err = readInput(p) if err != nil { log.Printf("Error reading input: %s", err) continue } - if inputChanged(lastSeenInput, input) { - log.Print("Updating task list") - lastSeenInput = input - c.Stop() - c := cron.New() - addJobs(c, input) - c.Start() - log.Print("Done updating task list") + for inputLine, taskAddingJob := range jobsFromInput { + if jobsFromInput[inputLine].EntryID == 0 { + taskAddingJob.EntryID = c.Schedule( + jobsFromInput[inputLine].Schedule, + jobsFromInput[inputLine].Task, + ) + jobsFromInput[inputLine] = taskAddingJob + + log.Printf( + "Added '%s' with recurrence '%s'", + inputLine.RawTask, + inputLine.RawSchedule, + ) + } else if taskAddingJob.Delete { + c.Remove(taskAddingJob.EntryID) + delete(jobsFromInput, inputLine) + log.Printf("Removed '%s'", inputLine.RawTask) + } } - time.Sleep(time.Minute) // re-read the input file every minute + time.Sleep(time.Minute) } } @@ -108,15 +121,19 @@ func inputFilePath() (string, error) { var inputFileRe = regexp.MustCompile(`([^\s]+\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+[^\s]+)\s+(.*)`) -func readInput(p string) (map[InputLine]TaskAddingJob, error) { - input := map[InputLine]TaskAddingJob{} - +func readInput(p string) error { f, err := os.Open(p) if err != nil { - return nil, fmt.Errorf("opening '%s': %w", p, err) + return fmt.Errorf("opening '%s': %w", p, err) } defer f.Close() + previousInput := map[InputLine]struct{}{} + for k := range jobsFromInput { + previousInput[k] = struct{}{} + } + currentInput := map[InputLine]struct{}{} + scanner := bufio.NewScanner(f) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) @@ -135,38 +152,41 @@ func readInput(p string) (map[InputLine]TaskAddingJob, error) { RawTask: matches[2], } + currentInput[inputLine] = struct{}{} + if _, ok := previousInput[inputLine]; ok { + continue + } + schedule, err := cron.ParseStandard(inputLine.RawSchedule) if err != nil { - log.Printf("Failed to add '%s' with recurrence '%s': %s", inputLine.RawTask, inputLine.RawSchedule, err) + log.Printf( + "Failed to add '%s' with recurrence '%s': %s", + inputLine.RawTask, + inputLine.RawSchedule, + err, + ) continue } - job := Task{Name: inputLine.RawTask} - taskAddingJob := TaskAddingJob{ + jobsFromInput[inputLine] = TaskAddingJob{ Schedule: schedule, - Task: job, + Task: Task{Name: inputLine.RawTask}, } - - input[inputLine] = taskAddingJob } - if err := scanner.Err(); err != nil { - return nil, fmt.Errorf("scanning: %w", err) + return fmt.Errorf("scanning: %w", err) } - return input, nil -} - -func inputChanged(old, new map[InputLine]TaskAddingJob) bool { - if len(new) != len(old) { - return true - } - for k := range old { - if _, ok := new[k]; !ok { - return true + // Mark stuff that we previously saw, but is now missing, for pruning. + for k := range previousInput { + if _, ok := currentInput[k]; !ok { + v := jobsFromInput[k] + v.Delete = true + jobsFromInput[k] = v } } - return false + + return nil } func createTask(task string) error { @@ -198,10 +218,3 @@ func createTask(task string) error { log.Printf("Created task '%s'", task) return nil } - -func addJobs(c *cron.Cron, tasks map[InputLine]TaskAddingJob) { - for _, task := range tasks { - _ = c.Schedule(task.Schedule, task.Task) - } - log.Printf("Added %d jobs", len(tasks)) -} diff --git a/main_test.go b/main_test.go deleted file mode 100644 index 3e79bf9..0000000 --- a/main_test.go +++ /dev/null @@ -1,18 +0,0 @@ -package main - -import ( - "testing" -) - -func TestMain(t *testing.T) { - tasks, err := readInput("testdata/test_tasks.txt") - if err != nil { - t.Logf("Expected no error when reading input file, got '%s'", err) - t.FailNow() - } - - if len(tasks) != 3 { - t.Logf("Expected 3 tasks to be parsed, got %d", len(tasks)) - t.FailNow() - } -} |
