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  }