LEFT | RIGHT |
1 package environs | 1 package environs |
2 | 2 |
3 import ( | 3 import ( |
4 "archive/tar" | 4 "archive/tar" |
5 "compress/gzip" | 5 "compress/gzip" |
6 "fmt" | 6 "fmt" |
7 "io" | 7 "io" |
8 "io/ioutil" | 8 "io/ioutil" |
9 "launchpad.net/juju/go/version" | 9 "launchpad.net/juju/go/version" |
10 "os" | 10 "os" |
11 "os/exec" | 11 "os/exec" |
12 "path/filepath" | 12 "path/filepath" |
| 13 "runtime" |
| 14 "strings" |
13 ) | 15 ) |
| 16 |
| 17 // toolsPath is the storage path for the juju tools with the |
| 18 // same version, OS, and arch as the currently running client. |
| 19 var toolsPath = fmt.Sprintf("tools/juju-%v-%s-%s.tgz", version.Current, runtime.
GOOS, runtime.GOARCH) |
14 | 20 |
15 // tarHeader returns a tar file header given the file's stat | 21 // tarHeader returns a tar file header given the file's stat |
16 // information. | 22 // information. |
17 func tarHeader(i os.FileInfo) *tar.Header { | 23 func tarHeader(i os.FileInfo) *tar.Header { |
18 return &tar.Header{ | 24 return &tar.Header{ |
19 Typeflag: tar.TypeReg, | 25 Typeflag: tar.TypeReg, |
20 Name: i.Name(), | 26 Name: i.Name(), |
21 Size: i.Size(), | 27 Size: i.Size(), |
22 Mode: int64(i.Mode() & 0777), | 28 Mode: int64(i.Mode() & 0777), |
23 ModTime: i.ModTime(), | 29 ModTime: i.ModTime(), |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
101 "GOBIN=" + dir, | 107 "GOBIN=" + dir, |
102 "PATH=" + os.Getenv("PATH"), | 108 "PATH=" + os.Getenv("PATH"), |
103 } | 109 } |
104 out, err := cmd.CombinedOutput() | 110 out, err := cmd.CombinedOutput() |
105 if err != nil { | 111 if err != nil { |
106 return fmt.Errorf("build failed: %v; %s", err, out) | 112 return fmt.Errorf("build failed: %v; %s", err, out) |
107 } | 113 } |
108 return archive(w, dir) | 114 return archive(w, dir) |
109 } | 115 } |
110 | 116 |
111 // UploadTools uploads the current version of the juju tools | 117 // PutTools uploads the current version of the juju tools |
112 // executables to the given environment. | 118 // executables to the given storage. |
113 // TODO find binaries from $PATH when go dev environment not available. | 119 // TODO find binaries from $PATH when go dev environment not available. |
114 func UploadTools(env Environ) error { | 120 func PutTools(storage StorageWriter) error { |
115 // We create the entire archive before asking the environment to | 121 // We create the entire archive before asking the environment to |
116 // start uploading so that we can be sure we have archived | 122 // start uploading so that we can be sure we have archived |
117 // correctly. | 123 // correctly. |
118 f, err := ioutil.TempFile("", "juju-tgz") | 124 f, err := ioutil.TempFile("", "juju-tgz") |
119 if err != nil { | 125 if err != nil { |
120 return err | 126 return err |
121 } | 127 } |
122 defer f.Close() | 128 defer f.Close() |
123 defer os.Remove(f.Name()) | 129 defer os.Remove(f.Name()) |
124 err = bundleTools(f) | 130 err = bundleTools(f) |
125 if err != nil { | 131 if err != nil { |
126 return err | 132 return err |
127 } | 133 } |
128 _, err = f.Seek(0, 0) | 134 _, err = f.Seek(0, 0) |
129 if err != nil { | 135 if err != nil { |
130 return err | 136 return err |
131 } | 137 } |
132 fi, err := f.Stat() | 138 fi, err := f.Stat() |
133 if err != nil { | 139 if err != nil { |
134 return err | 140 return err |
135 } | 141 } |
136 » return env.PutFile(version.ToolsPath, f, fi.Size()) | 142 » return storage.Put(toolsPath, f, fi.Size()) |
137 } | 143 } |
| 144 |
| 145 // GetTools finds the latest compatible version of the juju tools |
| 146 // and downloads and extracts them into the given directory. |
| 147 func GetTools(storage StorageReader, dir string) error { |
| 148 » // TODO search the storage for the right tools version. |
| 149 » r, err := storage.Get(toolsPath) |
| 150 » if err != nil { |
| 151 » » return err |
| 152 » } |
| 153 » defer r.Close() |
| 154 |
| 155 » r, err = gzip.NewReader(r) |
| 156 » if err != nil { |
| 157 » » return err |
| 158 » } |
| 159 » defer r.Close() |
| 160 |
| 161 » tr := tar.NewReader(r) |
| 162 » for { |
| 163 » » hdr, err := tr.Next() |
| 164 » » if err != nil { |
| 165 » » » if err == io.EOF { |
| 166 » » » » err = nil |
| 167 » » » } |
| 168 » » » return err |
| 169 » » } |
| 170 » » if strings.Contains(hdr.Name, "/\\") { |
| 171 » » » return fmt.Errorf("bad name %q in tools archive", hdr.Na
me) |
| 172 » » } |
| 173 |
| 174 » » name := filepath.Join(dir, hdr.Name) |
| 175 » » if err := writeFile(name, os.FileMode(hdr.Mode&0777), tr); err !
= nil { |
| 176 » » » return fmt.Errorf("tar extract %q failed: %v", name, err
) |
| 177 » » } |
| 178 » } |
| 179 » panic("not reached") |
| 180 } |
| 181 |
| 182 func writeFile(name string, mode os.FileMode, r io.Reader) error { |
| 183 » f, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode) |
| 184 » if err != nil { |
| 185 » » return err |
| 186 » } |
| 187 » defer f.Close() |
| 188 » _, err = io.Copy(f, r) |
| 189 » return err |
| 190 } |
| 191 |
| 192 // EmptyStorage holds a StorageReader object |
| 193 // that contains nothing. |
| 194 var EmptyStorage StorageReader = emptyStorage{} |
| 195 |
| 196 type emptyStorage struct{} |
| 197 |
| 198 func (s emptyStorage) Get(name string) (io.ReadCloser, error) { |
| 199 » return nil, &NotFoundError{fmt.Errorf("file %q not found in empty storag
e", name)} |
| 200 } |
| 201 |
| 202 func (s emptyStorage) List(prefix string) ([]string, error) { |
| 203 » return nil, nil |
| 204 } |
LEFT | RIGHT |