diff options
Diffstat (limited to 'go/tools/builders/go_path.go')
-rw-r--r-- | go/tools/builders/go_path.go | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/go/tools/builders/go_path.go b/go/tools/builders/go_path.go new file mode 100644 index 00000000..58a7b8a9 --- /dev/null +++ b/go/tools/builders/go_path.go @@ -0,0 +1,203 @@ +// Copyright 2018 The Bazel Authors. 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 main + +import ( + "archive/zip" + "encoding/json" + "errors" + "flag" + "fmt" + "io" + "io/ioutil" + "log" + "os" + "path/filepath" +) + +type mode int + +const ( + invalidMode mode = iota + archiveMode + copyMode + linkMode +) + +func modeFromString(s string) (mode, error) { + switch s { + case "archive": + return archiveMode, nil + case "copy": + return copyMode, nil + case "link": + return linkMode, nil + default: + return invalidMode, fmt.Errorf("invalid mode: %s", s) + } +} + +type manifestEntry struct { + Src, Dst string +} + +func main() { + log.SetPrefix("GoPath: ") + log.SetFlags(0) + if err := run(os.Args[1:]); err != nil { + log.Fatal(err) + } +} + +func run(args []string) error { + var manifest, out string + flags := flag.NewFlagSet("go_path", flag.ContinueOnError) + flags.StringVar(&manifest, "manifest", "", "name of json file listing files to include") + flags.StringVar(&out, "out", "", "output file or directory") + modeFlag := flags.String("mode", "", "copy, link, or archive") + if err := flags.Parse(args); err != nil { + return err + } + if manifest == "" { + return errors.New("-manifest not set") + } + if out == "" { + return errors.New("-out not set") + } + if *modeFlag == "" { + return errors.New("-mode not set") + } + mode, err := modeFromString(*modeFlag) + if err != nil { + return err + } + + entries, err := readManifest(manifest) + if err != nil { + return err + } + + switch mode { + case archiveMode: + err = archivePath(out, entries) + case copyMode: + err = copyPath(out, entries) + case linkMode: + err = linkPath(out, entries) + } + return err +} + +func readManifest(path string) ([]manifestEntry, error) { + data, err := ioutil.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("error reading manifest: %v", err) + } + var entries []manifestEntry + if err := json.Unmarshal(data, &entries); err != nil { + return nil, fmt.Errorf("error unmarshalling manifest %s: %v", path, err) + } + return entries, nil +} + +func archivePath(out string, manifest []manifestEntry) (err error) { + outFile, err := os.Create(out) + if err != nil { + return err + } + defer func() { + if e := outFile.Close(); err == nil && e != nil { + err = fmt.Errorf("error closing archive %s: %v", out, e) + } + }() + outZip := zip.NewWriter(outFile) + + for _, entry := range manifest { + srcFile, err := os.Open(abs(filepath.FromSlash(entry.Src))) + if err != nil { + return err + } + w, err := outZip.Create(entry.Dst) + if err != nil { + srcFile.Close() + return err + } + if _, err := io.Copy(w, srcFile); err != nil { + srcFile.Close() + return err + } + if err := srcFile.Close(); err != nil { + return err + } + } + + if err := outZip.Close(); err != nil { + return fmt.Errorf("error constructing archive %s: %v", out, err) + } + return nil +} + +func copyPath(out string, manifest []manifestEntry) error { + if err := os.MkdirAll(out, 0777); err != nil { + return err + } + for _, entry := range manifest { + dst := abs(filepath.Join(out, filepath.FromSlash(entry.Dst))) + if err := os.MkdirAll(filepath.Dir(dst), 0777); err != nil { + return err + } + srcFile, err := os.Open(abs(filepath.FromSlash(entry.Src))) + if err != nil { + return err + } + dstFile, err := os.Create(dst) + if err != nil { + srcFile.Close() + return err + } + if _, err := io.Copy(dstFile, srcFile); err != nil { + dstFile.Close() + srcFile.Close() + return err + } + srcFile.Close() + if err := dstFile.Close(); err != nil { + return err + } + } + return nil +} + +func linkPath(out string, manifest []manifestEntry) error { + // out directory may already exist and may contain old symlinks. Delete. + if err := os.RemoveAll(out); err != nil { + return err + } + if err := os.MkdirAll(out, 0777); err != nil { + return err + } + for _, entry := range manifest { + dst := filepath.Join(out, filepath.FromSlash(entry.Dst)) + dstDir := filepath.Dir(dst) + src, _ := filepath.Rel(dstDir, entry.Src) + if err := os.MkdirAll(dstDir, 0777); err != nil { + return err + } + if err := os.Symlink(src, dst); err != nil { + return err + } + } + return nil +} |