1// 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 glob
16
17import (
18	"io/ioutil"
19	"os"
20	"path/filepath"
21	"strings"
22
23	"github.com/google/blueprint/deptools"
24	"github.com/google/blueprint/pathtools"
25)
26
27func IsGlob(glob string) bool {
28	return strings.IndexAny(glob, "*?[") >= 0
29}
30
31// GlobWithDepFile finds all files that match glob.  It compares the list of files
32// against the contents of fileListFile, and rewrites fileListFile if it has changed.  It also
33// writes all of the the directories it traversed as a depenencies on fileListFile to depFile.
34//
35// The format of glob is either path/*.ext for a single directory glob, or path/**/*.ext
36// for a recursive glob.
37//
38// Returns a list of file paths, and an error.
39func GlobWithDepFile(glob, fileListFile, depFile string, excludes []string) (files []string, err error) {
40	files, dirs, err := pathtools.GlobWithExcludes(glob, excludes)
41	if err != nil {
42		return nil, err
43	}
44
45	fileList := strings.Join(files, "\n") + "\n"
46
47	writeFileIfChanged(fileListFile, []byte(fileList), 0666)
48	deptools.WriteDepFile(depFile, fileListFile, dirs)
49
50	return
51}
52
53func writeFileIfChanged(filename string, data []byte, perm os.FileMode) error {
54	var isChanged bool
55
56	dir := filepath.Dir(filename)
57	err := os.MkdirAll(dir, 0777)
58	if err != nil {
59		return err
60	}
61
62	info, err := os.Stat(filename)
63	if err != nil {
64		if os.IsNotExist(err) {
65			// The file does not exist yet.
66			isChanged = true
67		} else {
68			return err
69		}
70	} else {
71		if info.Size() != int64(len(data)) {
72			isChanged = true
73		} else {
74			oldData, err := ioutil.ReadFile(filename)
75			if err != nil {
76				return err
77			}
78
79			if len(oldData) != len(data) {
80				isChanged = true
81			} else {
82				for i := range data {
83					if oldData[i] != data[i] {
84						isChanged = true
85						break
86					}
87				}
88			}
89		}
90	}
91
92	if isChanged {
93		err = ioutil.WriteFile(filename, data, perm)
94		if err != nil {
95			return err
96		}
97	}
98
99	return nil
100}
101