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