...
1 package desktop
2
3 import (
4 "log"
5 "os"
6 "path/filepath"
7 "runtime"
8 "strings"
9 "sync"
10 )
11
12 const bufferSize = 32 * 1024
13
14 type scan struct {
15 e [][]*Entry
16 errs chan error
17 in chan *scanEntry
18 sync.Mutex
19 sync.WaitGroup
20 }
21
22 type scanEntry struct {
23 i int
24 f *os.File
25 }
26
27
28
29 func Scan(dirs []string) ([][]*Entry, error) {
30 s := &scan{e: make([][]*Entry, len(dirs)), errs: make(chan error), in: make(chan *scanEntry)}
31
32 for i := 0; i < runtime.GOMAXPROCS(-1); i++ {
33 go scanner(s)
34 }
35
36 for i, dir := range dirs {
37 i, dir := i, dir
38
39 s.Add(1)
40 go scanDir(i, dir, s)
41 }
42
43 done := make(chan bool, 1)
44 go func() {
45 s.Wait()
46 close(s.in)
47
48 done <- true
49 }()
50
51 select {
52 case err := <-s.errs:
53 return nil, err
54 case <-done:
55 return s.e, nil
56 }
57 }
58
59 func scanner(s *scan) {
60 var (
61 buf = make([]byte, bufferSize)
62 scanEntry *scanEntry
63 entry *Entry
64 err error
65 )
66
67 for scanEntry = range s.in {
68 entry, err = Parse(scanEntry.f, buf)
69 scanEntry.f.Close()
70 if err != nil {
71 s.errs <- err
72 s.Done()
73 return
74 } else if entry == nil {
75 s.Done()
76 continue
77 }
78
79 s.Lock()
80 s.e[scanEntry.i] = append(s.e[scanEntry.i], entry)
81 s.Unlock()
82
83 s.Done()
84 }
85 }
86
87 func scanFile(i int, dir string, e os.DirEntry, s *scan) {
88 if e == nil || e.IsDir() || !strings.HasSuffix(strings.ToLower(e.Name()), ".desktop") {
89 s.Done()
90 return
91 }
92
93 f, err := os.OpenFile(filepath.Join(dir, e.Name()), os.O_RDONLY, 0644)
94 if os.IsNotExist(err) {
95 s.Done()
96 return
97 } else if err != nil {
98
99 s.errs <- err
100 s.Done()
101 return
102 }
103
104 s.in <- &scanEntry{i: i, f: f}
105 }
106
107 func scanDir(i int, dir string, s *scan) {
108 defer s.Done()
109
110 dirEntries, err := os.ReadDir(dir)
111 if os.IsNotExist(err) {
112 return
113 } else if err != nil {
114 log.Fatal(err)
115 }
116
117 for _, dirEntry := range dirEntries {
118 s.Add(1)
119 go scanFile(i, dir, dirEntry, s)
120 }
121 }
122
View as plain text