1
2
3
4
5
6
7
8
9
10
11
12
13
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(abs(filepath.FromSlash(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 := abs(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(abs(filepath.FromSlash(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
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 }
204
View as plain text