func TestCopy(t *testing.T) { Convey("Copy file from A to B", t, func() { Convey("Copy a file that does exist", func() { tmpPath := path.Join(os.TempDir(), "testdata/README.txt") So(cae.Copy(tmpPath, "testdata/README.txt"), ShouldBeNil) So(cae.IsExist(tmpPath), ShouldBeTrue) }) Convey("Copy a file that does not exist", func() { So(cae.Copy( path.Join(os.TempDir(), "testdata/README.txt"), "testdata/404.txt"), ShouldNotBeNil) }) }) }
// extractFile extracts file from ZipArchive to file system. func (z *ZipArchive) extractFile(f *File) error { if !z.isHasWriter { for _, zf := range z.ReadCloser.File { if f.Name == zf.Name { return extractFile(zf, path.Dir(f.tmpPath)) } } } return cae.Copy(f.tmpPath, f.absPath) }
// extractFile extracts file from TzArchive to file system. func (tz *TzArchive) extractFile(f *File, tr *tar.Reader) error { if !tz.isHasWriter { for _, h := range tz.ReadCloser.File { if f.Name == h.Name { return extractFile(h, tr, f.absPath) } } } return cae.Copy(f.Name, f.absPath) }
// ExtractTo extracts the whole archive or the given files to the // specified destination. // It accepts a function as a middleware for custom operations. func (tz *TzArchive) ExtractToFunc(destPath string, fn cae.HookFunc, entries ...string) (err error) { destPath = strings.Replace(destPath, "\\", "/", -1) isHasEntry := len(entries) > 0 if Verbose { fmt.Println("Extracting " + tz.FileName + "...") } os.MkdirAll(destPath, os.ModePerm) // Copy post-added files. for _, f := range tz.files { if !cae.IsExist(f.absPath) { continue } relPath := path.Join(destPath, f.Name) os.MkdirAll(path.Dir(relPath), os.ModePerm) if err := cae.Copy(relPath, f.absPath); err != nil { return err } } tr, f, err := openFile(tz.FileName) if err != nil { return err } defer f.Close() for { h, err := tr.Next() if err == io.EOF { break } else if err != nil { return err } h.Name = strings.Replace(h.Name, "\\", "/", -1) // Directory. if h.Typeflag == tar.TypeDir { if isHasEntry { if cae.IsEntry(h.Name, entries) { if err = fn(h.Name, h.FileInfo()); err != nil { continue } os.MkdirAll(path.Join(destPath, h.Name), os.ModePerm) } continue } if err = fn(h.Name, h.FileInfo()); err != nil { continue } os.MkdirAll(path.Join(destPath, h.Name), os.ModePerm) continue } // File. if isHasEntry { if cae.IsEntry(h.Name, entries) { if err = fn(h.Name, h.FileInfo()); err != nil { continue } err = extractFile(h, tr, destPath) } } else { if err = fn(h.Name, h.FileInfo()); err != nil { continue } err = extractFile(h, tr, destPath) } if err != nil { return err } } return nil }
// Flush saves changes to original zip file if any. func (tz *TzArchive) Flush() (err error) { if !tz.isHasChanged || (tz.ReadCloser == nil && !tz.isHasWriter) { return nil } // Extract to tmp path and pack back. tmpPath := path.Join(os.TempDir(), "cae", path.Base(tz.FileName)) os.RemoveAll(tmpPath) os.MkdirAll(tmpPath, os.ModePerm) defer os.RemoveAll(tmpPath) // Copy post-added files. for _, f := range tz.files { if strings.HasSuffix(f.Name, "/") { os.MkdirAll(path.Join(tmpPath, f.Name), os.ModePerm) continue } else if !cae.IsExist(f.absPath) { continue } relPath := path.Join(tmpPath, f.Name) os.MkdirAll(path.Dir(relPath), os.ModePerm) if err := cae.Copy(relPath, f.absPath); err != nil { return err } } if !tz.isHasWriter { tz.ReadCloser, err = openReader(tz.FileName) if err != nil { return err } tz.syncFiles() tr, f, err := openFile(tz.FileName) if err != nil { return err } defer f.Close() i := 0 for { h, err := tr.Next() if err == io.EOF { break } else if err != nil { return err } if h.Typeflag == tar.TypeDir { os.MkdirAll(path.Join(tmpPath, h.Name), os.ModePerm) continue } // Relative path inside zip temporary changed. fileName := tz.files[i].Name tz.files[i].Name = path.Join(tmpPath, fileName) if err := tz.extractFile(tz.files[i], tr); err != nil { return err } // Change back here. tz.files[i].Name = fileName i++ } } if tz.isHasWriter { return packToWriter(tmpPath, tz.writer, defaultPackFunc, true) } if err := PackTo(tmpPath, tz.FileName); err != nil { return err } return tz.Open(tz.FileName, os.O_RDWR|os.O_TRUNC, tz.Permission) }