This is an automated email from the ASF dual-hosted git repository.
lukeroy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/openwhisk-runtime-go.git
The following commit(s) were added to refs/heads/master by this push:
new 916abe7 Add tar.gz support to the go Proxy (#191)
916abe7 is described below
commit 916abe7d9e8b491d01d5a4ad4f161d3a5a75d963
Author: Luke-Roy-IBM <[email protected]>
AuthorDate: Wed Apr 5 21:07:55 2023 +0200
Add tar.gz support to the go Proxy (#191)
* Add tar.gz support to the go Proxy
This new feature will allow for more versatile deployment packages and
greater flexibility in handling compressed files.
Giving an alternative to zip files.
this feature does not impact the current functionality of the go Proxy
* Add license header and fix eol
* Implement suggestions
* Remove debugging statement
* Remove unneeded fmt import
---
openwhisk/extractor.go | 4 ++
openwhisk/filetype.go | 10 +++++
openwhisk/tar.go | 105 +++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 119 insertions(+)
diff --git a/openwhisk/extractor.go b/openwhisk/extractor.go
index 097de0a..adf4cc7 100644
--- a/openwhisk/extractor.go
+++ b/openwhisk/extractor.go
@@ -64,6 +64,10 @@ func (ap *ActionProxy) ExtractAction(buf *[]byte, suffix
string) (string, error)
}
Debug("Extract Action, assuming a zip")
return file, Unzip(*buf, newDir)
+
+ } else if IsGz(*buf) {
+ Debug("Extract Action, assuming a tar.gz")
+ return file, UnTar(*buf, newDir)
}
return file, ioutil.WriteFile(file, *buf, 0755)
}
diff --git a/openwhisk/filetype.go b/openwhisk/filetype.go
index 20fe388..ed255d0 100644
--- a/openwhisk/filetype.go
+++ b/openwhisk/filetype.go
@@ -65,3 +65,13 @@ func IsZip(buf []byte) bool {
(buf[2] == 0x3 || buf[2] == 0x5 || buf[2] == 0x7) &&
(buf[3] == 0x4 || buf[3] == 0x6 || buf[3] == 0x8)
}
+
+// IsGz checks if the given file is a valid tar.gz file
+func IsGz(buf []byte) bool {
+ // Magic number: The first two bytes are fixed (0x1f and 0x8b), which
represent the magic number of a gzip file.
+ // Compression method: The third byte indicates the compression method
used. For gzip files, this is always (deflate).
+ return len(buf) > 3 &&
+ buf[0] == 0x1f &&
+ buf[1] == 0x8b &&
+ buf[2] == 0x08
+}
diff --git a/openwhisk/tar.go b/openwhisk/tar.go
new file mode 100644
index 0000000..cc683f7
--- /dev/null
+++ b/openwhisk/tar.go
@@ -0,0 +1,105 @@
+/*
+ * 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 openwhisk
+
+import (
+ "archive/tar"
+ "bytes"
+ "compress/gzip"
+ "io"
+ "os"
+ "path/filepath"
+)
+
+func openTar(src []byte) (*tar.Reader, error) {
+ // Create a new bytes.Reader from the input byte slice
+ reader := bytes.NewReader(src)
+
+ // Create a new gzip.Reader from the bytes.Reader
+ gzipReader, err := gzip.NewReader(reader)
+ if err != nil {
+ return nil, err
+ }
+ defer gzipReader.Close()
+
+ // Create a new tar.Reader from the gzip.Reader
+ tarReader := tar.NewReader(gzipReader)
+
+ return tarReader, nil
+}
+
+func UnTar(src []byte, dest string) error {
+ r, err := openTar(src)
+ if err != nil {
+ return err
+ }
+ Debug("open Tar")
+ os.MkdirAll(dest, 0755)
+ for {
+ header, err := r.Next()
+ switch {
+
+ // if no more files are found return
+ case err == io.EOF:
+ return nil
+
+ // return any other error
+ case err != nil:
+ return err
+
+ // if the header is nil, just skip it (not sure how this
happens)
+ case header == nil:
+ continue
+ }
+
+ // the target location where the dir/file should be created
+ target := filepath.Join(dest, header.Name)
+ // isLink := header.FileInfo().Mode()&os.ModeSymlink ==
os.ModeSymlink
+
+ // the following switch could also be done using fi.Mode(), not
sure if there
+ // a benefit of using one vs. the other.
+ // fi := header.FileInfo()
+
+ // check the file type
+ switch header.Typeflag {
+
+ // if its a dir and it doesn't exist create it
+ case tar.TypeDir:
+ if _, err := os.Stat(target); err != nil {
+ if err := os.MkdirAll(target, 0755); err != nil
{
+ return err
+ }
+ }
+
+ // if it's a file create it
+ case tar.TypeReg:
+ f, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR,
os.FileMode(header.Mode))
+ if err != nil {
+ return err
+ }
+
+ // copy over contents
+ if _, err := io.Copy(f, r); err != nil {
+ return err
+ }
+
+ // manually close here after each file operation;
defering would cause each file close
+ // to wait until all operations have completed.
+ f.Close()
+ }
+ }
+}