github.com/cloudfoundry-attic/ltc@v0.0.0-20151123212628-098adc7919fc/droplet_runner/command_factory/zipper/zipper.go (about)

     1  package zipper
     2  
     3  import (
     4  	"archive/zip"
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  	"os"
     9  	"path/filepath"
    10  	"strings"
    11  
    12  	"github.com/cloudfoundry-incubator/ltc/droplet_runner/command_factory/cf_ignore"
    13  )
    14  
    15  //go:generate counterfeiter -o fake_zipper/fake_zipper.go . Zipper
    16  type Zipper interface {
    17  	Zip(srcDir string, cfIgnore cf_ignore.CFIgnore) (string, error)
    18  	IsZipFile(path string) bool
    19  	Unzip(srcZip string, destDir string) error
    20  }
    21  
    22  type DropletArtifactZipper struct{}
    23  
    24  func (zipper *DropletArtifactZipper) Zip(srcDir string, cfIgnore cf_ignore.CFIgnore) (string, error) {
    25  	tmpPath, err := ioutil.TempDir(os.TempDir(), "droplet-artifact-zipper")
    26  	if err != nil {
    27  		return "", err
    28  	}
    29  
    30  	fileWriter, err := os.OpenFile(filepath.Join(tmpPath, "artifact.zip"), os.O_CREATE|os.O_WRONLY, 0600)
    31  	if err != nil {
    32  		return "", err
    33  	}
    34  	defer fileWriter.Close()
    35  
    36  	zipWriter := zip.NewWriter(fileWriter)
    37  	defer zipWriter.Close()
    38  
    39  	contentsFileInfo, err := os.Stat(srcDir)
    40  	if err != nil {
    41  		return "", err
    42  	}
    43  
    44  	if !contentsFileInfo.IsDir() {
    45  		return "", fmt.Errorf("%s must be a directory", srcDir)
    46  	}
    47  
    48  	if ignoreFile, err := os.Open(filepath.Join(srcDir, ".cfignore")); err == nil {
    49  		defer ignoreFile.Close()
    50  
    51  		if err := cfIgnore.Parse(ignoreFile); err != nil {
    52  			return "", err
    53  		}
    54  	}
    55  
    56  	err = filepath.Walk(srcDir, func(fullPath string, info os.FileInfo, err error) error {
    57  		if err != nil {
    58  			return err
    59  		}
    60  
    61  		relativePath, err := filepath.Rel(srcDir, fullPath)
    62  		if err != nil {
    63  			return err
    64  		}
    65  
    66  		if cfIgnore.ShouldIgnore(relativePath) {
    67  			return nil
    68  		}
    69  
    70  		if relativePath == fileWriter.Name() || relativePath == "." || relativePath == ".." {
    71  			return nil
    72  		}
    73  
    74  		if h, err := zip.FileInfoHeader(info); err == nil {
    75  			h.Name = filepath.ToSlash(relativePath)
    76  
    77  			if info.IsDir() {
    78  				h.Name = h.Name + "/"
    79  			}
    80  
    81  			h.SetMode(info.Mode())
    82  
    83  			writer, err := zipWriter.CreateHeader(h)
    84  			if err != nil {
    85  				return err
    86  			}
    87  
    88  			if info.IsDir() {
    89  				return nil
    90  			}
    91  
    92  			li, err := os.Lstat(fullPath)
    93  			if err != nil {
    94  				return err
    95  			}
    96  
    97  			if li.Mode()&os.ModeSymlink == os.ModeSymlink {
    98  				dest, err := os.Readlink(fullPath)
    99  				if err != nil {
   100  					return err
   101  				}
   102  				if _, err := io.Copy(writer, strings.NewReader(dest)); err != nil {
   103  					return err
   104  				}
   105  			} else {
   106  				fr, err := os.Open(fullPath)
   107  				if err != nil {
   108  					return err
   109  				}
   110  				defer fr.Close()
   111  				if _, err := io.Copy(writer, fr); err != nil {
   112  					return err
   113  				}
   114  			}
   115  		}
   116  
   117  		return nil
   118  	})
   119  
   120  	return fileWriter.Name(), err
   121  }
   122  
   123  func (zipper *DropletArtifactZipper) IsZipFile(path string) bool {
   124  	reader, err := zip.OpenReader(path)
   125  	if err != nil {
   126  		return false
   127  	} else {
   128  		reader.Close()
   129  		return true
   130  	}
   131  }
   132  
   133  func (zipper *DropletArtifactZipper) Unzip(srcZip string, destDir string) error {
   134  	reader, err := zip.OpenReader(srcZip)
   135  	if err != nil {
   136  		return err
   137  	}
   138  	defer reader.Close()
   139  
   140  	for _, f := range reader.File {
   141  		err := func() error {
   142  			fileReader, err := f.Open()
   143  			if err != nil {
   144  				return err
   145  			}
   146  			defer fileReader.Close()
   147  
   148  			fileInfo := f.FileHeader.FileInfo()
   149  
   150  			if fileInfo.IsDir() {
   151  				return nil
   152  			}
   153  
   154  			if err := os.MkdirAll(filepath.Dir(filepath.Join(destDir, f.FileHeader.Name)), os.ModeDir|os.ModePerm); err != nil {
   155  				return err
   156  			}
   157  
   158  			fileWriter, err := os.OpenFile(filepath.Join(destDir, f.FileHeader.Name), os.O_CREATE|os.O_WRONLY, f.FileHeader.Mode())
   159  			if err != nil {
   160  				return err
   161  			}
   162  			defer fileWriter.Close()
   163  
   164  			_, err = io.Copy(fileWriter, fileReader)
   165  			if err != nil {
   166  				return err
   167  			}
   168  
   169  			return nil
   170  		}()
   171  
   172  		if err != nil {
   173  			return err
   174  		}
   175  	}
   176  
   177  	return nil
   178  }