]> Cypherpunks.ru repositories - goredo.git/blob - targets.go
DRY filepath.Abs/Rel
[goredo.git] / targets.go
1 /*
2 goredo -- djb's redo implementation on pure Go
3 Copyright (C) 2020-2023 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         root = mustAbs(root)
29         dir, err := os.Open(root)
30         if err != nil {
31                 return ErrLine(err)
32         }
33         defer dir.Close()
34         for {
35                 entries, err := dir.ReadDir(1 << 10)
36                 if err != nil {
37                         if err == io.EOF {
38                                 break
39                         }
40                         return ErrLine(err)
41                 }
42                 for _, entry := range entries {
43                         if !entry.IsDir() {
44                                 continue
45                         }
46                         pth := path.Join(root, entry.Name())
47                         if entry.Name() == RedoDir {
48                                 redoDir, err := os.Open(pth)
49                                 if err != nil {
50                                         return ErrLine(err)
51                                 }
52                                 redoEntries, err := redoDir.ReadDir(0)
53                                 redoDir.Close()
54                                 if err != nil {
55                                         return ErrLine(err)
56                                 }
57                                 for _, redoEntry := range redoEntries {
58                                         name := redoEntry.Name()
59                                         if strings.HasSuffix(name, DepSuffix) {
60                                                 name = cwdMustRel(root, name)
61                                                 tgts[name[:len(name)-len(DepSuffix)]] = struct{}{}
62                                         }
63                                 }
64                         } else {
65                                 if err = targetsCollect(pth, tgts); err != nil {
66                                         return err
67                                 }
68                         }
69                 }
70         }
71         return nil
72 }
73
74 func targetsWalker(tgts []string) ([]string, error) {
75         tgtsMap := map[string]struct{}{}
76         for _, tgt := range tgts {
77                 if err := targetsCollect(tgt, tgtsMap); err != nil {
78                         return nil, err
79                 }
80         }
81         tgts = make([]string, 0, len(tgtsMap))
82         for tgt := range tgtsMap {
83                 tgts = append(tgts, tgt)
84         }
85         return tgts, nil
86 }
87
88 func collectWholeDeps(
89         tgts map[string]struct{},
90         deps map[string]map[string]struct{},
91         seen map[string]struct{},
92 ) {
93         for tgt := range tgts {
94                 seen[tgt] = struct{}{}
95                 collectWholeDeps(deps[tgt], deps, seen)
96         }
97 }