func getYAMLDocumentName(data, pattern string) string {
	if len(data) <= 0 {
		return ""
	}
	r, _ := regexp.Compile(pattern)
	name := r.FindString(data)
	return name
}
get yaml file name from a file using a defined pattern
package file
import (
	"bufio"
	"bytes"
	"container/list"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	mesos "github.com/mesos/mesos-go/mesosproto"
	"github.com/pkg/errors"
	log "github.com/sirupsen/logrus"
	"gopkg.in/yaml.v2"
	"github.com/paypal/dce-go/config"
	"github.com/paypal/dce-go/types"
	"github.com/paypal/dce-go/utils/pod"
)
const (
	FILE_DELIMITER = ","
	YAML_SEPARATOR = "#---#"
	FILE_POSTFIX   = "-generated.yml"
	PATH_DELIMITER = "/"
	MAP_DELIMITER  = "="
	TraceFolder    = "composetrace"
)
type EditorFunc func(serviceName string, taskInfo *mesos.TaskInfo, executorId string, taskId string, containerDetails map[interface{}]interface{}, ports *list.Element) (map[interface{}]interface{}, *list.Element, error)
func GetFiles(taskInfo *mesos.TaskInfo) ([]string, error) {
	log.Println("====================Retrieve  compose file list from fileName label====================")
	filelist := pod.GetLabel("fileName", taskInfo)
	if filelist == "" {
		err := errors.New("missing label fileName")
		log.Errorln(err)
		return nil, err
	}
	var files []string
	for _, file := range strings.Split(filelist, FILE_DELIMITER) {
		files = append(files, strings.TrimSpace(file))
	}
	log.Println("Required file list : ", files)
	return files, nil
}
func GetPluginOrder(taskInfo *mesos.TaskInfo) ([]string, error) {
	log.Println("====================Get plugin order====================")
	pluginList := pod.GetLabel(types.PLUGIN_ORDER, taskInfo)
	if pluginList == "" {
		err := errors.New("Missing label pluginorder")
		return nil, err
	}
	var plugins []string
	for _, plugin := range strings.Split(pluginList, FILE_DELIMITER) {
		plugins = append(plugins, plugin)
	}
	pod.PluginOrder = plugins
	log.Println("Plugin Order : ", pod.PluginOrder)
	return plugins, nil
}
func GetYAML(taskInfo *mesos.TaskInfo) []string {
	log.Println("====================Get compose file from URI====================")
	var files []string
	if taskInfo == nil || taskInfo.Executor == nil || taskInfo.Executor.Command == nil {
		return files
	}
	uris := taskInfo.Executor.Command.GetUris()
	for _, uri := range uris {
		arr := strings.Split(uri.GetValue(), "/")
		name := arr[len(arr)-1]
		GetDirFilesRecv(name, &files)
	}
	log.Println("Compose file from URI: ", files)
	return files
}
func GetDirFilesRecv(dir string, files *[]string) {
	d, err := os.Stat(dir)
	if err != nil {
		log.Errorf("Error getting file info of %s:%v\n", dir, err)
		return
	}
	if !d.IsDir() && (strings.HasSuffix(dir, ".yml") || strings.HasSuffix(dir, ".yaml") || dir == "yaml") {
		*files = append(*files, dir)
		return
	}
	archiveExt := []string{".tar", ".tar.gz", ".tar.bz2", ".tar.xz", ".gz", ".tgz", ".tbz2", ".txz", ".zip"}
	fileext := filepath.Ext(dir)
	if index := IndexArray(archiveExt, fileext); index != -1 {
		dir = strings.TrimSuffix(dir, fileext)
	}
	dirs, err := ioutil.ReadDir(dir)
	if err != nil || dirs == nil || len(dirs) == 0 {
		log.Printf("%s is not a directory : %v", dir, err)
		return
	}
	for _, f := range dirs {
		if !f.IsDir() {
			if strings.Contains(f.Name(), ".yml") {
				*files = append(*files, dir+"/"+f.Name())
			}
		} else {
			GetDirFilesRecv(dir+"/"+f.Name(), files)
		}
	}
}
func SearchFile(root, file string) string {
	var filePath string
	filepath.Walk(root, func(path string, f os.FileInfo, err error) error {
		if f.Name() == file {
			filePath = path
			return nil
		}
		return nil
	})
	return filePath
}
func IsSubset(first, second []string) bool {
	log.Println("subset : ", first)
	log.Println("set : ", second)
	set := make(map[string]int)
	for _, value := range second {
		set[value] += 1
	}
	for _, value := range first {
		if count, found := set[value]; !found {
			return false
		} else if count < 1 {
			return false
		} else {
			set[value] = count - 1
		}
	}
	return true
}
func CheckFileExist(file string) bool {
	if _, err := os.Stat(file); os.IsNotExist(err) {
		log.Printf("File %s does not exist", file)
		return false
	}
	return true
}
func PrefixTaskId(taskId string, session string) string {
	if strings.HasPrefix(session, taskId) {
		return session
	}
	return taskId + "_" + session
}
func WriteToFile(file string, data []byte) (string, error) {
	if !strings.Contains(file, config.GetAppFolder()) {
		file = FolderPath(strings.Fields(file))[0]
	}
	log.Printf("Write to file : %s\n", file)
	f, err := os.Create(file)
	if err != nil {
		log.Errorf("Error creating file %v", err)
		return "", err
	}
	defer f.Close()
	_, err = f.Write(data)
	if err != nil {
		log.Errorln("Error writing into file : ", err.Error())
		return "", err
	}
	return f.Name(), nil
}
func DeleteFile(file string) error {
	if !strings.Contains(file, config.GetAppFolder()) {
		file = FolderPath(strings.Fields(file))[0]
	}
	return os.Remove(file)
}
func WriteChangeToFiles() error {
	filesMap := pod.GetServiceDetail()
	for file := range filesMap {
		content, err := yaml.Marshal(filesMap[file])
		if err != nil {
			log.Errorf("error occured while marshalling file from fileMap: %s", err)
		}
		_, err = WriteToFile(file, content)
		if err != nil {
			return err
		}
	}
	return nil
}
func DumpPluginModifiedComposeFiles(plugin, funcName string, pluginOrder int) {
	filesMap := pod.GetServiceDetail()
	for file := range filesMap {
		content, _ := yaml.Marshal(filesMap[file])
		fParts := strings.Split(file, PATH_DELIMITER)
		if len(fParts) < 2 {
			log.Printf("Skip dumping modified compose file by plugin %s, since file name is invalid %s", plugin, file)
			return
		}
		_, err := WriteToFile(fmt.Sprintf("%s/%s/%s-%s-%s-%d.yml", fParts[0], TraceFolder, fParts[1], plugin, funcName, pluginOrder), content)
		if err != nil {
			log.Printf("Failed dumping modified compose file by plugin %s", plugin)
		}
	}
}
func OverwriteFile(file string, data []byte) error {
	log.Printf("Over-write file: %s\n", file)
	os.Remove(file)
	f, err := os.Create(file)
	if err != nil {
		log.Errorf("Error creating file %s", err)
		return err
	}
	defer f.Close()
	_, err = f.Write(data)
	if err != nil {
		log.Errorf("Error writing into file : %s", err.Error())
		return err
	}
	return nil
}
func SplitYAML(file string) ([]string, error) {
	logger := log.WithFields(log.Fields{
		"File": file,
		"Func": "SplitYAML",
	})
	logger.Println("Start split downloaded compose file")
	var names []string
	if _, err := os.Stat(file); os.IsNotExist(err) {
		logger.Printf("File %s doesn't exist\n", file)
		return nil, err
	}
	dat, err := ioutil.ReadFile(file)
	if err != nil {
		return nil, err
	}
	dir := filepath.Dir(file)
	scanner := bufio.NewScanner(strings.NewReader(string(dat)))
	scanner.Split(SplitFunc)
	for scanner.Scan() {
		splitData := scanner.Text()
		logger.Printf("Split data : %s\n", splitData)
		name := strings.TrimLeft(getYAMLDocumentName(splitData, "#.*yml"), "#")
		if name == "" {
			logger.Println("No file name found from split data")
			continue
		}
		if dir != "." {
			name = filepath.Join(dir, name)
		}
		fileName, err := WriteToFile(name, []byte(splitData))
		if err != nil {
			logger.Errorf("Error writing files %s : %v\n", fileName, err)
			return nil, err
		}
		names = append(names, fileName)
	}
	if len(names) == 0 {
		d := FolderPath(strings.Fields(file))[0]
		CopyFile(file, d)
		names = append(names, d)
	}
	logger.Printf("After split file, get file names: %s\n", names)
	return FolderPath(names), nil
}
func SplitFunc(data []byte, atEOF bool) (advance int, token []byte, err error) {
	if atEOF && len(data) == 0 {
		return 0, nil, nil
	}
	sep := len([]byte(YAML_SEPARATOR))
	if i := bytes.Index(data, []byte(YAML_SEPARATOR)); i >= 0 {
		i += sep
		after := data[i:]
		if len(after) == 0 {
			if atEOF {
				return len(data), data[:len(data)-sep], nil
			}
			return 0, nil, nil
		}
		if j := bytes.IndexByte(after, '\n'); j >= 0 {
			return i + j + 1, data[0 : i-sep], nil
		}
		return 0, nil, nil
	}
	if atEOF {
		return len(data), data, nil
	}
	return 0, nil, nil
}