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-core/log" | 9 "launchpad.net/juju-core/log" |
10 "launchpad.net/juju-core/state" | 10 "launchpad.net/juju-core/state" |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
228 if bestTools == nil || bestTools.Number.Less(t.Number) { | 228 if bestTools == nil || bestTools.Number.Less(t.Number) { |
229 bestTools = t | 229 bestTools = t |
230 } | 230 } |
231 } | 231 } |
232 return bestTools | 232 return bestTools |
233 } | 233 } |
234 | 234 |
235 const urlFile = "downloaded-url.txt" | 235 const urlFile = "downloaded-url.txt" |
236 | 236 |
237 // toolsParentDir returns the tools parent directory. | 237 // toolsParentDir returns the tools parent directory. |
238 func toolsParentDir(varDir string) string { | 238 func toolsParentDir(dataDir string) string { |
239 » return path.Join(varDir, "tools") | 239 » return path.Join(dataDir, "tools") |
240 } | 240 } |
241 | 241 |
242 // UnpackTools reads a set of juju tools in gzipped tar-archive | 242 // UnpackTools reads a set of juju tools in gzipped tar-archive |
243 // format and unpacks them into the appropriate tools directory | 243 // format and unpacks them into the appropriate tools directory |
244 // within varDir. If a valid tools directory already exists, | 244 // within dataDir. If a valid tools directory already exists, |
245 // UnpackTools returns without error. | 245 // UnpackTools returns without error. |
246 func UnpackTools(varDir string, tools *state.Tools, r io.Reader) (err error) { | 246 func UnpackTools(dataDir string, tools *state.Tools, r io.Reader) (err error) { |
247 zr, err := gzip.NewReader(r) | 247 zr, err := gzip.NewReader(r) |
248 if err != nil { | 248 if err != nil { |
249 return err | 249 return err |
250 } | 250 } |
251 defer zr.Close() | 251 defer zr.Close() |
252 | 252 |
253 // Make a temporary directory in the tools directory, | 253 // Make a temporary directory in the tools directory, |
254 // first ensuring that the tools directory exists. | 254 // first ensuring that the tools directory exists. |
255 » err = os.MkdirAll(toolsParentDir(varDir), 0755) | 255 » err = os.MkdirAll(toolsParentDir(dataDir), 0755) |
256 » if err != nil { | 256 » if err != nil { |
257 » » return err | 257 » » return err |
258 » } | 258 » } |
259 » dir, err := ioutil.TempDir(toolsParentDir(varDir), "unpacking-") | 259 » dir, err := ioutil.TempDir(toolsParentDir(dataDir), "unpacking-") |
260 if err != nil { | 260 if err != nil { |
261 return err | 261 return err |
262 } | 262 } |
263 defer removeAll(dir) | 263 defer removeAll(dir) |
264 | 264 |
265 tr := tar.NewReader(zr) | 265 tr := tar.NewReader(zr) |
266 for { | 266 for { |
267 hdr, err := tr.Next() | 267 hdr, err := tr.Next() |
268 if err == io.EOF { | 268 if err == io.EOF { |
269 break | 269 break |
(...skipping 10 matching lines...) Expand all Loading... |
280 name := filepath.Join(dir, hdr.Name) | 280 name := filepath.Join(dir, hdr.Name) |
281 if err := writeFile(name, os.FileMode(hdr.Mode&0777), tr); err !
= nil { | 281 if err := writeFile(name, os.FileMode(hdr.Mode&0777), tr); err !
= nil { |
282 return fmt.Errorf("tar extract %q failed: %v", name, err
) | 282 return fmt.Errorf("tar extract %q failed: %v", name, err
) |
283 } | 283 } |
284 } | 284 } |
285 err = ioutil.WriteFile(filepath.Join(dir, urlFile), []byte(tools.URL), 0
644) | 285 err = ioutil.WriteFile(filepath.Join(dir, urlFile), []byte(tools.URL), 0
644) |
286 if err != nil { | 286 if err != nil { |
287 return err | 287 return err |
288 } | 288 } |
289 | 289 |
290 » err = os.Rename(dir, ToolsDir(varDir, tools.Binary)) | 290 » err = os.Rename(dir, ToolsDir(dataDir, tools.Binary)) |
291 // If we've failed to rename the directory, it may be because | 291 // If we've failed to rename the directory, it may be because |
292 // the directory already exists - if ReadTools succeeds, we | 292 // the directory already exists - if ReadTools succeeds, we |
293 // assume all's ok. | 293 // assume all's ok. |
294 if err != nil { | 294 if err != nil { |
295 » » _, err := ReadTools(varDir, tools.Binary) | 295 » » _, err := ReadTools(dataDir, tools.Binary) |
296 if err == nil { | 296 if err == nil { |
297 return nil | 297 return nil |
298 } | 298 } |
299 } | 299 } |
300 return nil | 300 return nil |
301 } | 301 } |
302 | 302 |
303 func removeAll(dir string) { | 303 func removeAll(dir string) { |
304 err := os.RemoveAll(dir) | 304 err := os.RemoveAll(dir) |
305 if err == nil || os.IsNotExist(err) { | 305 if err == nil || os.IsNotExist(err) { |
306 return | 306 return |
307 } | 307 } |
308 log.Printf("environs: cannot remove %q: %v", dir, err) | 308 log.Printf("environs: cannot remove %q: %v", dir, err) |
309 } | 309 } |
310 | 310 |
311 func writeFile(name string, mode os.FileMode, r io.Reader) error { | 311 func writeFile(name string, mode os.FileMode, r io.Reader) error { |
312 f, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode) | 312 f, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode) |
313 if err != nil { | 313 if err != nil { |
314 return err | 314 return err |
315 } | 315 } |
316 defer f.Close() | 316 defer f.Close() |
317 _, err = io.Copy(f, r) | 317 _, err = io.Copy(f, r) |
318 return err | 318 return err |
319 } | 319 } |
320 | 320 |
321 // ReadTools checks that the tools for the given version exist | 321 // ReadTools checks that the tools for the given version exist |
322 // in the varDir directory, and returns a Tools instance describing them. | 322 // in the dataDir directory, and returns a Tools instance describing them. |
323 func ReadTools(varDir string, vers version.Binary) (*state.Tools, error) { | 323 func ReadTools(dataDir string, vers version.Binary) (*state.Tools, error) { |
324 » dir := ToolsDir(varDir, vers) | 324 » dir := ToolsDir(dataDir, vers) |
325 urlData, err := ioutil.ReadFile(filepath.Join(dir, urlFile)) | 325 urlData, err := ioutil.ReadFile(filepath.Join(dir, urlFile)) |
326 if err != nil { | 326 if err != nil { |
327 return nil, fmt.Errorf("cannot read URL in tools directory: %v",
err) | 327 return nil, fmt.Errorf("cannot read URL in tools directory: %v",
err) |
328 } | 328 } |
329 url := strings.TrimSpace(string(urlData)) | 329 url := strings.TrimSpace(string(urlData)) |
330 if len(url) == 0 { | 330 if len(url) == 0 { |
331 return nil, fmt.Errorf("empty URL in tools directory %q", dir) | 331 return nil, fmt.Errorf("empty URL in tools directory %q", dir) |
332 } | 332 } |
333 // TODO(rog): do more verification here too, such as checking | 333 // TODO(rog): do more verification here too, such as checking |
334 // for the existence of certain files. | 334 // for the existence of certain files. |
335 return &state.Tools{ | 335 return &state.Tools{ |
336 URL: url, | 336 URL: url, |
337 Binary: vers, | 337 Binary: vers, |
338 }, nil | 338 }, nil |
339 } | 339 } |
340 | 340 |
341 // ChangeAgentTools atomically replaces the agent-specific symlink | 341 // ChangeAgentTools atomically replaces the agent-specific symlink |
342 // under varDir so it points to the previously unpacked | 342 // under dataDir so it points to the previously unpacked |
343 // version vers. It returns the new tools read. | 343 // version vers. It returns the new tools read. |
344 func ChangeAgentTools(varDir string, agentName string, vers version.Binary) (*st
ate.Tools, error) { | 344 func ChangeAgentTools(dataDir string, agentName string, vers version.Binary) (*s
tate.Tools, error) { |
345 » tools, err := ReadTools(varDir, vers) | 345 » tools, err := ReadTools(dataDir, vers) |
346 » if err != nil { | 346 » if err != nil { |
347 » » return nil, err | 347 » » return nil, err |
348 » } | 348 » } |
349 » tmpName := AgentToolsDir(varDir, "tmplink-"+agentName) | 349 » tmpName := AgentToolsDir(dataDir, "tmplink-"+agentName) |
350 err = os.Symlink(tools.Binary.String(), tmpName) | 350 err = os.Symlink(tools.Binary.String(), tmpName) |
351 if err != nil { | 351 if err != nil { |
352 return nil, fmt.Errorf("cannot create tools symlink: %v", err) | 352 return nil, fmt.Errorf("cannot create tools symlink: %v", err) |
353 } | 353 } |
354 » err = os.Rename(tmpName, AgentToolsDir(varDir, agentName)) | 354 » err = os.Rename(tmpName, AgentToolsDir(dataDir, agentName)) |
355 if err != nil { | 355 if err != nil { |
356 return nil, fmt.Errorf("cannot update tools symlink: %v", err) | 356 return nil, fmt.Errorf("cannot update tools symlink: %v", err) |
357 } | 357 } |
358 return tools, nil | 358 return tools, nil |
359 } | 359 } |
360 | 360 |
361 // ToolsStoragePath returns the slash-separated path that is used to store and | 361 // ToolsStoragePath returns the slash-separated path that is used to store and |
362 // retrieve the given version of the juju tools in a Storage. | 362 // retrieve the given version of the juju tools in a Storage. |
363 func ToolsStoragePath(vers version.Binary) string { | 363 func ToolsStoragePath(vers version.Binary) string { |
364 return toolPrefix + vers.String() + ".tgz" | 364 return toolPrefix + vers.String() + ".tgz" |
365 } | 365 } |
366 | 366 |
367 // ToolsDir returns the slash-separated directory name that is used to | 367 // ToolsDir returns the slash-separated directory name that is used to |
368 // store binaries for the given version of the juju tools | 368 // store binaries for the given version of the juju tools |
369 // within the varDir directory. | 369 // within the dataDir directory. |
370 func ToolsDir(varDir string, vers version.Binary) string { | 370 func ToolsDir(dataDir string, vers version.Binary) string { |
371 » return path.Join(varDir, "tools", vers.String()) | 371 » return path.Join(dataDir, "tools", vers.String()) |
372 } | 372 } |
373 | 373 |
374 // AgentToolsDir returns the slash-separated directory name that is used | 374 // AgentToolsDir returns the slash-separated directory name that is used |
375 // to store binaries for the tools used by the given agent | 375 // to store binaries for the tools used by the given agent |
376 // within the given varDir directory. | 376 // within the given dataDir directory. |
377 // Conventionally it is a symbolic link to the actual tools directory. | 377 // Conventionally it is a symbolic link to the actual tools directory. |
378 func AgentToolsDir(varDir, agentName string) string { | 378 func AgentToolsDir(dataDir, agentName string) string { |
379 » return path.Join(varDir, "tools", agentName) | 379 » return path.Join(dataDir, "tools", agentName) |
380 } | 380 } |
381 | 381 |
382 // ToolsSearchFlags gives options when searching | 382 // ToolsSearchFlags gives options when searching |
383 // for tools. | 383 // for tools. |
384 type ToolsSearchFlags int | 384 type ToolsSearchFlags int |
385 | 385 |
386 const ( | 386 const ( |
387 // HighestVersion indicates that versions above the version being | 387 // HighestVersion indicates that versions above the version being |
388 // searched for may be included in the search. The default behavior | 388 // searched for may be included in the search. The default behavior |
389 // is to search for versions <= the one provided. | 389 // is to search for versions <= the one provided. |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
474 return nil, &NotFoundError{fmt.Errorf("file %q not found in empty storag
e", name)} | 474 return nil, &NotFoundError{fmt.Errorf("file %q not found in empty storag
e", name)} |
475 } | 475 } |
476 | 476 |
477 func (s emptyStorage) URL(string) (string, error) { | 477 func (s emptyStorage) URL(string) (string, error) { |
478 return "", fmt.Errorf("empty storage has no URLs") | 478 return "", fmt.Errorf("empty storage has no URLs") |
479 } | 479 } |
480 | 480 |
481 func (s emptyStorage) List(prefix string) ([]string, error) { | 481 func (s emptyStorage) List(prefix string) ([]string, error) { |
482 return nil, nil | 482 return nil, nil |
483 } | 483 } |
LEFT | RIGHT |