1// 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 ( 18 "compress/gzip" 19 "fmt" 20 "io" 21 "os" 22 "path/filepath" 23 "strings" 24) 25 26func 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 34// 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 50// 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 61// 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 71// 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 { 75 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 } 93 } 94 } 95 // recreate all the directories 96 ensureDirectoriesExist(ctx, dirs...) 97} 98 99// 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} 130 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} 147 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} 173