173 lines
4.3 KiB
Go
173 lines
4.3 KiB
Go
// 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
|
|
}
|