filezip.go 7.71 KiB
Newer Older
package filemdl

import (
	"archive/zip"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strings"

	"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/errormdl"
	"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/loggermdl"
	"github.com/DataDog/zstd"
)

//Zip - Zip
func Zip(source, target string) error {
	source = filepath.Clean(source)
	target = filepath.Clean(target)

	zipfile, err := os.Create(target)
	if err != nil {
		return err
	}
	defer zipfile.Close()

	archive := zip.NewWriter(zipfile)
	defer archive.Close()

	info, err := os.Stat(source)
	if err != nil {
		return err
	}

	var baseDir string
	if info.IsDir() {
		baseDir = filepath.Base(source)
	}

	filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
		if errormdl.CheckErr(err) != nil {
			return errormdl.CheckErr(err)
		}

		header, err := zip.FileInfoHeader(info)
		if errormdl.CheckErr(err) != nil {
			return errormdl.CheckErr(err)
		}

		if baseDir != "" {
			header.Name = filepath.Join(baseDir, strings.TrimPrefix(path, source))
			// Replace all occurances of \\ with /. This is necessary to properly unzip the zip file created on windows system on ubuntu system
			header.Name = strings.Replace(header.Name, "\\", "/", -1)
		}

		if info.IsDir() {
			header.Name += "/"
		} else {
			header.Method = zip.Deflate
		}

		writer, err := archive.CreateHeader(header)
		if errormdl.CheckErr(err) != nil {
			return errormdl.CheckErr(err)
		}

		if info.IsDir() {
			return nil
		}

		file, err := os.Open(path)
		if errormdl.CheckErr(err) != nil {
			return errormdl.CheckErr(err)
		}
		_, err = io.Copy(writer, file)
		if errormdl.CheckErr(err) != nil {
		}

		file.Close()
		return errormdl.CheckErr(err)
	})

	return errormdl.CheckErr(err)
}

//ZipWithoutBaseDirectory Zip Without Base Directory
func ZipWithoutBaseDirectory(source, target string) error {
	source = filepath.Clean(source)
	target = filepath.Clean(target)

	zipfile, err := os.Create(target)
	if err != nil {
		return err
	}
	defer zipfile.Close()

	archive := zip.NewWriter(zipfile)
	defer archive.Close()

	info, err := os.Stat(source)
	if err != nil {
		return err
	}

	var baseDir string
	if info.IsDir() {
		baseDir = filepath.Base(source)
	}

	filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
		if errormdl.CheckErr(err) != nil {
			return errormdl.CheckErr(err)
		}

		header, err := zip.FileInfoHeader(info)
		if errormdl.CheckErr(err) != nil {
			return errormdl.CheckErr(err)
		}

		if baseDir != "" {
			header.Name = strings.TrimPrefix(path, source)
			// Replace all occurances of \\ with /. This is necessary to properly unzip the zip file created on windows system on ubuntu system
			header.Name = strings.Replace(header.Name, "\\", "/", -1)
		}

		if info.IsDir() {
			header.Name += "/"
		} else {
			header.Method = zip.Deflate
		}

		writer, err := archive.CreateHeader(header)
		if errormdl.CheckErr(err) != nil {
			return errormdl.CheckErr(err)
		}

		if info.IsDir() {
			return nil
		}

		file, err := os.Open(path)
		if errormdl.CheckErr(err) != nil {
			return errormdl.CheckErr(err)
		}
		_, err = io.Copy(writer, file)
		if errormdl.CheckErr(err) != nil {
		}

		file.Close()
		return errormdl.CheckErr(err)
	})

	return errormdl.CheckErr(err)
}

