github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/resource/context/internal/context.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package internal 5 6 import ( 7 "io" 8 9 "github.com/juju/errors" 10 ) 11 12 // ContextDownload downloads the named resource and returns the path 13 // to which it was downloaded. If the resource does not exist or has 14 // not been uploaded yet then errors.NotFound is returned. 15 // 16 // Note that the downloaded file is checked for correctness. 17 func ContextDownload(deps ContextDownloadDeps) (path string, err error) { 18 // TODO(katco): Potential race-condition: two commands running at 19 // once. Solve via collision using os.Mkdir() with a uniform 20 // temp dir name (e.g. "<datadir>/.<res name>.download")? 21 22 resDirSpec := deps.NewContextDirectorySpec() 23 24 remote, err := deps.OpenResource() 25 if err != nil { 26 return "", errors.Trace(err) 27 } 28 defer deps.CloseAndLog(remote, "remote resource") 29 path = resDirSpec.Resolve(remote.Info().Path) 30 31 isUpToDate, err := resDirSpec.IsUpToDate(remote.Content()) 32 if err != nil { 33 return "", errors.Trace(err) 34 } 35 if isUpToDate { 36 // We're up to date already! 37 return path, nil 38 } 39 40 if err := deps.Download(resDirSpec, remote); err != nil { 41 return "", errors.Trace(err) 42 } 43 44 return path, nil 45 } 46 47 // ContextDownloadDeps provides the externally defined functions 48 // on which ContextDownload depends. The functionality all relates 49 // to a single resource. 50 type ContextDownloadDeps interface { 51 // NewContextDirectorySpec returns the dir spec for the resource 52 // in the hook context. 53 NewContextDirectorySpec() ContextDirectorySpec 54 55 // OpenResource reads the resource info and opens the resource 56 // content for reading. 57 OpenResource() (ContextOpenedResource, error) 58 59 // CloseAndLog closes the closer and logs any error. 60 CloseAndLog(io.Closer, string) 61 62 // Download writes the remote to the target directory. 63 Download(DownloadTarget, ContextOpenedResource) error 64 } 65 66 // ContextDirectorySpec exposes the functionality of a resource dir spec 67 // in a hook context. 68 type ContextDirectorySpec interface { 69 Resolver 70 71 // Initializeprepares the target directory and returns it. 72 Initialize() (DownloadDirectory, error) 73 74 // IsUpToDate indicates whether or not the resource dir is in sync 75 // with the content. 76 IsUpToDate(Content) (bool, error) 77 } 78 79 // NewContextDirectorySpec returns a new directory spec for the context. 80 func NewContextDirectorySpec(dataDir, name string, deps DirectorySpecDeps) ContextDirectorySpec { 81 return &contextDirectorySpec{ 82 DirectorySpec: NewDirectorySpec(dataDir, name, deps), 83 } 84 } 85 86 type contextDirectorySpec struct { 87 *DirectorySpec 88 } 89 90 // Initializeimplements ContextDirectorySpec. 91 func (spec contextDirectorySpec) Initialize() (DownloadDirectory, error) { 92 return spec.DirectorySpec.Initialize() 93 } 94 95 // ContextDownloadDirectory is an adapter for TempDirectorySpec. 96 type ContextDownloadDirectory struct { 97 *TempDirectorySpec 98 } 99 100 // Initialize implements DownloadTarget. 101 func (dir ContextDownloadDirectory) Initialize() (DownloadDirectory, error) { 102 return dir.TempDirectorySpec.Initialize() 103 } 104 105 // ContextOpenedResource exposes the functionality of an "opened" 106 // resource. 107 type ContextOpenedResource interface { 108 ContentSource 109 io.Closer 110 } 111 112 // NewContextContentChecker returns a content checker for the hook context. 113 func NewContextContentChecker(content Content, deps NewContextContentCheckerDeps) ContentChecker { 114 if content.Fingerprint.IsZero() { 115 return &NopChecker{} 116 } 117 118 sizer := deps.NewSizeTracker() 119 checksumWriter := deps.NewChecksumWriter() 120 //checker.checksumWriter = charmresource.NewFingerprintHash() 121 return NewContentChecker(content, sizer, checksumWriter) 122 } 123 124 // NewContextContentCheckerDeps exposes the functionality needed 125 // by NewContextContentChecker(). 126 type NewContextContentCheckerDeps interface { 127 // NewSizeTracker returns a new size tracker. 128 NewSizeTracker() SizeTracker 129 130 // NewChecksumWriter returns a new checksum writer. 131 NewChecksumWriter() ChecksumWriter 132 }