| // Copyright 2017 Google Inc. All rights reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package build |
| |
| import ( |
| "compress/gzip" |
| "fmt" |
| "io" |
| "os" |
| "path/filepath" |
| "strings" |
| ) |
| |
| func absPath(ctx Context, p string) string { |
| ret, err := filepath.Abs(p) |
| if err != nil { |
| ctx.Fatalf("Failed to get absolute path: %v", err) |
| } |
| return ret |
| } |
| |
| // indexList finds the index of a string in a []string |
| func indexList(s string, list []string) int { |
| for i, l := range list { |
| if l == s { |
| return i |
| } |
| } |
| |
| return -1 |
| } |
| |
| // inList determines whether a string is in a []string |
| func inList(s string, list []string) bool { |
| return indexList(s, list) != -1 |
| } |
| |
| // removeFromlist removes all occurrences of the string in list. |
| func removeFromList(s string, list []string) []string { |
| filteredList := make([]string, 0, len(list)) |
| for _, ls := range list { |
| if s != ls { |
| filteredList = append(filteredList, ls) |
| } |
| } |
| return filteredList |
| } |
| |
| // ensureDirectoriesExist is a shortcut to os.MkdirAll, sending errors to the ctx logger. |
| func ensureDirectoriesExist(ctx Context, dirs ...string) { |
| for _, dir := range dirs { |
| err := os.MkdirAll(dir, 0777) |
| if err != nil { |
| ctx.Fatalf("Error creating %s: %q\n", dir, err) |
| } |
| } |
| } |
| |
| // ensureEmptyDirectoriesExist ensures that the given directories exist and are empty |
| func ensureEmptyDirectoriesExist(ctx Context, dirs ...string) { |
| // remove all the directories |
| for _, dir := range dirs { |
| seenErr := map[string]bool{} |
| for { |
| err := os.RemoveAll(dir) |
| if err == nil { |
| break |
| } |
| |
| if pathErr, ok := err.(*os.PathError); !ok || |
| dir == pathErr.Path || seenErr[pathErr.Path] { |
| |
| ctx.Fatalf("Error removing %s: %q\n", dir, err) |
| } else { |
| seenErr[pathErr.Path] = true |
| err = os.Chmod(filepath.Dir(pathErr.Path), 0700) |
| if err != nil { |
| ctx.Fatal(err) |
| } |
| } |
| } |
| } |
| // recreate all the directories |
| ensureDirectoriesExist(ctx, dirs...) |
| } |
| |
| // ensureEmptyFileExists ensures that the containing directory exists, and the |
| // specified file exists. If it doesn't exist, it will write an empty file. |
| func ensureEmptyFileExists(ctx Context, file string) { |
| ensureDirectoriesExist(ctx, filepath.Dir(file)) |
| if _, err := os.Stat(file); os.IsNotExist(err) { |
| f, err := os.Create(file) |
| if err != nil { |
| ctx.Fatalf("Error creating %s: %q\n", file, err) |
| } |
| f.Close() |
| } else if err != nil { |
| ctx.Fatalf("Error checking %s: %q\n", file, err) |
| } |
| } |
| |
| // singleUnquote is similar to strconv.Unquote, but can handle multi-character strings inside single quotes. |
| func singleUnquote(str string) (string, bool) { |
| if len(str) < 2 || str[0] != '\'' || str[len(str)-1] != '\'' { |
| return "", false |
| } |
| return str[1 : len(str)-1], true |
| } |
| |
| // decodeKeyValue decodes a key=value string |
| func decodeKeyValue(str string) (string, string, bool) { |
| idx := strings.IndexRune(str, '=') |
| if idx == -1 { |
| return "", "", false |
| } |
| return str[:idx], str[idx+1:], true |
| } |
| |
| // copyFile copies a file from src to dst. filepath.Dir(dst) must exist. |
| func copyFile(src, dst string) (int64, error) { |
| source, err := os.Open(src) |
| if err != nil { |
| return 0, err |
| } |
| defer source.Close() |
| |
| destination, err := os.Create(dst) |
| if err != nil { |
| return 0, err |
| } |
| defer destination.Close() |
| |
| return io.Copy(destination, source) |
| } |
| |
| // gzipFileToDir writes a compressed copy of src to destDir with the suffix ".gz". |
| func gzipFileToDir(src, destDir string) error { |
| in, err := os.Open(src) |
| if err != nil { |
| return fmt.Errorf("failed to open %s: %s", src, err.Error()) |
| } |
| defer in.Close() |
| |
| dest := filepath.Join(destDir, filepath.Base(src)+".gz") |
| |
| out, err := os.OpenFile(dest, os.O_CREATE|os.O_WRONLY, 0666) |
| if err != nil { |
| return fmt.Errorf("failed to open %s: %s", dest, err.Error()) |
| } |
| defer out.Close() |
| gz := gzip.NewWriter(out) |
| defer gz.Close() |
| |
| _, err = io.Copy(gz, in) |
| if err != nil { |
| return fmt.Errorf("failed to gzip %s: %s", dest, err.Error()) |
| } |
| |
| return nil |
| } |