-
Notifications
You must be signed in to change notification settings - Fork 1
/
vdir.go
139 lines (124 loc) · 2.92 KB
/
vdir.go
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
// The vdir package implements a simple library to interact with vdir
// filesystem storage: https://vdirsyncer.pimutils.org/en/stable/vdir.html
package vdir
import (
"errors"
"fmt"
"io/fs"
"log"
"os"
"path/filepath"
"github.com/emersion/go-ical"
)
// Vdir is a map of all collections and items
type Vdir map[*Collection][]*Item
// Init initializes the map with collections and items in path, items have unique IDs
func (v *Vdir) Init(path string) error {
f, err := os.Stat(path)
if errors.Is(err, fs.ErrNotExist) {
return fmt.Errorf("Vdir path does not exist: %q", path)
}
if !f.IsDir() {
return fmt.Errorf("Vdir path is not a directory: %q", path)
}
var itemId int
walkFunc := func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() && hasIcalFiles(path) {
c := &Collection{}
if err := c.Init(path); err != nil {
return err
}
// parse collection folder for ical files
err = filepath.WalkDir(
c.Path,
func(pp string, dd fs.DirEntry, err error) error {
if isIcal(pp, dd) {
item := new(Item)
if err := item.Init(pp); err != nil {
log.Println(err)
}
if item.Ical != nil {
itemId++
item.Id = itemId
(*v)[c] = append((*v)[c], item)
}
}
return nil
},
)
if err != nil {
return err
}
}
return nil
}
err = filepath.WalkDir(path, walkFunc)
if err != nil {
return err
}
return nil
}
// ItemById finds and returns an item for specified id
func (v *Vdir) ItemById(id int) (*Item, error) {
for _, items := range *v {
for _, item := range items {
if item.Id == id {
return item, nil
}
}
}
return nil, fmt.Errorf("Item not found: %d", id)
}
// ItemByPath finds and returns an item for specified path
func (v *Vdir) ItemByPath(path string) (*Item, error) {
for _, items := range *v {
for _, item := range items {
if item.Path == path {
return item, nil
}
}
}
return nil, fmt.Errorf("Item not found: %q", path)
}
// Tags returns a slice of all tags found in todos inside vdir
func (v *Vdir) Tags() (tags []Tag, err error) {
containsTag := func(tags []Tag, tag Tag) bool {
for _, t := range tags {
if tag == t {
return true
}
}
return false
}
for _, items := range *v {
for _, item := range items {
tt, err := item.Tags()
if err != nil {
return tags, err
}
for _, tag := range tt {
if !containsTag(tags, tag) {
tags = append(tags, tag)
}
}
}
}
return
}
// isIcal reports whether path is a file that has an ical extension
func isIcal(path string, de fs.DirEntry) bool {
return !de.IsDir() && filepath.Ext(path) == fmt.Sprintf(".%s", ical.Extension)
}
// hasIcalFiles reports whether path contains ical files
func hasIcalFiles(path string) bool {
files, _ := os.ReadDir(path)
for _, f := range files {
if filepath.Ext(f.Name()) == fmt.Sprintf(".%s", ical.Extension) {
return true
}
}
return false
}