blob: d4c3431e90ce2b7c5136c853ff9fdd5b3c04649e [file] [log] [blame]
Dan Willemsen1e704462016-08-21 15:17:17 -07001// Copyright 2017 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 build
16
17import (
Colin Cross8ba7d472020-06-25 11:27:52 -070018 "compress/gzip"
19 "fmt"
Patrice Arruda7cc20742020-06-10 18:48:01 +000020 "io"
Dan Willemsen1e704462016-08-21 15:17:17 -070021 "os"
22 "path/filepath"
23 "strings"
24)
25
Dan Willemsend9e8f0a2017-10-30 13:42:06 -070026func absPath(ctx Context, p string) string {
27 ret, err := filepath.Abs(p)
28 if err != nil {
29 ctx.Fatalf("Failed to get absolute path: %v", err)
30 }
31 return ret
32}
33
Dan Willemsen1e704462016-08-21 15:17:17 -070034// indexList finds the index of a string in a []string
35func indexList(s string, list []string) int {
36 for i, l := range list {
37 if l == s {
38 return i
39 }
40 }
41
42 return -1
43}
44
45// inList determines whether a string is in a []string
46func inList(s string, list []string) bool {
47 return indexList(s, list) != -1
48}
49
Patrice Arruda13848222019-04-22 17:12:02 -070050// removeFromlist removes all occurrences of the string in list.
51func removeFromList(s string, list []string) []string {
52 filteredList := make([]string, 0, len(list))
53 for _, ls := range list {
54 if s != ls {
55 filteredList = append(filteredList, ls)
56 }
57 }
58 return filteredList
59}
60
Dan Willemsen1e704462016-08-21 15:17:17 -070061// ensureDirectoriesExist is a shortcut to os.MkdirAll, sending errors to the ctx logger.
62func ensureDirectoriesExist(ctx Context, dirs ...string) {
63 for _, dir := range dirs {
64 err := os.MkdirAll(dir, 0777)
65 if err != nil {
66 ctx.Fatalf("Error creating %s: %q\n", dir, err)
67 }
68 }
69}
70
Jeff Gastonefc1b412017-03-29 17:29:06 -070071// ensureEmptyDirectoriesExist ensures that the given directories exist and are empty
72func ensureEmptyDirectoriesExist(ctx Context, dirs ...string) {
73 // remove all the directories
74 for _, dir := range dirs {
Dan Willemsenfe8b6452018-05-12 18:34:24 -070075 seenErr := map[string]bool{}
76 for {
77 err := os.RemoveAll(dir)
78 if err == nil {
79 break
80 }
81
82 if pathErr, ok := err.(*os.PathError); !ok ||
83 dir == pathErr.Path || seenErr[pathErr.Path] {
84
85 ctx.Fatalf("Error removing %s: %q\n", dir, err)
86 } else {
87 seenErr[pathErr.Path] = true
88 err = os.Chmod(filepath.Dir(pathErr.Path), 0700)
89 if err != nil {
90 ctx.Fatal(err)
91 }
92 }
Jeff Gastonefc1b412017-03-29 17:29:06 -070093 }
94 }
95 // recreate all the directories
96 ensureDirectoriesExist(ctx, dirs...)
97}
98
Dan Willemsen1e704462016-08-21 15:17:17 -070099// ensureEmptyFileExists ensures that the containing directory exists, and the
100// specified file exists. If it doesn't exist, it will write an empty file.
101func ensureEmptyFileExists(ctx Context, file string) {
102 ensureDirectoriesExist(ctx, filepath.Dir(file))
103 if _, err := os.Stat(file); os.IsNotExist(err) {
104 f, err := os.Create(file)
105 if err != nil {
106 ctx.Fatalf("Error creating %s: %q\n", file, err)
107 }
108 f.Close()
109 } else if err != nil {
110 ctx.Fatalf("Error checking %s: %q\n", file, err)
111 }
112}
113
114// singleUnquote is similar to strconv.Unquote, but can handle multi-character strings inside single quotes.
115func singleUnquote(str string) (string, bool) {
116 if len(str) < 2 || str[0] != '\'' || str[len(str)-1] != '\'' {
117 return "", false
118 }
119 return str[1 : len(str)-1], true
120}
121
122// decodeKeyValue decodes a key=value string
123func decodeKeyValue(str string) (string, string, bool) {
124 idx := strings.IndexRune(str, '=')
125 if idx == -1 {
126 return "", "", false
127 }
128 return str[:idx], str[idx+1:], true
129}
Patrice Arruda7cc20742020-06-10 18:48:01 +0000130
131// copyFile copies a file from src to dst. filepath.Dir(dst) must exist.
132func copyFile(src, dst string) (int64, error) {
133 source, err := os.Open(src)
134 if err != nil {
135 return 0, err
136 }
137 defer source.Close()
138
139 destination, err := os.Create(dst)
140 if err != nil {
141 return 0, err
142 }
143 defer destination.Close()
144
145 return io.Copy(destination, source)
146}
Colin Cross8ba7d472020-06-25 11:27:52 -0700147
148// gzipFileToDir writes a compressed copy of src to destDir with the suffix ".gz".
149func gzipFileToDir(src, destDir string) error {
150 in, err := os.Open(src)
151 if err != nil {
152 return fmt.Errorf("failed to open %s: %s", src, err.Error())
153 }
154 defer in.Close()
155
156 dest := filepath.Join(destDir, filepath.Base(src)+".gz")
157
158 out, err := os.OpenFile(dest, os.O_CREATE|os.O_WRONLY, 0666)
159 if err != nil {
160 return fmt.Errorf("failed to open %s: %s", dest, err.Error())
161 }
162 defer out.Close()
163 gz := gzip.NewWriter(out)
164 defer gz.Close()
165
166 _, err = io.Copy(gz, in)
167 if err != nil {
168 return fmt.Errorf("failed to gzip %s: %s", dest, err.Error())
169 }
170
171 return nil
172}