github.com/elopio/cli@v6.21.2-0.20160902224010-ea909d1fdb2f+incompatible/cf/actors/push.go (about) 1 package actors 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 "runtime" 9 10 "code.cloudfoundry.org/cli/cf/api/applicationbits" 11 "code.cloudfoundry.org/cli/cf/api/resources" 12 "code.cloudfoundry.org/cli/cf/appfiles" 13 . "code.cloudfoundry.org/cli/cf/i18n" 14 "code.cloudfoundry.org/cli/cf/models" 15 "code.cloudfoundry.org/gofileutils/fileutils" 16 ) 17 18 const windowsPathPrefix = `\\?\` 19 20 //go:generate counterfeiter . PushActor 21 22 type PushActor interface { 23 UploadApp(appGUID string, zipFile *os.File, presentFiles []resources.AppFileResource) error 24 ProcessPath(dirOrZipFile string, f func(string) error) error 25 GatherFiles(localFiles []models.AppFileFields, appDir string, uploadDir string) ([]resources.AppFileResource, bool, error) 26 ValidateAppParams(apps []models.AppParams) []error 27 MapManifestRoute(routeName string, app models.Application, appParamsFromContext models.AppParams) error 28 } 29 30 type PushActorImpl struct { 31 appBitsRepo applicationbits.Repository 32 appfiles appfiles.AppFiles 33 zipper appfiles.Zipper 34 routeActor RouteActor 35 } 36 37 func NewPushActor(appBitsRepo applicationbits.Repository, zipper appfiles.Zipper, appfiles appfiles.AppFiles, routeActor RouteActor) PushActor { 38 return PushActorImpl{ 39 appBitsRepo: appBitsRepo, 40 appfiles: appfiles, 41 zipper: zipper, 42 routeActor: routeActor, 43 } 44 } 45 46 // ProcessPath takes in a director of app files or a zip file which contains 47 // the app files. If given a zip file, it will extract the zip to a temporary 48 // location, call the provided callback with that location, and then clean up 49 // the location after the callback has been executed. 50 // 51 // This was done so that the caller of ProcessPath wouldn't need to know if it 52 // was a zip file or an app dir that it was given, and the caller would not be 53 // responsible for cleaning up the temporary directory ProcessPath creates when 54 // given a zip. 55 func (actor PushActorImpl) ProcessPath(dirOrZipFile string, f func(string) error) error { 56 if !actor.zipper.IsZipFile(dirOrZipFile) { 57 if filepath.IsAbs(dirOrZipFile) { 58 appDir, err := filepath.EvalSymlinks(dirOrZipFile) 59 if err != nil { 60 return err 61 } 62 err = f(appDir) 63 if err != nil { 64 return err 65 } 66 } else { 67 absPath, err := filepath.Abs(dirOrZipFile) 68 if err != nil { 69 return err 70 } 71 appDir, err := filepath.EvalSymlinks(absPath) 72 if err != nil { 73 return err 74 } 75 76 err = f(appDir) 77 if err != nil { 78 return err 79 } 80 } 81 82 return nil 83 } 84 85 tempDir, err := ioutil.TempDir("", "unzipped-app") 86 if err != nil { 87 return err 88 } 89 90 err = actor.zipper.Unzip(dirOrZipFile, tempDir) 91 if err != nil { 92 return err 93 } 94 95 err = f(tempDir) 96 if err != nil { 97 return err 98 } 99 100 err = os.RemoveAll(tempDir) 101 if err != nil { 102 return err 103 } 104 105 return nil 106 } 107 108 func (actor PushActorImpl) GatherFiles(localFiles []models.AppFileFields, appDir string, uploadDir string) ([]resources.AppFileResource, bool, error) { 109 appFileResource := []resources.AppFileResource{} 110 for _, file := range localFiles { 111 appFileResource = append(appFileResource, resources.AppFileResource{ 112 Path: file.Path, 113 Sha1: file.Sha1, 114 Size: file.Size, 115 }) 116 } 117 118 remoteFiles, err := actor.appBitsRepo.GetApplicationFiles(appFileResource) 119 if err != nil { 120 return []resources.AppFileResource{}, false, err 121 } 122 123 filesToUpload := make([]models.AppFileFields, len(localFiles), len(localFiles)) 124 copy(filesToUpload, localFiles) 125 126 for _, remoteFile := range remoteFiles { 127 for i, fileToUpload := range filesToUpload { 128 if remoteFile.Path == fileToUpload.Path { 129 filesToUpload = append(filesToUpload[:i], filesToUpload[i+1:]...) 130 } 131 } 132 } 133 134 err = actor.appfiles.CopyFiles(filesToUpload, appDir, uploadDir) 135 if err != nil { 136 return []resources.AppFileResource{}, false, err 137 } 138 139 _, err = os.Stat(filepath.Join(appDir, ".cfignore")) 140 if err == nil { 141 err = fileutils.CopyPathToPath(filepath.Join(appDir, ".cfignore"), filepath.Join(uploadDir, ".cfignore")) 142 if err != nil { 143 return []resources.AppFileResource{}, false, err 144 } 145 } 146 147 for i := range remoteFiles { 148 fullPath, err := filepath.Abs(filepath.Join(appDir, remoteFiles[i].Path)) 149 if err != nil { 150 return []resources.AppFileResource{}, false, err 151 } 152 153 if runtime.GOOS == "windows" { 154 fullPath = windowsPathPrefix + fullPath 155 } 156 fileInfo, err := os.Lstat(fullPath) 157 if err != nil { 158 return []resources.AppFileResource{}, false, err 159 } 160 fileMode := fileInfo.Mode() 161 162 if runtime.GOOS == "windows" { 163 fileMode = fileMode | 0700 164 } 165 166 remoteFiles[i].Mode = fmt.Sprintf("%#o", fileMode) 167 } 168 169 return remoteFiles, len(filesToUpload) > 0, nil 170 } 171 172 func (actor PushActorImpl) UploadApp(appGUID string, zipFile *os.File, presentFiles []resources.AppFileResource) error { 173 return actor.appBitsRepo.UploadBits(appGUID, zipFile, presentFiles) 174 } 175 176 func (actor PushActorImpl) ValidateAppParams(apps []models.AppParams) []error { 177 errs := []error{} 178 179 for _, app := range apps { 180 appName := app.Name 181 182 if app.Routes != nil { 183 if app.Hosts != nil { 184 errs = append(errs, fmt.Errorf(T("Application {{.AppName}} must not be configured with both 'routes' and 'host'/'hosts'", map[string]interface{}{"AppName": appName}))) 185 } 186 187 if app.Domains != nil { 188 errs = append(errs, fmt.Errorf(T("Application {{.AppName}} must not be configured with both 'routes' and 'domain'/'domains'", map[string]interface{}{"AppName": appName}))) 189 } 190 191 if app.NoHostname != nil { 192 errs = append(errs, fmt.Errorf(T("Application {{.AppName}} must not be configured with both 'routes' and 'no-hostname'", map[string]interface{}{"AppName": appName}))) 193 } 194 } 195 } 196 197 if len(errs) > 0 { 198 return errs 199 } 200 201 return nil 202 } 203 204 func (actor PushActorImpl) MapManifestRoute(routeName string, app models.Application, appParamsFromContext models.AppParams) error { 205 return actor.routeActor.FindAndBindRoute(routeName, app, appParamsFromContext) 206 }