github.com/rakutentech/cli@v6.12.5-0.20151006231303-24468b65536e+incompatible/cf/app_files/zipper.go (about) 1 package app_files 2 3 import ( 4 "archive/zip" 5 "io" 6 "os" 7 "path/filepath" 8 9 "github.com/cloudfoundry/cli/cf/errors" 10 "github.com/cloudfoundry/gofileutils/fileutils" 11 ) 12 13 type Zipper interface { 14 Zip(dirToZip string, targetFile *os.File) (err error) 15 IsZipFile(path string) bool 16 Unzip(appDir string, destDir string) (err error) 17 GetZipSize(zipFile *os.File) (int64, error) 18 } 19 20 type ApplicationZipper struct{} 21 22 func (zipper ApplicationZipper) Zip(dirOrZipFile string, targetFile *os.File) (err error) { 23 if zipper.IsZipFile(dirOrZipFile) { 24 err = fileutils.CopyPathToWriter(dirOrZipFile, targetFile) 25 } else { 26 err = writeZipFile(dirOrZipFile, targetFile) 27 } 28 targetFile.Seek(0, os.SEEK_SET) 29 return 30 } 31 32 func (zipper ApplicationZipper) IsZipFile(file string) (result bool) { 33 _, err := zip.OpenReader(file) 34 return err == nil 35 } 36 37 func writeZipFile(dir string, targetFile *os.File) error { 38 isEmpty, err := fileutils.IsDirEmpty(dir) 39 if err != nil { 40 return err 41 } 42 43 if isEmpty { 44 return errors.NewEmptyDirError(dir) 45 } 46 47 writer := zip.NewWriter(targetFile) 48 defer writer.Close() 49 50 appfiles := ApplicationFiles{} 51 return appfiles.WalkAppFiles(dir, func(fileName string, fullPath string) error { 52 fileInfo, err := os.Stat(fullPath) 53 if err != nil { 54 return err 55 } 56 57 header, err := zip.FileInfoHeader(fileInfo) 58 if err != nil { 59 return err 60 } 61 62 header.Name = filepath.ToSlash(fileName) 63 64 if fileInfo.IsDir() { 65 header.Name += "/" 66 } 67 68 zipFilePart, err := writer.CreateHeader(header) 69 if err != nil { 70 return err 71 } 72 73 if fileInfo.IsDir() { 74 return nil 75 } else { 76 return fileutils.CopyPathToWriter(fullPath, zipFilePart) 77 } 78 }) 79 } 80 81 func (zipper ApplicationZipper) Unzip(appDir string, destDir string) (err error) { 82 r, err := zip.OpenReader(appDir) 83 if err != nil { 84 return 85 } 86 defer r.Close() 87 88 for _, f := range r.File { 89 func() { 90 // Don't try to extract directories 91 if f.FileInfo().IsDir() { 92 return 93 } 94 95 var rc io.ReadCloser 96 rc, err = f.Open() 97 if err != nil { 98 return 99 } 100 101 // functional scope from above is important 102 // otherwise this only closes the last file handle 103 defer rc.Close() 104 105 destFilePath := filepath.Join(destDir, f.Name) 106 107 err = fileutils.CopyReaderToPath(rc, destFilePath) 108 if err != nil { 109 return 110 } 111 112 err = os.Chmod(destFilePath, f.FileInfo().Mode()) 113 if err != nil { 114 return 115 } 116 }() 117 } 118 119 return 120 } 121 122 func (zipper ApplicationZipper) GetZipSize(zipFile *os.File) (int64, error) { 123 zipFileSize := int64(0) 124 125 stat, err := zipFile.Stat() 126 if err != nil { 127 return 0, err 128 } 129 130 zipFileSize = int64(stat.Size()) 131 132 return zipFileSize, nil 133 }