]> Cypherpunks.ru repositories - goredo.git/blob - targets.go
e19b90acb84e99c90acd5bc0d8c46e84d1313252
[goredo.git] / targets.go
1 /*
2 goredo -- djb's redo implementation on pure Go
3 Copyright (C) 2020-2024 Sergey Matveev <stargrave@stargrave.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, version 3 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 package main
19
20 import (
21         "io"
22         "os"
23         "path"
24         "strings"
25 )
26
27 func targetsCollect(root string, tgts map[string]struct{}) error {
28         dir, err := os.Open(root)
29         if err != nil {
30                 return ErrLine(err)
31         }
32         defer dir.Close()
33         for {
34                 entries, err := dir.ReadDir(1 << 10)
35                 if err != nil {
36                         if err == io.EOF {
37                                 break
38                         }
39                         return ErrLine(err)
40                 }
41                 for _, entry := range entries {
42                         if !entry.IsDir() {
43                                 continue
44                         }
45                         pth := path.Join(root, entry.Name())
46                         if entry.Name() == RedoDir {
47                                 redoDir, err := os.Open(pth)
48                                 if err != nil {
49                                         return ErrLine(err)
50                                 }
51                                 redoEntries, err := redoDir.ReadDir(0)
52                                 redoDir.Close()
53                                 if err != nil {
54                                         return ErrLine(err)
55                                 }
56                                 for _, redoEntry := range redoEntries {
57                                         name := redoEntry.Name()
58                                         if strings.HasSuffix(name, DepSuffix) {
59                                                 name = cwdMustRel(root, name)
60                                                 tgts[name[:len(name)-len(DepSuffix)]] = struct{}{}
61                                         }
62                                 }
63                         } else {
64                                 if err = targetsCollect(pth, tgts); err != nil {
65                                         return err
66                                 }
67                         }
68                 }
69         }
70         return nil
71 }
72
73 func targetsWalker(tgts []string) ([]string, error) {
74         tgtsMap := make(map[string]struct{})
75         for _, tgt := range tgts {
76                 if err := targetsCollect(mustAbs(tgt), tgtsMap); err != nil {
77                         return nil, err
78                 }
79         }
80         tgts = make([]string, 0, len(tgtsMap))
81         for tgt := range tgtsMap {
82                 tgts = append(tgts, tgt)
83         }
84         return tgts, nil
85 }
86
87 func collectWholeDeps(
88         tgts map[string]*Tgt,
89         deps map[string]map[string]*Tgt,
90         seen map[string]*Tgt,
91 ) {
92         for _, tgt := range tgts {
93                 if _, exists := seen[tgt.rel]; exists {
94                         continue
95                 }
96                 seen[tgt.rel] = tgt
97                 collectWholeDeps(deps[tgt.rel], deps, seen)
98         }
99 }