1// Copyright 2022 The Bazel Authors. 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 respipe 16 17import ( 18 "context" 19 "fmt" 20 "os" 21 "path/filepath" 22 23 "src/tools/ak/res/res" 24) 25 26// EmitPathInfos takes the list of provided PathInfos and emits them via its returned channel. 27func EmitPathInfos(ctx context.Context, pis []*res.PathInfo) <-chan *res.PathInfo { 28 // produce PathInfos from res files 29 piC := make(chan *res.PathInfo) 30 go func() { 31 defer close(piC) 32 for _, pi := range pis { 33 select { 34 case piC <- pi: 35 case <-ctx.Done(): 36 return 37 } 38 } 39 }() 40 return piC 41} 42 43// EmitPathInfosDir descends a provided directory and emits PathInfo objects via its returned 44// channel. It also emits any errors encountered during the walk to its error channel. 45func EmitPathInfosDir(ctx context.Context, base string) (<-chan *res.PathInfo, <-chan error) { 46 piC := make(chan *res.PathInfo) 47 errC := make(chan error) 48 go func() { 49 defer close(piC) 50 defer close(errC) 51 emit := func(path string, info os.FileInfo, err error) error { 52 if err != nil { 53 return fmt.Errorf("%s: walk failed: %v", path, err) 54 } 55 if info.IsDir() { 56 // we do not care about dirs. 57 return nil 58 } 59 pi, err := res.ParsePath(path) 60 if err == res.ErrNotResPath || err == res.ErrSkipResPath { 61 return nil 62 } 63 if err != nil { 64 if !SendErr(ctx, errC, Errorf(ctx, "%s: unexpected PathInfo failure: %v", path, err)) { 65 return filepath.SkipDir 66 } 67 return nil 68 } 69 select { 70 case <-ctx.Done(): 71 return filepath.SkipDir 72 case piC <- &pi: 73 } 74 return nil 75 } 76 if err := filepath.Walk(base, emit); err != nil { 77 SendErr(ctx, errC, Errorf(ctx, "%s: walk encountered err: %v", base, err)) 78 } 79 }() 80 return piC, errC 81} 82 83// EmitPathInfosDirs descends a provided directories and emits PathsInfo objects via its returned 84// channel. It also emits any errors encountered during the walk to its error channel. 85func EmitPathInfosDirs(ctx context.Context, dirs []string) (<-chan *res.PathInfo, <-chan error) { 86 piCs := make([]<-chan *res.PathInfo, 0, len(dirs)) 87 errCs := make([]<-chan error, 0, len(dirs)) 88 for _, rd := range dirs { 89 piC, piErr := EmitPathInfosDir(ctx, rd) 90 piCs = append(piCs, piC) 91 errCs = append(errCs, piErr) 92 } 93 return MergePathInfoStreams(ctx, piCs), MergeErrStreams(ctx, errCs) 94} 95