github.com/ajguerrer/rules_go@v0.20.3/go/tools/builders/go_path.go (about) 1 // Copyright 2018 The Bazel Authors. 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 15 package main 16 17 import ( 18 "archive/zip" 19 "encoding/json" 20 "errors" 21 "flag" 22 "fmt" 23 "io" 24 "io/ioutil" 25 "log" 26 "os" 27 "path/filepath" 28 ) 29 30 type mode int 31 32 const ( 33 invalidMode mode = iota 34 archiveMode 35 copyMode 36 linkMode 37 ) 38 39 func modeFromString(s string) (mode, error) { 40 switch s { 41 case "archive": 42 return archiveMode, nil 43 case "copy": 44 return copyMode, nil 45 case "link": 46 return linkMode, nil 47 default: 48 return invalidMode, fmt.Errorf("invalid mode: %s", s) 49 } 50 } 51 52 type manifestEntry struct { 53 Src, Dst string 54 } 55 56 func main() { 57 log.SetPrefix("GoPath: ") 58 log.SetFlags(0) 59 if err := run(os.Args[1:]); err != nil { 60 log.Fatal(err) 61 } 62 } 63 64 func run(args []string) error { 65 var manifest, out string 66 flags := flag.NewFlagSet("go_path", flag.ContinueOnError) 67 flags.StringVar(&manifest, "manifest", "", "name of json file listing files to include") 68 flags.StringVar(&out, "out", "", "output file or directory") 69 modeFlag := flags.String("mode", "", "copy, link, or archive") 70 if err := flags.Parse(args); err != nil { 71 return err 72 } 73 if manifest == "" { 74 return errors.New("-manifest not set") 75 } 76 if out == "" { 77 return errors.New("-out not set") 78 } 79 if *modeFlag == "" { 80 return errors.New("-mode not set") 81 } 82 mode, err := modeFromString(*modeFlag) 83 if err != nil { 84 return err 85 } 86 87 entries, err := readManifest(manifest) 88 if err != nil { 89 return err 90 } 91 92 switch mode { 93 case archiveMode: 94 err = archivePath(out, entries) 95 case copyMode: 96 err = copyPath(out, entries) 97 case linkMode: 98 err = linkPath(out, entries) 99 } 100 return err 101 } 102 103 func readManifest(path string) ([]manifestEntry, error) { 104 data, err := ioutil.ReadFile(path) 105 if err != nil { 106 return nil, fmt.Errorf("error reading manifest: %v", err) 107 } 108 var entries []manifestEntry 109 if err := json.Unmarshal(data, &entries); err != nil { 110 return nil, fmt.Errorf("error unmarshalling manifest %s: %v", path, err) 111 } 112 return entries, nil 113 } 114 115 func archivePath(out string, manifest []manifestEntry) (err error) { 116 outFile, err := os.Create(out) 117 if err != nil { 118 return err 119 } 120 defer func() { 121 if e := outFile.Close(); err == nil && e != nil { 122 err = fmt.Errorf("error closing archive %s: %v", out, e) 123 } 124 }() 125 outZip := zip.NewWriter(outFile) 126 127 for _, entry := range manifest { 128 srcFile, err := os.Open(entry.Src) 129 if err != nil { 130 return err 131 } 132 w, err := outZip.Create(entry.Dst) 133 if err != nil { 134 srcFile.Close() 135 return err 136 } 137 if _, err := io.Copy(w, srcFile); err != nil { 138 srcFile.Close() 139 return err 140 } 141 if err := srcFile.Close(); err != nil { 142 return err 143 } 144 } 145 146 if err := outZip.Close(); err != nil { 147 return fmt.Errorf("error constructing archive %s: %v", out, err) 148 } 149 return nil 150 } 151 152 func copyPath(out string, manifest []manifestEntry) error { 153 if err := os.MkdirAll(out, 0777); err != nil { 154 return err 155 } 156 for _, entry := range manifest { 157 dst := filepath.Join(out, filepath.FromSlash(entry.Dst)) 158 if err := os.MkdirAll(filepath.Dir(dst), 0777); err != nil { 159 return err 160 } 161 srcFile, err := os.Open(entry.Src) 162 if err != nil { 163 return err 164 } 165 dstFile, err := os.Create(dst) 166 if err != nil { 167 srcFile.Close() 168 return err 169 } 170 if _, err := io.Copy(dstFile, srcFile); err != nil { 171 dstFile.Close() 172 srcFile.Close() 173 return err 174 } 175 srcFile.Close() 176 if err := dstFile.Close(); err != nil { 177 return err 178 } 179 } 180 return nil 181 } 182 183 func linkPath(out string, manifest []manifestEntry) error { 184 // out directory may already exist and may contain old symlinks. Delete. 185 if err := os.RemoveAll(out); err != nil { 186 return err 187 } 188 if err := os.MkdirAll(out, 0777); err != nil { 189 return err 190 } 191 for _, entry := range manifest { 192 dst := filepath.Join(out, filepath.FromSlash(entry.Dst)) 193 dstDir := filepath.Dir(dst) 194 src, _ := filepath.Rel(dstDir, entry.Src) 195 if err := os.MkdirAll(dstDir, 0777); err != nil { 196 return err 197 } 198 if err := os.Symlink(src, dst); err != nil { 199 return err 200 } 201 } 202 return nil 203 }