@marcel91200 / caddy Mirror · read-only
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 11, 01:00 UTC

master
go 133 lines 2.69 KB
Raw
1 // Copyright 2015 Matthew Holt and The Caddy Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package caddyfile
16
17 import (
18 "fmt"
19 "slices"
20 )
21
22 type adjacency map[string][]string
23
24 type importGraph struct {
25 nodes map[string]struct{}
26 edges adjacency
27 }
28
29 func (i *importGraph) addNode(name string) {
30 if i.nodes == nil {
31 i.nodes = make(map[string]struct{})
32 }
33 if _, exists := i.nodes[name]; exists {
34 return
35 }
36 i.nodes[name] = struct{}{}
37 }
38
39 func (i *importGraph) addNodes(names []string) {
40 for _, name := range names {
41 i.addNode(name)
42 }
43 }
44
45 func (i *importGraph) removeNode(name string) {
46 delete(i.nodes, name)
47 delete(i.edges, name)
48 for k, targets := range i.edges {
49 i.edges[k] = slices.DeleteFunc(targets, func(t string) bool { return t == name })
50 }
51 }
52
53 func (i *importGraph) removeNodes(names []string) {
54 for _, name := range names {
55 i.removeNode(name)
56 }
57 }
58
59 func (i *importGraph) addEdge(from, to string) error {
60 if !i.exists(from) || !i.exists(to) {
61 return fmt.Errorf("one of the nodes does not exist")
62 }
63
64 if i.willCycle(to, from) {
65 return fmt.Errorf("a cycle of imports exists between %s and %s", from, to)
66 }
67
68 if i.areConnected(from, to) {
69 // if connected, there's nothing to do
70 return nil
71 }
72
73 if i.nodes == nil {
74 i.nodes = make(map[string]struct{})
75 }
76 if i.edges == nil {
77 i.edges = make(adjacency)
78 }
79
80 i.edges[from] = append(i.edges[from], to)
81 return nil
82 }
83
84 func (i *importGraph) addEdges(from string, tos []string) error {
85 for _, to := range tos {
86 err := i.addEdge(from, to)
87 if err != nil {
88 return err
89 }
90 }
91 return nil
92 }
93
94 func (i *importGraph) areConnected(from, to string) bool {
95 al, ok := i.edges[from]
96 if !ok {
97 return false
98 }
99 return slices.Contains(al, to)
100 }
101
102 func (i *importGraph) willCycle(from, to string) bool {
103 if from == to {
104 return true
105 }
106 collector := make(map[string]bool)
107
108 var visit func(string)
109 visit = func(start string) {
110 if !collector[start] {
111 collector[start] = true
112 for _, v := range i.edges[start] {
113 visit(v)
114 }
115 }
116 }
117
118 for _, v := range i.edges[from] {
119 visit(v)
120 }
121 for k := range collector {
122 if to == k {
123 return true
124 }
125 }
126
127 return false
128 }
129
130 func (i *importGraph) exists(key string) bool {
131 _, exists := i.nodes[key]
132 return exists
133 }