You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by as...@apache.org on 2021/09/09 09:52:41 UTC

[camel-k] 02/37: chore(s2i): Use tar.gz archive to preserve file permissions

This is an automated email from the ASF dual-hosted git repository.

astefanutti pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-k.git

commit 34956df3c99cb0d86f11483dc881596940fb1178
Author: Antonin Stefanutti <an...@stefanutti.fr>
AuthorDate: Thu Jul 29 11:36:41 2021 +0200

    chore(s2i): Use tar.gz archive to preserve file permissions
---
 pkg/builder/s2i.go  | 72 +++++++++++++++++++++++++++++++++++++++++++++++++----
 pkg/util/zip/zip.go | 64 -----------------------------------------------
 2 files changed, 67 insertions(+), 69 deletions(-)

diff --git a/pkg/builder/s2i.go b/pkg/builder/s2i.go
index 428901a..6ce99b6 100644
--- a/pkg/builder/s2i.go
+++ b/pkg/builder/s2i.go
@@ -18,10 +18,16 @@ limitations under the License.
 package builder
 
 import (
+	"archive/tar"
+	"compress/gzip"
 	"context"
+	"fmt"
+	"io"
 	"io/ioutil"
 	"os"
 	"path"
+	"path/filepath"
+	"strings"
 	"time"
 
 	"github.com/pkg/errors"
@@ -42,7 +48,6 @@ import (
 	"github.com/apache/camel-k/pkg/client"
 	"github.com/apache/camel-k/pkg/util/kubernetes/customclient"
 	"github.com/apache/camel-k/pkg/util/log"
-	"github.com/apache/camel-k/pkg/util/zip"
 )
 
 type s2iTask struct {
@@ -140,7 +145,7 @@ func (t *s2iTask) Do(ctx context.Context) v1.BuildStatus {
 	if err != nil {
 		return status.Failed(err)
 	}
-	archive := path.Join(tmpDir, "archive.zip")
+	archive := path.Join(tmpDir, "archive.tar.gz")
 	defer os.RemoveAll(tmpDir)
 
 	contextDir := t.task.ContextDir
@@ -156,14 +161,19 @@ func (t *s2iTask) Do(ctx context.Context) v1.BuildStatus {
 		contextDir = path.Join(pwd, ContextDir)
 	}
 
-	err = zip.Directory(contextDir, archive)
+	archiveFile, err := os.Create(archive)
 	if err != nil {
-		return status.Failed(errors.Wrap(err, "cannot zip context directory"))
+		return status.Failed(errors.Wrap(err, "cannot create tar archive"))
+	}
+
+	err = tarDir(contextDir, archiveFile)
+	if err != nil {
+		return status.Failed(errors.Wrap(err, "cannot tar context directory"))
 	}
 
 	resource, err := ioutil.ReadFile(archive)
 	if err != nil {
-		return status.Failed(errors.Wrap(err, "cannot fully read zip file "+archive))
+		return status.Failed(errors.Wrap(err, "cannot read tar file "+archive))
 	}
 
 	restClient, err := customclient.GetClientFor(t.c, "build.openshift.io", "v1")
@@ -275,3 +285,55 @@ func (t *s2iTask) cancelBuild(ctx context.Context, build *buildv1.Build) error {
 	*build = *target
 	return nil
 }
+
+func tarDir(src string, writers ...io.Writer) error {
+	// ensure the src actually exists before trying to tar it
+	if _, err := os.Stat(src); err != nil {
+		return fmt.Errorf("unable to tar files - %v", err.Error())
+	}
+
+	mw := io.MultiWriter(writers...)
+
+	gzw := gzip.NewWriter(mw)
+	defer gzw.Close()
+
+	tw := tar.NewWriter(gzw)
+	defer tw.Close()
+
+	return filepath.Walk(src, func(file string, fi os.FileInfo, err error) error {
+		if err != nil {
+			return err
+		}
+
+		if !fi.Mode().IsRegular() {
+			return nil
+		}
+
+		header, err := tar.FileInfoHeader(fi, fi.Name())
+		if err != nil {
+			return err
+		}
+
+		// update the name to correctly reflect the desired destination when un-taring
+		header.Name = strings.TrimPrefix(strings.Replace(file, src, "", -1), string(filepath.Separator))
+
+		if err := tw.WriteHeader(header); err != nil {
+			return err
+		}
+
+		f, err := os.Open(file)
+		if err != nil {
+			return err
+		}
+
+		if _, err := io.Copy(tw, f); err != nil {
+			return err
+		}
+
+		// manually close here after each file operation; deferring would cause each file close
+		// to wait until all operations have completed.
+		f.Close()
+
+		return nil
+	})
+}
diff --git a/pkg/util/zip/zip.go b/pkg/util/zip/zip.go
deleted file mode 100644
index a5f59de..0000000
--- a/pkg/util/zip/zip.go
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one or more
-contributor license agreements.  See the NOTICE file distributed with
-this work for additional information regarding copyright ownership.
-The ASF licenses this file to You 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"
-	"io"
-	"os"
-	"path/filepath"
-	"strings"
-)
-
-func Directory(pathToZip, destinationPath string) error {
-	destinationFile, err := os.Create(destinationPath)
-	if err != nil {
-		return err
-	}
-	myZip := zip.NewWriter(destinationFile)
-	err = filepath.Walk(pathToZip, func(filePath string, info os.FileInfo, err error) error {
-		if info.IsDir() {
-			return nil
-		}
-		if err != nil {
-			return err
-		}
-		relPath := strings.TrimPrefix(filePath, pathToZip)
-		zipFile, err := myZip.Create(relPath)
-		if err != nil {
-			return err
-		}
-		fsFile, err := os.Open(filePath)
-		if err != nil {
-			return err
-		}
-		_, err = io.Copy(zipFile, fsFile)
-		if err != nil {
-			return err
-		}
-		return nil
-	})
-	if err != nil {
-		return err
-	}
-	err = myZip.Close()
-	if err != nil {
-		return err
-	}
-	return nil
-}