blob: 91ae72320a489a02cc4b5044ed995be352f2be37 [file] [log] [blame]
Colin Cross127d2ea2016-11-01 11:10:51 -07001// Copyright 2015 Google Inc. All rights reserved.
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
15package blueprint
16
17import (
18 "fmt"
Colin Cross127d2ea2016-11-01 11:10:51 -070019 "sort"
Colin Cross741e14e2017-12-07 22:02:40 -080020 "strings"
Colin Crosse98d0822018-09-21 15:30:13 -070021
22 "github.com/google/blueprint/pathtools"
Colin Cross127d2ea2016-11-01 11:10:51 -070023)
24
Colin Cross25236982021-04-05 17:20:34 -070025func verifyGlob(key globKey, pattern string, excludes []string, g pathtools.GlobResult) {
Colin Cross127d2ea2016-11-01 11:10:51 -070026 if pattern != g.Pattern {
Colin Cross25236982021-04-05 17:20:34 -070027 panic(fmt.Errorf("Mismatched patterns %q and %q for glob key %q", pattern, g.Pattern, key))
Colin Cross127d2ea2016-11-01 11:10:51 -070028 }
Colin Cross54cb95a2018-02-23 11:09:18 -080029 if len(excludes) != len(g.Excludes) {
Colin Cross25236982021-04-05 17:20:34 -070030 panic(fmt.Errorf("Mismatched excludes %v and %v for glob key %q", excludes, g.Excludes, key))
Colin Cross127d2ea2016-11-01 11:10:51 -070031 }
Colin Cross54cb95a2018-02-23 11:09:18 -080032
33 for i := range excludes {
34 if g.Excludes[i] != excludes[i] {
Colin Cross25236982021-04-05 17:20:34 -070035 panic(fmt.Errorf("Mismatched excludes %v and %v for glob key %q", excludes, g.Excludes, key))
Colin Cross54cb95a2018-02-23 11:09:18 -080036 }
37 }
Colin Cross127d2ea2016-11-01 11:10:51 -070038}
39
40func (c *Context) glob(pattern string, excludes []string) ([]string, error) {
Colin Cross25236982021-04-05 17:20:34 -070041 // Sort excludes so that two globs with the same excludes in a different order reuse the same
42 // key. Make a copy first to avoid modifying the caller's version.
43 excludes = append([]string(nil), excludes...)
44 sort.Strings(excludes)
45
46 key := globToKey(pattern, excludes)
Colin Cross127d2ea2016-11-01 11:10:51 -070047
48 // Try to get existing glob from the stored results
49 c.globLock.Lock()
Colin Cross25236982021-04-05 17:20:34 -070050 g, exists := c.globs[key]
Colin Cross127d2ea2016-11-01 11:10:51 -070051 c.globLock.Unlock()
52
53 if exists {
54 // Glob has already been done, double check it is identical
Colin Cross25236982021-04-05 17:20:34 -070055 verifyGlob(key, pattern, excludes, g)
Colin Crossa64ca942021-01-21 13:47:59 -080056 // Return a copy so that modifications don't affect the cached value.
Colin Cross67c99252021-04-07 14:28:13 -070057 return append([]string(nil), g.Matches...), nil
Colin Cross127d2ea2016-11-01 11:10:51 -070058 }
59
60 // Get a globbed file list
Colin Cross67c99252021-04-07 14:28:13 -070061 result, err := c.fs.Glob(pattern, excludes, pathtools.FollowSymlinks)
Colin Cross127d2ea2016-11-01 11:10:51 -070062 if err != nil {
63 return nil, err
64 }
65
66 // Store the results
67 c.globLock.Lock()
Colin Cross25236982021-04-05 17:20:34 -070068 if g, exists = c.globs[key]; !exists {
69 c.globs[key] = result
Colin Cross127d2ea2016-11-01 11:10:51 -070070 }
71 c.globLock.Unlock()
72
Colin Cross127d2ea2016-11-01 11:10:51 -070073 if exists {
Colin Cross67c99252021-04-07 14:28:13 -070074 // Getting the list raced with another goroutine, throw away the results and use theirs
Colin Cross25236982021-04-05 17:20:34 -070075 verifyGlob(key, pattern, excludes, g)
Colin Crossa64ca942021-01-21 13:47:59 -080076 // Return a copy so that modifications don't affect the cached value.
Colin Cross67c99252021-04-07 14:28:13 -070077 return append([]string(nil), g.Matches...), nil
Colin Cross127d2ea2016-11-01 11:10:51 -070078 }
79
Colin Crossa64ca942021-01-21 13:47:59 -080080 // Return a copy so that modifications don't affect the cached value.
Colin Cross67c99252021-04-07 14:28:13 -070081 return append([]string(nil), result.Matches...), nil
Colin Cross127d2ea2016-11-01 11:10:51 -070082}
83
Colin Cross25236982021-04-05 17:20:34 -070084func (c *Context) Globs() pathtools.MultipleGlobResults {
85 keys := make([]globKey, 0, len(c.globs))
Colin Cross127d2ea2016-11-01 11:10:51 -070086 for k := range c.globs {
Colin Cross25236982021-04-05 17:20:34 -070087 keys = append(keys, k)
Colin Cross127d2ea2016-11-01 11:10:51 -070088 }
Colin Cross127d2ea2016-11-01 11:10:51 -070089
Colin Cross25236982021-04-05 17:20:34 -070090 sort.Slice(keys, func(i, j int) bool {
91 if keys[i].pattern != keys[j].pattern {
92 return keys[i].pattern < keys[j].pattern
93 }
94 return keys[i].excludes < keys[j].excludes
95 })
96
97 globs := make(pathtools.MultipleGlobResults, len(keys))
98 for i, key := range keys {
99 globs[i] = c.globs[key]
Colin Cross127d2ea2016-11-01 11:10:51 -0700100 }
101
102 return globs
103}
104
Colin Cross25236982021-04-05 17:20:34 -0700105// globKey combines a pattern and a list of excludes into a hashable struct to be used as a key in
106// a map.
107type globKey struct {
108 pattern string
109 excludes string
Colin Cross127d2ea2016-11-01 11:10:51 -0700110}
111
Colin Cross25236982021-04-05 17:20:34 -0700112// globToKey converts a pattern and an excludes list into a globKey struct that is hashable and
113// usable as a key in a map.
114func globToKey(pattern string, excludes []string) globKey {
115 return globKey{pattern, strings.Join(excludes, "|")}
Colin Cross127d2ea2016-11-01 11:10:51 -0700116}