LEFT | RIGHT |
(no file at all) | |
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" | 13 "runtime" |
| 14 "strings" |
14 ) | 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) |
15 | 20 |
16 // tarHeader returns a tar file header given the file's stat | 21 // tarHeader returns a tar file header given the file's stat |
17 // information. | 22 // information. |
18 func tarHeader(i os.FileInfo) *tar.Header { | 23 func tarHeader(i os.FileInfo) *tar.Header { |
19 return &tar.Header{ | 24 return &tar.Header{ |
20 Typeflag: tar.TypeReg, | 25 Typeflag: tar.TypeReg, |
21 Name: i.Name(), | 26 Name: i.Name(), |
22 Size: i.Size(), | 27 Size: i.Size(), |
23 Mode: int64(i.Mode() & 0777), | 28 Mode: int64(i.Mode() & 0777), |
24 ModTime: i.ModTime(), | 29 ModTime: i.ModTime(), |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
102 "GOBIN=" + dir, | 107 "GOBIN=" + dir, |
103 "PATH=" + os.Getenv("PATH"), | 108 "PATH=" + os.Getenv("PATH"), |
104 } | 109 } |
105 out, err := cmd.CombinedOutput() | 110 out, err := cmd.CombinedOutput() |
106 if err != nil { | 111 if err != nil { |
107 return fmt.Errorf("build failed: %v; %s", err, out) | 112 return fmt.Errorf("build failed: %v; %s", err, out) |
108 } | 113 } |
109 return archive(w, dir) | 114 return archive(w, dir) |
110 } | 115 } |
111 | 116 |
112 // UploadTools uploads the current version of the juju tools | 117 // PutTools uploads the current version of the juju tools |
113 // executables to the given environment. | 118 // executables to the given storage. |
114 // TODO find binaries from $PATH when go dev environment not available. | 119 // TODO find binaries from $PATH when go dev environment not available. |
115 func UploadTools(env Environ) error { | 120 func PutTools(storage StorageWriter) error { |
116 // We create the entire archive before asking the environment to | 121 // We create the entire archive before asking the environment to |
117 // start uploading so that we can be sure we have archived | 122 // start uploading so that we can be sure we have archived |
118 // correctly. | 123 // correctly. |
119 f, err := ioutil.TempFile("", "juju-tgz") | 124 f, err := ioutil.TempFile("", "juju-tgz") |
120 if err != nil { | 125 if err != nil { |
121 return err | 126 return err |
122 } | 127 } |
123 defer f.Close() | 128 defer f.Close() |
124 defer os.Remove(f.Name()) | 129 defer os.Remove(f.Name()) |
125 err = bundleTools(f) | 130 err = bundleTools(f) |
126 if err != nil { | 131 if err != nil { |
127 return err | 132 return err |
128 } | 133 } |
129 _, err = f.Seek(0, 0) | 134 _, err = f.Seek(0, 0) |
130 if err != nil { | 135 if err != nil { |
131 return err | 136 return err |
132 } | 137 } |
133 fi, err := f.Stat() | 138 fi, err := f.Stat() |
134 if err != nil { | 139 if err != nil { |
135 return err | 140 return err |
136 } | 141 } |
137 » name := fmt.Sprintf("tools/juju-%v-%s-%s.tgz", version.Current, runtime.
GOOS, runtime.GOARCH) | 142 » return storage.Put(toolsPath, f, fi.Size()) |
138 » return env.PutFile(name, f, fi.Size()) | 143 } |
139 } | 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 |