diff options
author | Unknwon <u@gogs.io> | 2017-02-09 19:48:13 -0500 |
---|---|---|
committer | Unknwon <u@gogs.io> | 2017-02-09 19:48:13 -0500 |
commit | 2fd69f13d9599a6c58b47225565163fd7d87889f (patch) | |
tree | fd19e868e1c2e95a5fb83a268f6e393669d6ee79 /vendor/github.com/Unknwon/cae/zip/write.go | |
parent | eb66060cd7b9bce996b1d75ae80ce1ef31d5ce62 (diff) |
vendor: check in vendors
Bye bye glide...
Diffstat (limited to 'vendor/github.com/Unknwon/cae/zip/write.go')
-rw-r--r-- | vendor/github.com/Unknwon/cae/zip/write.go | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/vendor/github.com/Unknwon/cae/zip/write.go b/vendor/github.com/Unknwon/cae/zip/write.go new file mode 100644 index 00000000..076d0e34 --- /dev/null +++ b/vendor/github.com/Unknwon/cae/zip/write.go @@ -0,0 +1,364 @@ +// Copyright 2013 Unknown +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package zip + +import ( + "archive/zip" + "fmt" + "io" + "os" + "path" + "path/filepath" + "strings" + + "github.com/Unknwon/cae" +) + +// Switcher of printing trace information when pack and extract. +var Verbose = true + +// extractFile extracts zip.File to file system. +func extractFile(f *zip.File, destPath string) error { + filePath := path.Join(destPath, f.Name) + os.MkdirAll(path.Dir(filePath), os.ModePerm) + + rc, err := f.Open() + if err != nil { + return err + } + defer rc.Close() + + fw, err := os.Create(filePath) + if err != nil { + return err + } + defer fw.Close() + + if _, err = io.Copy(fw, rc); err != nil { + return err + } + + // Skip symbolic links. + if f.FileInfo().Mode()&os.ModeSymlink != 0 { + return nil + } + // Set back file information. + if err = os.Chtimes(filePath, f.ModTime(), f.ModTime()); err != nil { + return err + } + return os.Chmod(filePath, f.FileInfo().Mode()) +} + +var defaultExtractFunc = func(fullName string, fi os.FileInfo) error { + if !Verbose { + return nil + } + + fmt.Println("Extracting file..." + fullName) + return nil +} + +// ExtractToFunc extracts the whole archive or the given files to the +// specified destination. +// It accepts a function as a middleware for custom operations. +func (z *ZipArchive) ExtractToFunc(destPath string, fn cae.HookFunc, entries ...string) (err error) { + destPath = strings.Replace(destPath, "\\", "/", -1) + isHasEntry := len(entries) > 0 + if Verbose { + fmt.Println("Unzipping " + z.FileName + "...") + } + os.MkdirAll(destPath, os.ModePerm) + for _, f := range z.File { + f.Name = strings.Replace(f.Name, "\\", "/", -1) + + // Directory. + if strings.HasSuffix(f.Name, "/") { + if isHasEntry { + if cae.IsEntry(f.Name, entries) { + if err = fn(f.Name, f.FileInfo()); err != nil { + continue + } + os.MkdirAll(path.Join(destPath, f.Name), os.ModePerm) + } + continue + } + if err = fn(f.Name, f.FileInfo()); err != nil { + continue + } + os.MkdirAll(path.Join(destPath, f.Name), os.ModePerm) + continue + } + + // File. + if isHasEntry { + if cae.IsEntry(f.Name, entries) { + if err = fn(f.Name, f.FileInfo()); err != nil { + continue + } + err = extractFile(f, destPath) + } + } else { + if err = fn(f.Name, f.FileInfo()); err != nil { + continue + } + err = extractFile(f, destPath) + } + if err != nil { + return err + } + } + return nil +} + +// ExtractToFunc extracts the whole archive or the given files to the +// specified destination. +// It accepts a function as a middleware for custom operations. +func ExtractToFunc(srcPath, destPath string, fn cae.HookFunc, entries ...string) (err error) { + z, err := Open(srcPath) + if err != nil { + return err + } + defer z.Close() + return z.ExtractToFunc(destPath, fn, entries...) +} + +// ExtractTo extracts the whole archive or the given files to the +// specified destination. +// Call Flush() to apply changes before this. +func (z *ZipArchive) ExtractTo(destPath string, entries ...string) (err error) { + return z.ExtractToFunc(destPath, defaultExtractFunc, entries...) +} + +// ExtractTo extracts given archive or the given files to the +// specified destination. +func ExtractTo(srcPath, destPath string, entries ...string) (err error) { + return ExtractToFunc(srcPath, destPath, defaultExtractFunc, entries...) +} + +// 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) +} + +// Flush saves changes to original zip file if any. +func (z *ZipArchive) Flush() error { + if !z.isHasChanged || (z.ReadCloser == nil && !z.isHasWriter) { + return nil + } + + // Extract to tmp path and pack back. + tmpPath := path.Join(os.TempDir(), "cae", path.Base(z.FileName)) + os.RemoveAll(tmpPath) + defer os.RemoveAll(tmpPath) + + for _, f := range z.files { + if strings.HasSuffix(f.Name, "/") { + os.MkdirAll(path.Join(tmpPath, f.Name), os.ModePerm) + continue + } + + // Relative path inside zip temporary changed. + f.tmpPath = path.Join(tmpPath, f.Name) + if err := z.extractFile(f); err != nil { + return err + } + } + + if z.isHasWriter { + return packToWriter(tmpPath, z.writer, defaultPackFunc, true) + } + + if err := PackTo(tmpPath, z.FileName); err != nil { + return err + } + return z.Open(z.FileName, os.O_RDWR|os.O_TRUNC, z.Permission) +} + +// packFile packs a file or directory to zip.Writer. +func packFile(srcFile string, recPath string, zw *zip.Writer, fi os.FileInfo) error { + if fi.IsDir() { + fh, err := zip.FileInfoHeader(fi) + if err != nil { + return err + } + fh.Name = recPath + "/" + if _, err = zw.CreateHeader(fh); err != nil { + return err + } + } else { + fh, err := zip.FileInfoHeader(fi) + if err != nil { + return err + } + fh.Name = recPath + fh.Method = zip.Deflate + + fw, err := zw.CreateHeader(fh) + if err != nil { + return err + } + + if fi.Mode()&os.ModeSymlink != 0 { + target, err := os.Readlink(srcFile) + if err != nil { + return err + } + if _, err = fw.Write([]byte(target)); err != nil { + return err + } + } else { + f, err := os.Open(srcFile) + if err != nil { + return err + } + defer f.Close() + + if _, err = io.Copy(fw, f); err != nil { + return err + } + } + } + return nil +} + +// packDir packs a directory and its subdirectories and files +// recursively to zip.Writer. +func packDir(srcPath string, recPath string, zw *zip.Writer, fn cae.HookFunc) error { + dir, err := os.Open(srcPath) + if err != nil { + return err + } + defer dir.Close() + + fis, err := dir.Readdir(0) + if err != nil { + return err + } + for _, fi := range fis { + if cae.IsFilter(fi.Name()) { + continue + } + curPath := srcPath + "/" + fi.Name() + tmpRecPath := filepath.Join(recPath, fi.Name()) + if err = fn(curPath, fi); err != nil { + continue + } + + if fi.IsDir() { + if err = packFile(srcPath, tmpRecPath, zw, fi); err != nil { + return err + } + err = packDir(curPath, tmpRecPath, zw, fn) + } else { + err = packFile(curPath, tmpRecPath, zw, fi) + } + if err != nil { + return err + } + } + return nil +} + +// packToWriter packs given path object to io.Writer. +func packToWriter(srcPath string, w io.Writer, fn func(fullName string, fi os.FileInfo) error, includeDir bool) error { + zw := zip.NewWriter(w) + defer zw.Close() + + f, err := os.Open(srcPath) + if err != nil { + return err + } + defer f.Close() + + fi, err := f.Stat() + if err != nil { + return err + } + + basePath := path.Base(srcPath) + if fi.IsDir() { + if includeDir { + if err = packFile(srcPath, basePath, zw, fi); err != nil { + return err + } + } else { + basePath = "" + } + return packDir(srcPath, basePath, zw, fn) + } + return packFile(srcPath, basePath, zw, fi) +} + +// packTo packs given source path object to target path. +func packTo(srcPath, destPath string, fn cae.HookFunc, includeDir bool) error { + fw, err := os.Create(destPath) + if err != nil { + return err + } + defer fw.Close() + + return packToWriter(srcPath, fw, fn, includeDir) +} + +// PackToFunc packs the complete archive to the specified destination. +// It accepts a function as a middleware for custom operations. +func PackToFunc(srcPath, destPath string, fn func(fullName string, fi os.FileInfo) error, includeDir ...bool) error { + isIncludeDir := false + if len(includeDir) > 0 && includeDir[0] { + isIncludeDir = true + } + return packTo(srcPath, destPath, fn, isIncludeDir) +} + +var defaultPackFunc = func(fullName string, fi os.FileInfo) error { + if !Verbose { + return nil + } + + if fi.IsDir() { + fmt.Printf("Adding dir...%s\n", fullName) + } else { + fmt.Printf("Adding file...%s\n", fullName) + } + return nil +} + +// PackTo packs the whole archive to the specified destination. +// Call Flush() will automatically call this in the end. +func PackTo(srcPath, destPath string, includeDir ...bool) error { + return PackToFunc(srcPath, destPath, defaultPackFunc, includeDir...) +} + +// Close opens or creates archive and save changes. +func (z *ZipArchive) Close() (err error) { + if err = z.Flush(); err != nil { + return err + } + + if z.ReadCloser != nil { + if err = z.ReadCloser.Close(); err != nil { + return err + } + z.ReadCloser = nil + } + return nil +} |