~whynothugo/autovdirsyncer

ref: 05c0a0c4 autovdirsyncer/main.go -rw-r--r-- 2.6 KiB
05c0a0c4Hugo Osvaldo Barrera aur: Add make target to push updates 3 months ago
                                                                                
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
package main

import (
	"fmt"
	"io/fs"
	"os"
	"os/exec"
	"path/filepath"
	"sync"
	"time"

	"github.com/fsnotify/fsnotify"
)

var (
	vdirsyncerIsRunning sync.Mutex
	passiveInterval     time.Duration // Period between automatic syncs if nothing happens.
	activeDebounce      time.Duration // Period to debounce when changes are happening.
)

func runSynchronization() {
	vdirsyncerIsRunning.Lock()

	cmd := exec.Command("vdirsyncer", "sync")
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	err := cmd.Run()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error running vdirsyncer: %v.\n", err.Error())

		if exitError, ok := err.(*exec.ExitError); ok {
			fmt.Fprintf(
				os.Stderr,
				"Got exit code %d from vdirsyncer: %v.\n",
				exitError.ExitCode(),
				err.Error(),
			)
		}
	}
	fmt.Println("vdirsyncer ran successfully.")

	vdirsyncerIsRunning.Unlock()
}

func scheduleSynchronizations(timer *time.Timer) {
	for {
		<-timer.C
		runSynchronization()
		timer.Reset(passiveInterval)
	}
}

func listenForEvents(watcher *fsnotify.Watcher, timer *time.Timer) {
	for {
		select {
		case event, ok := <-watcher.Events:
			if !ok {
				return
			}
			// fsnotify only sends write-events, so we don't need
			// to check the event type (e.g. there are no "open" or
			// "read" events).

			fmt.Println("File altered:", event.Name)
			// XXX: If changes happen continuously within two
			// second intervals, sync never happens.
			timer.Reset(activeDebounce)
		case err, ok := <-watcher.Errors:
			if !ok {
				return
			}
			fmt.Println("error:", err)
		}
	}
}

func addDirsToWatcher(watcher *fsnotify.Watcher) error {
	baseDir := "/home/hugo/.local/share/calendars/"

	return filepath.WalkDir(baseDir, func(path string, d fs.DirEntry, err error) error {
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to read path %q: %v.\n", path, err)
			return err
		}
		if d.IsDir() {
			fmt.Printf("Listening for changes on %+v \n", path)
			err = watcher.Add(path)
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
		}
		return nil
	})
}

func main() {
	var err error

	// Frequency with which updates run.
	passiveInterval, err = time.ParseDuration("15m")
	if err != nil {
		fmt.Println(err)
		os.Exit(2)
	}

	activeDebounce, err = time.ParseDuration("2s")
	if err != nil {
		fmt.Println(err)
		os.Exit(2)
	}

	// Watcher that monitors for local fs changes.
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		fmt.Println(err)
		os.Exit(3)
	}
	defer watcher.Close()

	err = addDirsToWatcher(watcher)
	if err != nil {
		fmt.Println(err)
		os.Exit(3)
	}

	timer := time.NewTimer(passiveInterval)

	go listenForEvents(watcher, timer)
	go scheduleSynchronizations(timer)

	// Never exit.
	select {}
}