github.com/loggregator/cli@v6.33.1-0.20180224010324-82334f081791+incompatible/cf/appfiles/app_files.go (about) 1 package appfiles 2 3 import ( 4 "crypto/sha1" 5 "fmt" 6 "io" 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 "runtime" 11 12 "code.cloudfoundry.org/cli/cf/models" 13 "code.cloudfoundry.org/gofileutils/fileutils" 14 ) 15 16 const windowsPathPrefix = `\\?\` 17 18 //go:generate counterfeiter . AppFiles 19 20 type AppFiles interface { 21 AppFilesInDir(dir string) (appFiles []models.AppFileFields, err error) 22 CopyFiles(appFiles []models.AppFileFields, fromDir, toDir string) (err error) 23 CountFiles(directory string) int64 24 WalkAppFiles(dir string, onEachFile func(string, string) error) (err error) 25 } 26 27 type ApplicationFiles struct{} 28 29 func (appfiles ApplicationFiles) AppFilesInDir(dir string) ([]models.AppFileFields, error) { 30 appFiles := []models.AppFileFields{} 31 32 fullDirPath, toplevelErr := filepath.Abs(dir) 33 if toplevelErr != nil { 34 return appFiles, toplevelErr 35 } 36 37 toplevelErr = appfiles.WalkAppFiles(fullDirPath, func(fileName string, fullPath string) error { 38 fileInfo, err := os.Lstat(fullPath) 39 if err != nil { 40 return err 41 } 42 43 appFile := models.AppFileFields{ 44 Path: filepath.ToSlash(fileName), 45 Size: fileInfo.Size(), 46 } 47 48 if fileInfo.IsDir() { 49 appFile.Sha1 = "0" 50 appFile.Size = 0 51 } else { 52 sha, err := appfiles.shaFile(fullPath) 53 if err != nil { 54 return err 55 } 56 appFile.Sha1 = sha 57 } 58 59 appFiles = append(appFiles, appFile) 60 61 return nil 62 }) 63 64 return appFiles, toplevelErr 65 } 66 67 func (appfiles ApplicationFiles) shaFile(fullPath string) (string, error) { 68 hash := sha1.New() 69 file, err := os.Open(fullPath) 70 if err != nil { 71 return "", err 72 } 73 defer file.Close() 74 75 _, err = io.Copy(hash, file) 76 if err != nil { 77 return "", err 78 } 79 80 return fmt.Sprintf("%x", hash.Sum(nil)), nil 81 } 82 83 func (appfiles ApplicationFiles) CopyFiles(appFiles []models.AppFileFields, fromDir, toDir string) error { 84 for _, file := range appFiles { 85 err := func() error { 86 fromPath, err := filepath.Abs(filepath.Join(fromDir, file.Path)) 87 if err != nil { 88 return err 89 } 90 91 if runtime.GOOS == "windows" { 92 fromPath = windowsPathPrefix + fromPath 93 } 94 95 srcFileInfo, err := os.Stat(fromPath) 96 if err != nil { 97 return err 98 } 99 100 toPath, err := filepath.Abs(filepath.Join(toDir, file.Path)) 101 if err != nil { 102 return err 103 } 104 105 if runtime.GOOS == "windows" { 106 toPath = windowsPathPrefix + toPath 107 } 108 109 if srcFileInfo.IsDir() { 110 err = os.MkdirAll(toPath, srcFileInfo.Mode()) 111 if err != nil { 112 return err 113 } 114 return nil 115 } 116 117 return appfiles.copyFile(fromPath, toPath, srcFileInfo.Mode()) 118 }() 119 120 if err != nil { 121 return err 122 } 123 } 124 125 return nil 126 } 127 128 func (appfiles ApplicationFiles) copyFile(srcPath string, dstPath string, fileMode os.FileMode) error { 129 dst, err := fileutils.Create(dstPath) 130 if err != nil { 131 return err 132 } 133 defer dst.Close() 134 135 if runtime.GOOS != "windows" { 136 err = dst.Chmod(fileMode) 137 if err != nil { 138 return err 139 } 140 } 141 142 src, err := os.Open(srcPath) 143 if err != nil { 144 return err 145 } 146 defer src.Close() 147 148 _, err = io.Copy(dst, src) 149 if err != nil { 150 return err 151 } 152 153 return nil 154 } 155 156 func (appfiles ApplicationFiles) CountFiles(directory string) int64 { 157 var count int64 158 appfiles.WalkAppFiles(directory, func(_, _ string) error { 159 count++ 160 return nil 161 }) 162 return count 163 } 164 165 func (appfiles ApplicationFiles) WalkAppFiles(dir string, onEachFile func(string, string) error) error { 166 cfIgnore := loadIgnoreFile(dir) 167 walkFunc := func(fullPath string, f os.FileInfo, err error) error { 168 fileRelativePath, _ := filepath.Rel(dir, fullPath) 169 fileRelativeUnixPath := filepath.ToSlash(fileRelativePath) 170 171 if err != nil && runtime.GOOS == "windows" { 172 f, err = os.Lstat(windowsPathPrefix + fullPath) 173 if err != nil { 174 return err 175 } 176 fullPath = windowsPathPrefix + fullPath 177 } 178 179 if fullPath == dir { 180 return nil 181 } 182 183 if cfIgnore.FileShouldBeIgnored(fileRelativeUnixPath) { 184 if err == nil && f.IsDir() { 185 return filepath.SkipDir 186 } 187 return nil 188 } 189 190 if err != nil { 191 return err 192 } 193 194 if !f.Mode().IsRegular() && !f.IsDir() { 195 return nil 196 } 197 198 return onEachFile(fileRelativePath, fullPath) 199 } 200 201 return filepath.Walk(dir, walkFunc) 202 } 203 204 func loadIgnoreFile(dir string) CfIgnore { 205 fileContents, err := ioutil.ReadFile(filepath.Join(dir, ".cfignore")) 206 if err != nil { 207 return NewCfIgnore("") 208 } 209 210 return NewCfIgnore(string(fileContents)) 211 }