xref: /aosp_15_r20/external/bazelbuild-rules_android/src/tools/ak/res/respipe/path_emitter.go (revision 9e965d6fece27a77de5377433c2f7e6999b8cc0b)
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