//ZipWithSkipFileList This method will skip the file added in skiplist from zip
func ZipWithSkipFileList(source, target string, skipFileList []string) error {

	source = filepath.Clean(source)
	target = filepath.Clean(target)
	zipfile, err := os.Create(target)
	if err != nil {
		return err
	}
	defer zipfile.Close()
	archive := zip.NewWriter(zipfile)
	defer archive.Close()
	info, err := os.Stat(source)
	if err != nil {
		return err
	}
	var baseDir string
	if info.IsDir() {
		baseDir = filepath.Base(source)
	}
	filepath.Walk(source, func(path string, info os.FileInfo, err error) error {

		if !checkPathInSkipList(info.Name(), skipFileList) {
			header, err := zip.FileInfoHeader(info)
			if errormdl.CheckErr(err) != nil {
				return errormdl.CheckErr(err)
			}

			if baseDir != "" {
				header.Name = filepath.Join(baseDir, strings.TrimPrefix(path, source))
				// Replace all occurances of \\ with /. This is necessary to properly unzip the zip file created on windows system on ubuntu system
				header.Name = strings.Replace(header.Name, "\\", "/", -1)
			}

			if info.IsDir() {
				header.Name += "/"
			} else {
				header.Method = zip.Deflate
			}

			writer, err := archive.CreateHeader(header)
			if errormdl.CheckErr(err) != nil {
				return errormdl.CheckErr(err)
			}

			if info.IsDir() {
				return nil
			}

			file, err := os.Open(path)
			if errormdl.CheckErr(err) != nil {
				return errormdl.CheckErr(err)
			}

			_, err = io.Copy(writer, file)
			if err != nil {
			}

			file.Close()
			return nil
		}

		return nil
	})
	return errormdl.CheckErr(err)
}

func checkPathInSkipList(path string, skipList []string) bool {
	for _, prefix := range skipList {
		if strings.HasPrefix(path, prefix) {
			return true
		}
		if strings.HasSuffix(path, prefix) {
			return true
		}
	}
	return false
}

//Unzip Unzip
func Unzip(archive, target string) error {
	reader, err := zip.OpenReader(archive)
	if err != nil {
		loggermdl.LogError(err)
		return err
	}

	mkcDirError := os.MkdirAll(target, 0755)
	if mkcDirError != nil {
		loggermdl.LogError(mkcDirError)
		return mkcDirError
	}

	for _, file := range reader.File {
		filePath := filepath.Join(target, file.Name)
		parentPath := path.Dir(CleanPath(filePath))

		if !FileAvailabilityCheck(parentPath) {
			CreateDirectoryRecursive(parentPath)
		}

		if file.FileInfo().IsDir() {
			os.MkdirAll(filePath, file.Mode())
			continue
		}

		fileReader, openError := file.Open()
		if openError != nil {
			loggermdl.LogError(openError)
			return openError
		}

		targetFile, targetOpenError := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
		if targetOpenError != nil {
			loggermdl.LogError(targetOpenError)
			return targetOpenError
		}

		_, copyError := io.Copy(targetFile, fileReader)
		if copyError != nil {
			loggermdl.LogError(copyError)
			return copyError
		}
		targetCloseError := targetFile.Close()
		if targetCloseError != nil {
			loggermdl.LogError(targetCloseError)
			return targetCloseError
		}

		fileCloseError := fileReader.Close()
		if fileCloseError != nil {
			loggermdl.LogError(fileCloseError)
			return fileCloseError
		}
	}
	closeError := reader.Close()
	if closeError != nil {
		loggermdl.LogError(closeError)
		return closeError
	}
	return nil
}

//zip byte array
func zipBytes(inputData []byte) ([]byte, error) {
	compressedData, err := zstd.CompressLevel(nil, inputData, 9)
	return compressedData, err
}

// ZipSingleFile - Zip single file
func ZipSingleFile(sourceFilePath, destFilePath string) error {
	inputData, err := ioutil.ReadFile(sourceFilePath)
	if errormdl.CheckErr(err) != nil {
		return errormdl.CheckErr(err)
	}
	compressedData, err := zipBytes(inputData)
	if errormdl.CheckErr(err) != nil {
		return errormdl.CheckErr(err)
	}
	err = ioutil.WriteFile(destFilePath, compressedData, 0644)
	if errormdl.CheckErr(err) != nil {
		return errormdl.CheckErr(err)
	}
	return nil
}

//unzip bytes - Decompress
func unzipBytes(compressedData []byte) ([]byte, error) {
	decompressedData, err := zstd.Decompress(nil, compressedData)
Mahendra Vishwakarma's avatar
Mahendra Vishwakarma committed
	return decompressedData, errormdl.CheckErr(err)
}

// UnZipSingleFile - UnZip Single File
func UnZipSingleFile(sourceFilePath, destFilePath string) error {
	inputData, err := ioutil.ReadFile(sourceFilePath)
	if errormdl.CheckErr(err) != nil {
		return errormdl.CheckErr(err)
	}
	uncompressedData, err := unzipBytes(inputData)
	if errormdl.CheckErr(err) != nil {
		return errormdl.CheckErr(err)
	}
	err = ioutil.WriteFile(destFilePath, uncompressedData, 0644)
	if errormdl.CheckErr(err) != nil {
		return errormdl.CheckErr(err)
	}
	return nil
}