Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add archive utils with compression options #870

Merged
merged 4 commits into from
Sep 21, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions common/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,13 @@ var PlanProgressNumBaseDetectTransformers = 0

// PlanProgressNumDirectories keeps track of the number of files/folders analyzed during planning
var PlanProgressNumDirectories = 0

// CompressionType refers to the compression type
type CompressionType = string

const (
// GZipCompressionType allows archival using gzip compression format
GZipCompressionType CompressionType = "GZip"
// DefaultCompressionType allows archival without compression
DefaultCompressionType CompressionType = "Default"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the default is no compression, isn't it? I assume Tar is not a compression format. So can we possibly call it as NoCompression = None?

)
112 changes: 112 additions & 0 deletions common/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
package common

import (
"archive/tar"
"bytes"
"compress/gzip"
"crypto/sha256"
"embed"
"encoding/json"
Expand All @@ -39,6 +41,7 @@ import (
"unicode"

"github.com/Masterminds/sprig"
"github.com/docker/docker/pkg/ioutils"
"github.com/go-git/go-git/v5"
"github.com/konveyor/move2kube/types"
"github.com/mitchellh/mapstructure"
Expand Down Expand Up @@ -1328,3 +1331,112 @@ func ReplaceStartingTerminatingHyphens(str, startReplaceStr, endReplaceStr strin
}
return str
}

// CreateTarArchiveGZipStringWrapper can be used to archive a set of files and compression using gzip and return tar archive string
func CreateTarArchiveGZipStringWrapper(srcDir string) string {
reader := ReadDirAsTar(srcDir, "", GZipCompressionType)
if reader == nil {
logrus.Errorf("error during create tar archive from '%s'", srcDir)
}
defer reader.Close()
buf := new(bytes.Buffer)
_, err := io.Copy(buf, reader)
if err != nil {
logrus.Errorf("failed to copy bytes to buffer : %s", err)
}

return buf.String()

}

// ReadDirAsTar creates the Tar with given compression format and return ReadCloser interface
func ReadDirAsTar(srcDir, basePath string, compressionType CompressionType) io.ReadCloser {
errChan := make(chan error)
pr, pw := io.Pipe()
go func() {
err := writeDirToTar(pw, srcDir, basePath, compressionType)
errChan <- err
}()
closed := false
return ioutils.NewReadCloserWrapper(pr, func() error {
if closed {
return errors.New("reader already closed")
}
perr := pr.Close()
if err := <-errChan; err != nil {
closed = true
if perr == nil {
return err
}
return fmt.Errorf("%s - %s", perr, err)
}
closed = true
return nil
})
}

func writeDirToTar(w *io.PipeWriter, srcDir, basePath string, compressionType CompressionType) error {
defer w.Close()
var tw *tar.Writer
switch compressionType {
case GZipCompressionType:
// create writer for gzip
gzipWriter := gzip.NewWriter(w)
defer gzipWriter.Close()
tw = tar.NewWriter(gzipWriter)
default:
tw = tar.NewWriter(w)
}
defer tw.Close()
return filepath.Walk(srcDir, func(file string, fi os.FileInfo, err error) error {
if err != nil {
logrus.Debugf("Error walking folder to copy to container : %s", err)
return err
}
if fi.Mode()&os.ModeSocket != 0 {
return nil
}
var header *tar.Header
if fi.Mode()&os.ModeSymlink != 0 {
target, err := os.Readlink(file)
if err != nil {
return err
}
// Ensure that symlinks have Linux link names
header, err = tar.FileInfoHeader(fi, filepath.ToSlash(target))
if err != nil {
return err
}
} else {
header, err = tar.FileInfoHeader(fi, fi.Name())
if err != nil {
return err
}
}
relPath, err := filepath.Rel(srcDir, file)
if err != nil {
logrus.Debugf("Error walking folder to copy to container : %s", err)
return err
} else if relPath == "." {
return nil
}
header.Name = filepath.ToSlash(filepath.Join(basePath, relPath))
if err := tw.WriteHeader(header); err != nil {
logrus.Debugf("Error walking folder to copy to container : %s", err)
return err
}
if fi.Mode().IsRegular() {
f, err := os.Open(file)
if err != nil {
logrus.Debugf("Error walking folder to copy to container : %s", err)
return err
}
defer f.Close()
if _, err := io.Copy(tw, f); err != nil {
logrus.Debugf("Error walking folder to copy to container : %s", err)
return err
}
}
return nil
})
}
3 changes: 2 additions & 1 deletion environment/container/dockerengine.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/docker/docker/api/types/mount"
"github.com/docker/docker/client"
"github.com/docker/docker/pkg/stdcopy"
"github.com/konveyor/move2kube/common"
environmenttypes "github.com/konveyor/move2kube/types/environment"
"github.com/sirupsen/logrus"
"github.com/spf13/cast"
Expand Down Expand Up @@ -245,7 +246,7 @@ func (e *dockerEngine) CopyDirsFromContainer(containerID string, paths map[strin
// BuildImage creates a container
func (e *dockerEngine) BuildImage(image, context, dockerfile string) (err error) {
logrus.Infof("Building container image %s. This could take a few mins.", image)
reader := readDirAsTar(context, "")
reader := common.ReadDirAsTar(context, "", common.DefaultCompressionType)
resp, err := e.cli.ImageBuild(e.ctx, reader, types.ImageBuildOptions{
Dockerfile: dockerfile,
Tags: []string{image},
Expand Down
92 changes: 3 additions & 89 deletions environment/container/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,19 @@
package container

import (
"archive/tar"
"context"
"errors"
"fmt"
"io"
"os"
"path/filepath"

"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/ioutils"
"github.com/konveyor/move2kube/common"
"github.com/sirupsen/logrus"
)

func copyDirToContainer(ctx context.Context, cli *client.Client, containerID, src, dst string) error {
reader := readDirAsTar(src, dst)
reader := common.ReadDirAsTar(src, dst, common.DefaultCompressionType)
if reader == nil {
err := fmt.Errorf("error during create tar archive from '%s'", src)
logrus.Error(err)
Expand Down Expand Up @@ -78,90 +74,8 @@ func copyFromContainer(ctx context.Context, cli *client.Client, containerID stri
return archive.CopyTo(preArchive, copyInfo, destPath)
}

func readDirAsTar(srcDir, basePath string) io.ReadCloser {
errChan := make(chan error)
pr, pw := io.Pipe()
go func() {
err := writeDirToTar(pw, srcDir, basePath)
errChan <- err
}()
closed := false
return ioutils.NewReadCloserWrapper(pr, func() error {
if closed {
return errors.New("reader already closed")
}
perr := pr.Close()
if err := <-errChan; err != nil {
closed = true
if perr == nil {
return err
}
return fmt.Errorf("%s - %s", perr, err)
}
closed = true
return nil
})
}

func writeDirToTar(w *io.PipeWriter, srcDir, basePath string) error {
defer w.Close()
tw := tar.NewWriter(w)
defer tw.Close()
return filepath.Walk(srcDir, func(file string, fi os.FileInfo, err error) error {
if err != nil {
logrus.Debugf("Error walking folder to copy to container : %s", err)
return err
}
if fi.Mode()&os.ModeSocket != 0 {
return nil
}
var header *tar.Header
if fi.Mode()&os.ModeSymlink != 0 {
target, err := os.Readlink(file)
if err != nil {
return err
}
// Ensure that symlinks have Linux link names
header, err = tar.FileInfoHeader(fi, filepath.ToSlash(target))
if err != nil {
return err
}
} else {
header, err = tar.FileInfoHeader(fi, fi.Name())
if err != nil {
return err
}
}
relPath, err := filepath.Rel(srcDir, file)
if err != nil {
logrus.Debugf("Error walking folder to copy to container : %s", err)
return err
} else if relPath == "." {
return nil
}
header.Name = filepath.ToSlash(filepath.Join(basePath, relPath))
if err := tw.WriteHeader(header); err != nil {
logrus.Debugf("Error walking folder to copy to container : %s", err)
return err
}
if fi.Mode().IsRegular() {
f, err := os.Open(file)
if err != nil {
logrus.Debugf("Error walking folder to copy to container : %s", err)
return err
}
defer f.Close()
if _, err := io.Copy(tw, f); err != nil {
logrus.Debugf("Error walking folder to copy to container : %s", err)
return err
}
}
return nil
})
}

func copyDir(ctx context.Context, cli *client.Client, containerID, src, dst string) error {
reader := readDirAsTar(src, dst)
reader := common.ReadDirAsTar(src, dst, common.DefaultCompressionType)
if reader == nil {
err := fmt.Errorf("error during create tar archive from '%s'", src)
logrus.Error(err)
Expand Down
1 change: 1 addition & 0 deletions filesystem/templatecopy.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ func writeTemplateToFile(tpl string, config interface{}, writepath string,
"execTemplate": execTemplate(packageTemplate),
"encAesCbcPbkdf": common.EncryptAesCbcWithPbkdfWrapper,
"encRsaCert": common.EncryptRsaCertWrapper,
"archTarGZipStr": common.CreateTarArchiveGZipStringWrapper,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to expose just tar too.

}
template.Must(packageTemplate.Delims(openingDelimiter, closingDelimiter).Funcs(sprig.TxtFuncMap()).Funcs(methodMap).Parse(tpl))
if err != nil {
Expand Down