blob: 3ffe17e42ec017a16782f83f6768f1e0e885ed68 [file] [log] [blame]
/*
* 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 utils
import (
"archive/zip"
"errors"
"fmt"
"github.com/apache/incubator-openwhisk-client-go/whisk"
"github.com/apache/incubator-openwhisk-wskdeploy/wski18n"
"github.com/hokaccha/go-prettyjson"
"io"
"io/ioutil"
"net/http"
"os"
"os/user"
"path"
"path/filepath"
"reflect"
"strings"
)
const (
DEFAULT_HTTP_TIMEOUT = 30
DEFAULT_PROJECT_PATH = "."
// name of manifest and deployment files
ManifestFileNameYaml = "manifest.yaml"
ManifestFileNameYml = "manifest.yml"
DeploymentFileNameYaml = "deployment.yaml"
DeploymentFileNameYml = "deployment.yml"
)
// ActionRecord is a container to keep track of
// a whisk action struct and a location filepath we use to
// map files and manifest declared actions
type ActionRecord struct {
Action *whisk.Action
Packagename string
Filepath string
}
type TriggerRecord struct {
Trigger *whisk.Trigger
Packagename string
}
type RuleRecord struct {
Rule *whisk.Rule
Packagename string
}
func GetHomeDirectory() string {
usr, err := user.Current()
if err != nil {
return ""
}
return usr.HomeDir
}
// Potentially complex structures(such as DeploymentProject, DeploymentPackage)
// could implement those interface which is convenient for put, get subtract in
// containers etc.
type Comparable interface {
HashCode() uint32
Equals() bool
}
func IsFeedAction(trigger *whisk.Trigger) (string, bool) {
for _, annotation := range trigger.Annotations {
if annotation.Key == "feed" {
return annotation.Value.(string), true
}
}
return "", false
}
func PrettyJSON(j interface{}) (string, error) {
formatter := prettyjson.NewFormatter()
bytes, err := formatter.Marshal(j)
if err != nil {
return "", err
}
return string(bytes), nil
}
var kindToJSON []string = []string{"", "boolean", "integer", "integer", "integer", "integer", "integer", "integer", "integer", "integer",
"integer", "integer", "integer", "number", "number", "number", "number", "array", "", "", "", "object", "", "", "string", "", ""}
// Gets JSON type name
func GetJSONType(j interface{}) string {
fmt.Print(reflect.TypeOf(j).Kind())
return kindToJSON[reflect.TypeOf(j).Kind()]
}
func NewZipWritter(src, des string) *ZipWritter {
zw := &ZipWritter{src: src, des: des}
return zw
}
type ZipWritter struct {
src string
des string
zipWritter *zip.Writer
}
func (zw *ZipWritter) zipFile(path string, f os.FileInfo, err error) error {
if err != nil {
return err
}
if !f.Mode().IsRegular() || f.Size() == 0 {
return nil
}
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
fileName := strings.TrimPrefix(path, zw.src+"/")
wr, err := zw.zipWritter.Create(fileName)
if err != nil {
return err
}
_, err = io.Copy(wr, file)
if err != nil {
return err
}
return nil
}
func (zw *ZipWritter) Zip() error {
// create zip file
zipFile, err := os.Create(zw.des)
if err != nil {
return err
}
defer zipFile.Close()
zw.zipWritter = zip.NewWriter(zipFile)
err = filepath.Walk(zw.src, zw.zipFile)
if err != nil {
return nil
}
err = zw.zipWritter.Close()
if err != nil {
return err
}
return nil
}
func zipKindError() error {
errMsg := wski18n.T("creating an action from a .zip artifact requires specifying the action kind explicitly")
return errors.New(errMsg)
}
func extensionError(extension string) error {
errMsg := wski18n.T(
"'{{.name}}' is not a supported action runtime",
map[string]interface{}{
"name": extension,
})
return errors.New(errMsg)
}
func javaEntryError() error {
errMsg := wski18n.T("Java actions require --main to specify the fully-qualified name of the main class")
return errors.New(errMsg)
}
func deleteKey(key string, keyValueArr whisk.KeyValueArr) whisk.KeyValueArr {
for i := 0; i < len(keyValueArr); i++ {
if keyValueArr[i].Key == key {
keyValueArr = append(keyValueArr[:i], keyValueArr[i+1:]...)
break
}
}
return keyValueArr
}
func addKeyValue(key string, value interface{}, keyValueArr whisk.KeyValueArr) whisk.KeyValueArr {
keyValue := whisk.KeyValue{
Key: key,
Value: value,
}
return append(keyValueArr, keyValue)
}
func GetManifestFilePath(projectPath string) string {
if _, err := os.Stat(path.Join(projectPath, ManifestFileNameYaml)); err == nil {
return path.Join(projectPath, ManifestFileNameYaml)
} else if _, err := os.Stat(path.Join(projectPath, ManifestFileNameYml)); err == nil {
return path.Join(projectPath, ManifestFileNameYml)
} else {
return ""
}
}
func GetDeploymentFilePath(projectPath string) string {
if _, err := os.Stat(path.Join(projectPath, DeploymentFileNameYaml)); err == nil {
return path.Join(projectPath, DeploymentFileNameYaml)
} else if _, err := os.Stat(path.Join(projectPath, DeploymentFileNameYml)); err == nil {
return path.Join(projectPath, DeploymentFileNameYml)
} else {
return ""
}
}
// agnostic util reader to fetch content from web or local path or potentially other places.
type ContentReader struct {
URLReader
LocalReader
}
type URLReader struct {
}
func (urlReader *URLReader) ReadUrl(url string) (content []byte, err error) {
resp, err := http.Get(url)
if err != nil {
return content, err
}
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return content, err
} else {
defer resp.Body.Close()
}
return b, nil
}
type LocalReader struct {
}
func (localReader *LocalReader) ReadLocal(path string) ([]byte, error) {
cont, err := ioutil.ReadFile(path)
return cont, err
}
func Read(url string) ([]byte, error) {
if strings.HasPrefix(url, "http") {
return new(ContentReader).URLReader.ReadUrl(url)
} else {
return new(ContentReader).LocalReader.ReadLocal(url)
}
}