package assets import ( "archive/zip" "crypto/md5" "crypto/sha1" "crypto/sha256" "crypto/sha512" "encoding/hex" "fmt" "hash" "hash/crc32" "io" "io/ioutil" "os" "path" "path/filepath" "github.com/Nightapes/go-semantic-release/pkg/config" "github.com/pkg/errors" log "github.com/sirupsen/logrus" ) // Asset struct type Asset struct { name string path string zippedPath string algorithm string isCompressed bool } //NewAsset from a config func NewAsset(repository string, assetConfig config.Asset, algorithm string) (*Asset, error) { filePath := assetConfig.Path if assetConfig.Name != "" && assetConfig.Path == "" { filePath = assetConfig.Name log.Warn("Name is deprecated. Please update your config. See https://nightapes.github.io/go-semantic-release/") } realPath := path.Join(repository, filePath) file, err := os.Open(realPath) if err != nil { file.Close() return nil, errors.Wrapf(err, "Could not open file %s", realPath) } defer file.Close() name := assetConfig.Rename if assetConfig.Rename == "" { info, _ := file.Stat() name = info.Name() } asset := &Asset{ path: realPath, name: name, isCompressed: assetConfig.Compress, algorithm: algorithm, } return asset, nil } func (a *Asset) getChecksum() (string, error) { path, err := a.GetPath() if err != nil { return "", nil } log.Debugf("Calculating checksum for %s", path) file, err := os.Open(path) if err != nil { return "", errors.Wrapf(err, "Failed to open file %s to calculate checksum", a.name) } defer file.Close() // nolint: errcheck var hash hash.Hash switch a.algorithm { case "crc32": hash = crc32.NewIEEE() case "md5": hash = md5.New() case "sha1": hash = sha1.New() case "sha224": hash = sha256.New224() case "sha384": hash = sha512.New384() case "sha256": hash = sha256.New() case "sha512": hash = sha512.New() default: hash = sha256.New() } _, err = io.Copy(hash, file) if err != nil { return "", err } return hex.EncodeToString(hash.Sum(nil)), nil } // GetPath where the file is located, if zipped true, it will compress it and give you the new location func (a *Asset) GetPath() (string, error) { if a.isCompressed { return a.ZipFile() } return a.path, nil } // GetName of asset func (a *Asset) GetName() string { if a.isCompressed { return fmt.Sprintf("%s.zip", a.name) } return a.name } // IsCompressed return true if file was zipped func (a *Asset) IsCompressed() bool { return a.isCompressed } // ZipFile compress given file in zip format func (a *Asset) ZipFile() (string, error) { if a.zippedPath != "" { return a.zippedPath, nil } path := a.path fileToZip, err := os.Open(path) if err != nil { return "", errors.Wrapf(err, "Could not open file %s", path) } defer fileToZip.Close() zipFile, err := ioutil.TempFile(os.TempDir(), "asset.*.zip") if err != nil { return "", errors.Wrap(err, "Could not generate tmp file") } log.Debugf("Created zipfile %s", zipFile.Name()) fileToZipInfo, err := fileToZip.Stat() if err != nil { return "", errors.Wrap(err, "Could not read file infos") } zipWriter := zip.NewWriter(zipFile) defer zipWriter.Close() fileToZipHeader, err := zip.FileInfoHeader(fileToZipInfo) if err != nil { return "", errors.Wrap(err, "Could not add file infos to zip handler") } fileToZipHeader.Name = fileToZipInfo.Name() fileToZipWriter, err := zipWriter.CreateHeader(fileToZipHeader) if err != nil { return "", errors.Wrap(err, "Could not create zip header") } if _, err = io.Copy(fileToZipWriter, fileToZip); err != nil { return "", errors.Wrap(err, "Could not zip file") } if err := zipFile.Close(); err != nil { return "", errors.Wrap(err, "Could not close file") } a.zippedPath, err = filepath.Abs(zipFile.Name()) return a.zippedPath, err }