<commit_before>package utils

import (
	"fmt"

	buildv1alpha1 "github.com/knative/build/pkg/apis/build/v1alpha1"
	servingv1alpha1 "github.com/knative/serving/pkg/apis/serving/v1alpha1"
	runtimev1alpha1 "github.com/kyma-incubator/runtime/pkg/apis/runtime/v1alpha1"
	corev1 "k8s.io/api/core/v1"
)

// GetServiceSpec gets ServiceSpec for a function
func GetServiceSpec(imageName string, fn runtimev1alpha1.Function, rnInfo *RuntimeInfo) servingv1alpha1.ServiceSpec {
	defaultMode := int32(420)
	buildContainer := getBuildContainer(imageName, fn, rnInfo)
	volumes := []corev1.Volume{
		{
			Name: "dockerfile-vol",
			VolumeSource: corev1.VolumeSource{
				ConfigMap: &corev1.ConfigMapVolumeSource{
					DefaultMode: &defaultMode,
					LocalObjectReference: corev1.LocalObjectReference{
						Name: rnInfo.DockerFileConfigMapName(fn.Spec.Runtime),
					},
				},
			},
		},
		{
			Name: "func-vol",
			VolumeSource: corev1.VolumeSource{
				ConfigMap: &corev1.ConfigMapVolumeSource{
					DefaultMode: &defaultMode,
					LocalObjectReference: corev1.LocalObjectReference{
						Name: fn.Name,
					},
				},
			},
		},
	}

	// TODO: Make it constant for nodejs8/nodejs6
	envVarsForRevision := []corev1.EnvVar{
		{
			Name:  "FUNC_HANDLER",
			Value: "main",
		},
		{
			Name:  "MOD_NAME",
			Value: "handler",
		},
		{
			Name:  "FUNC_TIMEOUT",
			Value: "180",
		},
		{
			Name:  "FUNC_RUNTIME",
			Value: "nodejs8",
		},
		{
			Name:  "FUNC_MEMORY_LIMIT",
			Value: "128Mi",
		},
		{
			Name:  "FUNC_PORT",
			Value: "8080",
		},
		{
			Name:  "NODE_PATH",
			Value: "$(KUBELESS_INSTALL_VOLUME)/node_modules",
		},
	}

	return servingv1alpha1.ServiceSpec{
		RunLatest: &servingv1alpha1.RunLatestType{
			Configuration: servingv1alpha1.ConfigurationSpec{
				Build: &servingv1alpha1.RawExtension{
					BuildSpec: &buildv1alpha1.BuildSpec{
						ServiceAccountName: rnInfo.ServiceAccount,
						Steps: []corev1.Container{
							*buildContainer,
						},
						Volumes: volumes,
					},
				},
				RevisionTemplate: servingv1alpha1.RevisionTemplateSpec{
					Spec: servingv1alpha1.RevisionSpec{
						Container: corev1.Container{
							Image: imageName,
							Env:   envVarsForRevision,
						},
					},
				},
			},
		},
	}
}

func getBuildContainer(imageName string, fn runtimev1alpha1.Function, riUtil *RuntimeInfo) *corev1.Container {
	destination := fmt.Sprintf("--destination=%s", imageName)
	buildContainer := corev1.Container{
		Name:  "build-and-push",
		Image: "gcr.io/kaniko-project/executor",
		Args:  []string{"--dockerfile=/workspace/Dockerfile", destination},
		VolumeMounts: []corev1.VolumeMount{
			{
				Name:      "dockerfile-vol", //TODO: make it configurable
				MountPath: "/workspace",
			},
			{
				Name:      "func-vol",
				MountPath: "/src",
			},
		},
	}

	return &buildContainer
}
<commit_msg>add functionName as container name in service<commit_after>package utils

import (
	"fmt"

	buildv1alpha1 "github.com/knative/build/pkg/apis/build/v1alpha1"
	servingv1alpha1 "github.com/knative/serving/pkg/apis/serving/v1alpha1"
	runtimev1alpha1 "github.com/kyma-incubator/runtime/pkg/apis/runtime/v1alpha1"
	corev1 "k8s.io/api/core/v1"
)

// GetServiceSpec gets ServiceSpec for a function
func GetServiceSpec(imageName string, fn runtimev1alpha1.Function, rnInfo *RuntimeInfo) servingv1alpha1.ServiceSpec {
	defaultMode := int32(420)
	buildContainer := getBuildContainer(imageName, fn, rnInfo)
	volumes := []corev1.Volume{
		{
			Name: "dockerfile-vol",
			VolumeSource: corev1.VolumeSource{
				ConfigMap: &corev1.ConfigMapVolumeSource{
					DefaultMode: &defaultMode,
					LocalObjectReference: corev1.LocalObjectReference{
						Name: rnInfo.DockerFileConfigMapName(fn.Spec.Runtime),
					},
				},
			},
		},
		{
			Name: "func-vol",
			VolumeSource: corev1.VolumeSource{
				ConfigMap: &corev1.ConfigMapVolumeSource{
					DefaultMode: &defaultMode,
					LocalObjectReference: corev1.LocalObjectReference{
						Name: fn.Name,
					},
				},
			},
		},
	}

	// TODO: Make it constant for nodejs8/nodejs6
	envVarsForRevision := []corev1.EnvVar{
		{
			Name:  "FUNC_HANDLER",
			Value: "main",
		},
		{
			Name:  "MOD_NAME",
			Value: "handler",
		},
		{
			Name:  "FUNC_TIMEOUT",
			Value: "180",
		},
		{
			Name:  "FUNC_RUNTIME",
			Value: "nodejs8",
		},
		{
			Name:  "FUNC_MEMORY_LIMIT",
			Value: "128Mi",
		},
		{
			Name:  "FUNC_PORT",
			Value: "8080",
		},
		{
			Name:  "NODE_PATH",
			Value: "$(KUBELESS_INSTALL_VOLUME)/node_modules",
		},
	}

	return servingv1alpha1.ServiceSpec{
		RunLatest: &servingv1alpha1.RunLatestType{
			Configuration: servingv1alpha1.ConfigurationSpec{
				Build: &servingv1alpha1.RawExtension{
					BuildSpec: &buildv1alpha1.BuildSpec{
						ServiceAccountName: rnInfo.ServiceAccount,
						Steps: []corev1.Container{
							*buildContainer,
						},
						Volumes: volumes,
					},
				},
				RevisionTemplate: servingv1alpha1.RevisionTemplateSpec{
					Spec: servingv1alpha1.RevisionSpec{
						Container: corev1.Container{
							Image: imageName,
							Env:   envVarsForRevision,
							Name:  fn.Name,
						},
					},
				},
			},
		},
	}
}

func getBuildContainer(imageName string, fn runtimev1alpha1.Function, riUtil *RuntimeInfo) *corev1.Container {
	destination := fmt.Sprintf("--destination=%s", imageName)
	buildContainer := corev1.Container{
		Name:  "build-and-push",
		Image: "gcr.io/kaniko-project/executor",
		Args:  []string{"--dockerfile=/workspace/Dockerfile", destination},
		VolumeMounts: []corev1.VolumeMount{
			{
				Name:      "dockerfile-vol", //TODO: make it configurable
				MountPath: "/workspace",
			},
			{
				Name:      "func-vol",
				MountPath: "/src",
			},
		},
	}

	return &buildContainer
}
<|endoftext|>


<commit_before>package vfs

import (
	"encoding/json"
	"fmt"
	"os"
	"path"
	"strings"

	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/cozy/cozy-stack/pkg/couchdb"
	"github.com/cozy/cozy-stack/pkg/couchdb/mango"
)

type couchdbIndexer struct {
	db couchdb.Database
}

// NewCouchdbIndexer creates an Indexer instance based on couchdb to store
// files and directories metadata and index them.
func NewCouchdbIndexer(db couchdb.Database) Indexer {
	return &couchdbIndexer{
		db: db,
	}
}

func (c *couchdbIndexer) InitIndex() error {
	err := couchdb.CreateNamedDocWithDB(c.db, &DirDoc{
		DocName:  "",
		Type:     consts.DirType,
		DocID:    consts.RootDirID,
		Fullpath: "/",
		DirID:    "",
	})
	if err != nil {
		return err
	}

	err = couchdb.CreateNamedDocWithDB(c.db, &DirDoc{
		DocName:  path.Base(TrashDirName),
		Type:     consts.DirType,
		DocID:    consts.TrashDirID,
		Fullpath: TrashDirName,
		DirID:    consts.RootDirID,
	})
	if err != nil && !couchdb.IsConflictError(err) {
		return err
	}
	return nil
}

func (c *couchdbIndexer) DiskUsage() (int64, error) {
	var doc couchdb.ViewResponse
	err := couchdb.ExecView(c.db, consts.DiskUsageView, &couchdb.ViewRequest{
		Reduce: true,
	}, &doc)
	if err != nil {
		return 0, err
	}
	if len(doc.Rows) == 0 {
		return 0, nil
	}
	// Reduce of _count should give us a number value
	f64, ok := doc.Rows[0].Value.(float64)
	if !ok {
		return 0, ErrWrongCouchdbState
	}
	return int64(f64), nil
}

func (c *couchdbIndexer) CreateFileDoc(doc *FileDoc) error {
	return couchdb.CreateDoc(c.db, doc)
}

func (c *couchdbIndexer) CreateNamedFileDoc(doc *FileDoc) error {
	return couchdb.CreateNamedDoc(c.db, doc)
}

func (c *couchdbIndexer) UpdateFileDoc(olddoc, newdoc *FileDoc) error {
	newdoc.SetID(olddoc.ID())
	newdoc.SetRev(olddoc.Rev())
	return couchdb.UpdateDoc(c.db, newdoc)
}

func (c *couchdbIndexer) UpdateFileDocs(docs []*FileDoc) error {
	if len(docs) == 0 {
		return nil
	}
	couchdocs := make([]couchdb.Doc, len(docs))
	for i, doc := range docs {
		couchdocs[i] = doc
	}
	return couchdb.BulkUpdateDoc(c.db, couchdocs)
}

func (c *couchdbIndexer) DeleteFileDoc(doc *FileDoc) error {
	return couchdb.DeleteDoc(c.db, doc)
}

func (c *couchdbIndexer) CreateDirDoc(doc *DirDoc) error {
	return couchdb.CreateDoc(c.db, doc)
}

func (c *couchdbIndexer) CreateNamedDirDoc(doc *DirDoc) error {
	return couchdb.CreateNamedDoc(c.db, doc)
}

func (c *couchdbIndexer) UpdateDirDoc(olddoc, newdoc *DirDoc) error {
	newdoc.SetID(olddoc.ID())
	newdoc.SetRev(olddoc.Rev())
	if newdoc.Fullpath != olddoc.Fullpath {
		if err := c.moveDir(olddoc.Fullpath, newdoc.Fullpath); err != nil {
			return err
		}
	}
	return couchdb.UpdateDoc(c.db, newdoc)
}

func (c *couchdbIndexer) DeleteDirDoc(doc *DirDoc) error {
	return couchdb.DeleteDoc(c.db, doc)
}

// @TODO use couchdb bulk updates instead
func (c *couchdbIndexer) moveDir(oldpath, newpath string) error {
	var children []*DirDoc
	sel := mango.StartWith("path", oldpath+"/")
	req := &couchdb.FindRequest{
		UseIndex: "dir-by-path",
		Selector: sel,
	}
	err := couchdb.FindDocs(c.db, consts.Files, req, &children)
	if err != nil || len(children) == 0 {
		return err
	}

	errc := make(chan error)

	for _, child := range children {
		go func(child *DirDoc) {
			if !strings.HasPrefix(child.Fullpath, oldpath+"/") {
				errc <- fmt.Errorf("Child has wrong base directory")
			} else {
				child.Fullpath = path.Join(newpath, child.Fullpath[len(oldpath)+1:])
				errc <- couchdb.UpdateDoc(c.db, child)
			}
		}(child)
	}

	for range children {
		if e := <-errc; e != nil {
			err = e
		}
	}

	return err
}

func (c *couchdbIndexer) DirByID(fileID string) (*DirDoc, error) {
	doc := &DirDoc{}
	err := couchdb.GetDoc(c.db, consts.Files, fileID, doc)
	if couchdb.IsNotFoundError(err) {
		err = os.ErrNotExist
	}
	if err != nil {
		if fileID == consts.RootDirID {
			panic("Root directory is not in database")
		}
		if fileID == consts.TrashDirID {
			panic("Trash directory is not in database")
		}
		return nil, err
	}
	if doc.Type != consts.DirType {
		return nil, os.ErrNotExist
	}
	return doc, err
}

func (c *couchdbIndexer) DirByPath(name string) (*DirDoc, error) {
	if !path.IsAbs(name) {
		return nil, ErrNonAbsolutePath
	}
	var docs []*DirDoc
	sel := mango.Equal("path", path.Clean(name))
	req := &couchdb.FindRequest{
		UseIndex: "dir-by-path",
		Selector: sel,
		Limit:    1,
	}
	err := couchdb.FindDocs(c.db, consts.Files, req, &docs)
	if err != nil {
		return nil, err
	}
	if len(docs) == 0 {
		if name == "/" {
			panic("Root directory is not in database")
		}
		return nil, os.ErrNotExist
	}
	return docs[0], nil
}

func (c *couchdbIndexer) FileByID(fileID string) (*FileDoc, error) {
	doc := &FileDoc{}
	err := couchdb.GetDoc(c.db, consts.Files, fileID, doc)
	if couchdb.IsNotFoundError(err) {
		return nil, os.ErrNotExist
	}
	if err != nil {
		return nil, err
	}
	if doc.Type != consts.FileType {
		return nil, os.ErrNotExist
	}
	return doc, nil
}

func (c *couchdbIndexer) FileByPath(name string) (*FileDoc, error) {
	if !path.IsAbs(name) {
		return nil, ErrNonAbsolutePath
	}
	parent, err := c.DirByPath(path.Dir(name))
	if err != nil {
		return nil, err
	}

	// consts.FilesByParentView keys are [parentID, type, name]
	var res couchdb.ViewResponse
	err = couchdb.ExecView(c.db, consts.FilesByParentView, &couchdb.ViewRequest{
		Key:         []string{parent.DocID, consts.FileType, path.Base(name)},
		IncludeDocs: true,
	}, &res)
	if err != nil {
		return nil, err
	}

	if len(res.Rows) == 0 {
		return nil, os.ErrNotExist
	}

	var fdoc FileDoc
	err = json.Unmarshal(*res.Rows[0].Doc, &fdoc)
	return &fdoc, err
}

func (c *couchdbIndexer) FilePath(doc *FileDoc) (string, error) {
	var parentPath string
	if doc.DirID == consts.RootDirID {
		parentPath = "/"
	} else if doc.DirID == consts.TrashDirID {
		parentPath = TrashDirName
	} else {
		parent, err := c.DirByID(doc.DirID)
		if err != nil {
			return "", ErrParentDoesNotExist
		}
		parentPath = parent.Fullpath
	}
	return path.Join(parentPath, doc.DocName), nil
}

func (c *couchdbIndexer) DirOrFileByID(fileID string) (*DirDoc, *FileDoc, error) {
	dirOrFile := &DirOrFileDoc{}
	err := couchdb.GetDoc(c.db, consts.Files, fileID, dirOrFile)
	if err != nil {
		return nil, nil, err
	}
	dirDoc, fileDoc := dirOrFile.Refine()
	return dirDoc, fileDoc, nil
}

func (c *couchdbIndexer) DirOrFileByPath(name string) (*DirDoc, *FileDoc, error) {
	dirDoc, err := c.DirByPath(name)
	if err != nil && !os.IsNotExist(err) {
		return nil, nil, err
	}
	if err == nil {
		return dirDoc, nil, nil
	}
	fileDoc, err := c.FileByPath(name)
	if err != nil && !os.IsNotExist(err) {
		return nil, nil, err
	}
	if err == nil {
		return nil, fileDoc, nil
	}
	return nil, nil, err
}

func (c *couchdbIndexer) DirIterator(doc *DirDoc, opts *IteratorOptions) DirIterator {
	return NewIterator(c.db, doc, opts)
}

func (c *couchdbIndexer) DirBatch(doc *DirDoc, cursor couchdb.Cursor) ([]DirOrFileDoc, error) {
	// consts.FilesByParentView keys are [parentID, type, name]
	req := couchdb.ViewRequest{
		StartKey:    []string{doc.DocID, ""},
		EndKey:      []string{doc.DocID, couchdb.MaxString},
		IncludeDocs: true,
	}
	var res couchdb.ViewResponse
	cursor.ApplyTo(&req)
	err := couchdb.ExecView(c.db, consts.FilesByParentView, &req, &res)
	if err != nil {
		return nil, err
	}
	cursor.UpdateFrom(&res)

	docs := make([]DirOrFileDoc, len(res.Rows))
	for i, row := range res.Rows {
		var doc DirOrFileDoc
		err := json.Unmarshal(*row.Doc, &doc)
		if err != nil {
			return nil, err
		}
		docs[i] = doc
	}

	return docs, nil
}

func (c *couchdbIndexer) DirLength(doc *DirDoc) (int, error) {
	req := couchdb.ViewRequest{
		StartKey:   []string{doc.DocID, ""},
		EndKey:     []string{doc.DocID, couchdb.MaxString},
		Reduce:     true,
		GroupLevel: 1,
	}
	var res couchdb.ViewResponse
	err := couchdb.ExecView(c.db, consts.FilesByParentView, &req, &res)
	if err != nil {
		return 0, err
	}

	if len(res.Rows) == 0 {
		return 0, nil
	}

	// Reduce of _count should give us a number value
	f64, ok := res.Rows[0].Value.(float64)
	if !ok {
		return 0, ErrWrongCouchdbState
	}
	return int(f64), nil
}

func (c *couchdbIndexer) DirChildExists(dirID, name string) (bool, error) {
	var res couchdb.ViewResponse

	// consts.FilesByParentView keys are [parentID, type, name]
	err := couchdb.ExecView(c.db, consts.FilesByParentView, &couchdb.ViewRequest{
		Key:         []string{dirID, consts.FileType, name},
		IncludeDocs: false,
	}, &res)

	return len(res.Rows) > 0, err
}
<commit_msg>Check files and directories as child<commit_after>package vfs

import (
	"encoding/json"
	"fmt"
	"os"
	"path"
	"strings"

	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/cozy/cozy-stack/pkg/couchdb"
	"github.com/cozy/cozy-stack/pkg/couchdb/mango"
)

type couchdbIndexer struct {
	db couchdb.Database
}

// NewCouchdbIndexer creates an Indexer instance based on couchdb to store
// files and directories metadata and index them.
func NewCouchdbIndexer(db couchdb.Database) Indexer {
	return &couchdbIndexer{
		db: db,
	}
}

func (c *couchdbIndexer) InitIndex() error {
	err := couchdb.CreateNamedDocWithDB(c.db, &DirDoc{
		DocName:  "",
		Type:     consts.DirType,
		DocID:    consts.RootDirID,
		Fullpath: "/",
		DirID:    "",
	})
	if err != nil {
		return err
	}

	err = couchdb.CreateNamedDocWithDB(c.db, &DirDoc{
		DocName:  path.Base(TrashDirName),
		Type:     consts.DirType,
		DocID:    consts.TrashDirID,
		Fullpath: TrashDirName,
		DirID:    consts.RootDirID,
	})
	if err != nil && !couchdb.IsConflictError(err) {
		return err
	}
	return nil
}

func (c *couchdbIndexer) DiskUsage() (int64, error) {
	var doc couchdb.ViewResponse
	err := couchdb.ExecView(c.db, consts.DiskUsageView, &couchdb.ViewRequest{
		Reduce: true,
	}, &doc)
	if err != nil {
		return 0, err
	}
	if len(doc.Rows) == 0 {
		return 0, nil
	}
	// Reduce of _count should give us a number value
	f64, ok := doc.Rows[0].Value.(float64)
	if !ok {
		return 0, ErrWrongCouchdbState
	}
	return int64(f64), nil
}

func (c *couchdbIndexer) CreateFileDoc(doc *FileDoc) error {
	return couchdb.CreateDoc(c.db, doc)
}

func (c *couchdbIndexer) CreateNamedFileDoc(doc *FileDoc) error {
	return couchdb.CreateNamedDoc(c.db, doc)
}

func (c *couchdbIndexer) UpdateFileDoc(olddoc, newdoc *FileDoc) error {
	newdoc.SetID(olddoc.ID())
	newdoc.SetRev(olddoc.Rev())
	return couchdb.UpdateDoc(c.db, newdoc)
}

func (c *couchdbIndexer) UpdateFileDocs(docs []*FileDoc) error {
	if len(docs) == 0 {
		return nil
	}
	couchdocs := make([]couchdb.Doc, len(docs))
	for i, doc := range docs {
		couchdocs[i] = doc
	}
	return couchdb.BulkUpdateDoc(c.db, couchdocs)
}

func (c *couchdbIndexer) DeleteFileDoc(doc *FileDoc) error {
	return couchdb.DeleteDoc(c.db, doc)
}

func (c *couchdbIndexer) CreateDirDoc(doc *DirDoc) error {
	return couchdb.CreateDoc(c.db, doc)
}

func (c *couchdbIndexer) CreateNamedDirDoc(doc *DirDoc) error {
	return couchdb.CreateNamedDoc(c.db, doc)
}

func (c *couchdbIndexer) UpdateDirDoc(olddoc, newdoc *DirDoc) error {
	newdoc.SetID(olddoc.ID())
	newdoc.SetRev(olddoc.Rev())
	if newdoc.Fullpath != olddoc.Fullpath {
		if err := c.moveDir(olddoc.Fullpath, newdoc.Fullpath); err != nil {
			return err
		}
	}
	return couchdb.UpdateDoc(c.db, newdoc)
}

func (c *couchdbIndexer) DeleteDirDoc(doc *DirDoc) error {
	return couchdb.DeleteDoc(c.db, doc)
}

// @TODO use couchdb bulk updates instead
func (c *couchdbIndexer) moveDir(oldpath, newpath string) error {
	var children []*DirDoc
	sel := mango.StartWith("path", oldpath+"/")
	req := &couchdb.FindRequest{
		UseIndex: "dir-by-path",
		Selector: sel,
	}
	err := couchdb.FindDocs(c.db, consts.Files, req, &children)
	if err != nil || len(children) == 0 {
		return err
	}

	errc := make(chan error)

	for _, child := range children {
		go func(child *DirDoc) {
			if !strings.HasPrefix(child.Fullpath, oldpath+"/") {
				errc <- fmt.Errorf("Child has wrong base directory")
			} else {
				child.Fullpath = path.Join(newpath, child.Fullpath[len(oldpath)+1:])
				errc <- couchdb.UpdateDoc(c.db, child)
			}
		}(child)
	}

	for range children {
		if e := <-errc; e != nil {
			err = e
		}
	}

	return err
}

func (c *couchdbIndexer) DirByID(fileID string) (*DirDoc, error) {
	doc := &DirDoc{}
	err := couchdb.GetDoc(c.db, consts.Files, fileID, doc)
	if couchdb.IsNotFoundError(err) {
		err = os.ErrNotExist
	}
	if err != nil {
		if fileID == consts.RootDirID {
			panic("Root directory is not in database")
		}
		if fileID == consts.TrashDirID {
			panic("Trash directory is not in database")
		}
		return nil, err
	}
	if doc.Type != consts.DirType {
		return nil, os.ErrNotExist
	}
	return doc, err
}

func (c *couchdbIndexer) DirByPath(name string) (*DirDoc, error) {
	if !path.IsAbs(name) {
		return nil, ErrNonAbsolutePath
	}
	var docs []*DirDoc
	sel := mango.Equal("path", path.Clean(name))
	req := &couchdb.FindRequest{
		UseIndex: "dir-by-path",
		Selector: sel,
		Limit:    1,
	}
	err := couchdb.FindDocs(c.db, consts.Files, req, &docs)
	if err != nil {
		return nil, err
	}
	if len(docs) == 0 {
		if name == "/" {
			panic("Root directory is not in database")
		}
		return nil, os.ErrNotExist
	}
	return docs[0], nil
}

func (c *couchdbIndexer) FileByID(fileID string) (*FileDoc, error) {
	doc := &FileDoc{}
	err := couchdb.GetDoc(c.db, consts.Files, fileID, doc)
	if couchdb.IsNotFoundError(err) {
		return nil, os.ErrNotExist
	}
	if err != nil {
		return nil, err
	}
	if doc.Type != consts.FileType {
		return nil, os.ErrNotExist
	}
	return doc, nil
}

func (c *couchdbIndexer) FileByPath(name string) (*FileDoc, error) {
	if !path.IsAbs(name) {
		return nil, ErrNonAbsolutePath
	}
	parent, err := c.DirByPath(path.Dir(name))
	if err != nil {
		return nil, err
	}

	// consts.FilesByParentView keys are [parentID, type, name]
	var res couchdb.ViewResponse
	err = couchdb.ExecView(c.db, consts.FilesByParentView, &couchdb.ViewRequest{
		Key:         []string{parent.DocID, consts.FileType, path.Base(name)},
		IncludeDocs: true,
	}, &res)
	if err != nil {
		return nil, err
	}

	if len(res.Rows) == 0 {
		return nil, os.ErrNotExist
	}

	var fdoc FileDoc
	err = json.Unmarshal(*res.Rows[0].Doc, &fdoc)
	return &fdoc, err
}

func (c *couchdbIndexer) FilePath(doc *FileDoc) (string, error) {
	var parentPath string
	if doc.DirID == consts.RootDirID {
		parentPath = "/"
	} else if doc.DirID == consts.TrashDirID {
		parentPath = TrashDirName
	} else {
		parent, err := c.DirByID(doc.DirID)
		if err != nil {
			return "", ErrParentDoesNotExist
		}
		parentPath = parent.Fullpath
	}
	return path.Join(parentPath, doc.DocName), nil
}

func (c *couchdbIndexer) DirOrFileByID(fileID string) (*DirDoc, *FileDoc, error) {
	dirOrFile := &DirOrFileDoc{}
	err := couchdb.GetDoc(c.db, consts.Files, fileID, dirOrFile)
	if err != nil {
		return nil, nil, err
	}
	dirDoc, fileDoc := dirOrFile.Refine()
	return dirDoc, fileDoc, nil
}

func (c *couchdbIndexer) DirOrFileByPath(name string) (*DirDoc, *FileDoc, error) {
	dirDoc, err := c.DirByPath(name)
	if err != nil && !os.IsNotExist(err) {
		return nil, nil, err
	}
	if err == nil {
		return dirDoc, nil, nil
	}
	fileDoc, err := c.FileByPath(name)
	if err != nil && !os.IsNotExist(err) {
		return nil, nil, err
	}
	if err == nil {
		return nil, fileDoc, nil
	}
	return nil, nil, err
}

func (c *couchdbIndexer) DirIterator(doc *DirDoc, opts *IteratorOptions) DirIterator {
	return NewIterator(c.db, doc, opts)
}

func (c *couchdbIndexer) DirBatch(doc *DirDoc, cursor couchdb.Cursor) ([]DirOrFileDoc, error) {
	// consts.FilesByParentView keys are [parentID, type, name]
	req := couchdb.ViewRequest{
		StartKey:    []string{doc.DocID, ""},
		EndKey:      []string{doc.DocID, couchdb.MaxString},
		IncludeDocs: true,
	}
	var res couchdb.ViewResponse
	cursor.ApplyTo(&req)
	err := couchdb.ExecView(c.db, consts.FilesByParentView, &req, &res)
	if err != nil {
		return nil, err
	}
	cursor.UpdateFrom(&res)

	docs := make([]DirOrFileDoc, len(res.Rows))
	for i, row := range res.Rows {
		var doc DirOrFileDoc
		err := json.Unmarshal(*row.Doc, &doc)
		if err != nil {
			return nil, err
		}
		docs[i] = doc
	}

	return docs, nil
}

func (c *couchdbIndexer) DirLength(doc *DirDoc) (int, error) {
	req := couchdb.ViewRequest{
		StartKey:   []string{doc.DocID, ""},
		EndKey:     []string{doc.DocID, couchdb.MaxString},
		Reduce:     true,
		GroupLevel: 1,
	}
	var res couchdb.ViewResponse
	err := couchdb.ExecView(c.db, consts.FilesByParentView, &req, &res)
	if err != nil {
		return 0, err
	}

	if len(res.Rows) == 0 {
		return 0, nil
	}

	// Reduce of _count should give us a number value
	f64, ok := res.Rows[0].Value.(float64)
	if !ok {
		return 0, ErrWrongCouchdbState
	}
	return int(f64), nil
}

func (c *couchdbIndexer) DirChildExists(dirID, name string) (bool, error) {
	var res couchdb.ViewResponse

	// consts.FilesByParentView keys are [parentID, type, name]
	err := couchdb.ExecView(c.db, consts.FilesByParentView, &couchdb.ViewRequest{
		Keys: []interface{}{
			[]string{dirID, consts.FileType, name},
			[]string{dirID, consts.DirType, name},
		},
		IncludeDocs: false,
	}, &res)

	return len(res.Rows) > 0, err
}
<|endoftext|>


<commit_before>package websocket

import (
	"context"
	"crypto/tls"
	"fmt"
	"net/http"
	"sync"
	"time"

	"github.com/gorilla/websocket"
	"github.com/sirupsen/logrus"
)

const (
	// Time allowed to write a message to the peer.
	writeWait = 10 * time.Second

	// Time allowed to read the next pong message from the peer.
	pongWait = 10 * time.Second

	// Send pings to peer with this period. Must be less than pongWait.
	pingPeriod = (pongWait * 9) / 10

	reconnectWait = 2 * time.Second
)

// Websocket implements a websocket client
type Websocket interface {
	OnConnect(cb func())
	ConnectContext(ctx context.Context, addr string, headers http.Header) error
	ConnectWithRetry(parentCtx context.Context, addr string, headers http.Header)
	Wait()
	Read() <-chan []byte
	// WriteJSON writes interface{} encoded as JSON to our connection
	WriteJSON(v interface{}) error
	SetTLSConfig(c *tls.Config)
}

type websocketClient struct {
	conn            *websocket.Conn
	tlsClientConfig *tls.Config
	write           chan func()
	read            chan []byte
	wg              *sync.WaitGroup
	disconnected    chan error
	connected       chan struct{}
	onConnect       func()
}

// New creates a new Websocket
func New() Websocket {
	return &websocketClient{
		write:        make(chan func()),
		read:         make(chan []byte, 100),
		wg:           &sync.WaitGroup{},
		disconnected: make(chan error),
		connected:    make(chan struct{}),
	}
}

func (ws *websocketClient) SetTLSConfig(c *tls.Config) {
	ws.tlsClientConfig = c
}

func (ws *websocketClient) OnConnect(cb func()) {
	ws.onConnect = cb
}

func (ws *websocketClient) ConnectContext(ctx context.Context, addr string, headers http.Header) error {
	var err error
	var c *websocket.Conn
	logrus.Info("websocket: connecting to ", addr)
	if ws.tlsClientConfig != nil {
		dialer := &websocket.Dialer{
			Proxy:            http.ProxyFromEnvironment,
			HandshakeTimeout: 45 * time.Second,
			TLSClientConfig:  ws.tlsClientConfig,
		}
		c, _, err = dialer.DialContext(ctx, addr, headers)
	} else {
		c, _, err = websocket.DefaultDialer.DialContext(ctx, addr, headers)
	}
	if err != nil {
		ws.wasDisconnected(err)
		return err
	}
	logrus.Infof("websocket: connected to %s", addr)
	ws.wasConnected()
	ws.conn = c
	ws.readPump()
	ws.writePump(ctx) <- struct{}{}

	if ws.onConnect != nil {
		ws.onConnect()
	}
	return nil
}

// ConnectWithRetry tries to connect and blocks until connected.
// if disconnected because an error tries to reconnect again every 5th second
func (ws *websocketClient) ConnectWithRetry(parentCtx context.Context, addr string, headers http.Header) {

	ctx, cancel := context.WithCancel(parentCtx)
	ws.wg.Add(1)
	go func() {
		defer ws.wg.Done()
		for {
			select {
			case <-parentCtx.Done():
				logrus.Info("websocket: stopping reconnect because err: ", parentCtx.Err())
				return
			case err := <-ws.disconnected:
				cancel() // Stop any write/read pumps so we dont get duplicate write panic
				logrus.Error("websocket: disconnected")
				if websocket.IsCloseError(err, websocket.CloseNormalClosure) {
					logrus.Info("websocket: Skipping reconnect due to CloseNormalClosure")
					return
				}
				logrus.Info("websocket: Reconnect because error: ", err)
				go func() {
					time.Sleep(5 * time.Second)
					ctx, cancel = context.WithCancel(parentCtx)
					err := ws.ConnectContext(ctx, addr, headers)
					if err != nil {
						logrus.Error("websocket: Reconnect failed with error: ", err)
					}
				}()
			}
		}
	}()
	go ws.ConnectContext(ctx, addr, headers)
	<-ws.connected
	return
}

func (ws *websocketClient) Wait() {
	ws.wg.Wait()
}

func (ws *websocketClient) Read() <-chan []byte {
	return ws.read
}

// WriteJSON writes interface{} encoded as JSON to our connection
func (ws *websocketClient) WriteJSON(v interface{}) error {
	errCh := make(chan error, 1)
	select {
	case ws.write <- func() {
		err := ws.conn.WriteJSON(v)
		errCh <- err
	}:
	default:
		errCh <- fmt.Errorf("websocket: no one listening on write channel")
	}
	return <-errCh
}

func (ws *websocketClient) readPump() {
	go func() {
		ws.wg.Add(1)
		defer ws.wg.Done()
		ws.conn.SetReadDeadline(time.Now().Add(pongWait))
		ws.conn.SetPongHandler(func(string) error { ws.conn.SetReadDeadline(time.Now().Add(pongWait)); return nil })
		for {
			_, message, err := ws.conn.ReadMessage()
			if err != nil {
				logrus.Error("websocket: readPump error:", err)
				ws.wasDisconnected(err)
				return
			}
			logrus.Debugf("websocket: readPump got msg: %s", message)
			select {
			case ws.read <- message:
			default:
			}
		}
	}()
}

func (ws *websocketClient) writePump(ctx context.Context) chan struct{} {
	ready := make(chan struct{})
	go func() {
		ws.wg.Add(1)
		defer ws.wg.Done()
		ticker := time.NewTicker(pingPeriod)
		defer ticker.Stop()
		for {
			select {
			case t := <-ws.write:
				t()
			case <-ctx.Done():
				logrus.Error("websocket: Stopping writePump because err: ", ctx.Err())
				err := ws.conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
				if err != nil {
					logrus.Error("websocket: write close:", err)
					return
				}
				return
			case <-ticker.C:
				if err := ws.conn.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(writeWait)); err != nil {
					logrus.Error("websocket: ping:", err)
				}
			case <-ready:
			}
		}
	}()
	return ready
}

func (ws *websocketClient) wasDisconnected(err error) {
	select {
	case ws.disconnected <- err:
	default:
	}
}

func (ws *websocketClient) wasConnected() {
	select {
	case ws.connected <- struct{}{}:
	default:
	}
}
<commit_msg>Fixed careless mistakes<commit_after>package websocket

import (
	"context"
	"crypto/tls"
	"fmt"
	"net/http"
	"sync"
	"time"

	"github.com/gorilla/websocket"
	"github.com/sirupsen/logrus"
)

const (
	// Time allowed to write a message to the peer.
	writeWait = 10 * time.Second

	// Time allowed to read the next pong message from the peer.
	pongWait = 10 * time.Second

	// Send pings to peer with this period. Must be less than pongWait.
	pingPeriod = (pongWait * 9) / 10

	reconnectWait = 2 * time.Second
)

// Websocket implements a websocket client
type Websocket interface {
	OnConnect(cb func())
	ConnectContext(ctx context.Context, addr string, headers http.Header) error
	ConnectWithRetry(parentCtx context.Context, addr string, headers http.Header)
	Wait()
	Read() <-chan []byte
	// WriteJSON writes interface{} encoded as JSON to our connection
	WriteJSON(v interface{}) error
	SetTLSConfig(c *tls.Config)
}

type websocketClient struct {
	conn            *websocket.Conn
	tlsClientConfig *tls.Config
	write           chan func()
	read            chan []byte
	wg              *sync.WaitGroup
	disconnected    chan error
	connected       chan struct{}
	onConnect       func()
}

// New creates a new Websocket
func New() Websocket {
	return &websocketClient{
		write:        make(chan func()),
		read:         make(chan []byte, 100),
		wg:           &sync.WaitGroup{},
		disconnected: make(chan error),
		connected:    make(chan struct{}),
	}
}

func (ws *websocketClient) SetTLSConfig(c *tls.Config) {
	ws.tlsClientConfig = c
}

func (ws *websocketClient) OnConnect(cb func()) {
	ws.onConnect = cb
}

func (ws *websocketClient) ConnectContext(ctx context.Context, addr string, headers http.Header) error {
	var err error
	var c *websocket.Conn
	logrus.Info("websocket: connecting to ", addr)
	if ws.tlsClientConfig != nil {
		dialer := &websocket.Dialer{
			Proxy:            http.ProxyFromEnvironment,
			HandshakeTimeout: 45 * time.Second,
			TLSClientConfig:  ws.tlsClientConfig,
		}
		c, _, err = dialer.DialContext(ctx, addr, headers)
	} else {
		c, _, err = websocket.DefaultDialer.DialContext(ctx, addr, headers)
	}
	if err != nil {
		ws.wasDisconnected(err)
		return err
	}
	logrus.Infof("websocket: connected to %s", addr)
	ws.wasConnected()
	ws.conn = c
	ws.readPump()
	ws.writePump(ctx) <- struct{}{}

	if ws.onConnect != nil {
		ws.onConnect()
	}
	return nil
}

// ConnectWithRetry tries to connect and blocks until connected.
// if disconnected because an error tries to reconnect again every 5th second
func (ws *websocketClient) ConnectWithRetry(parentCtx context.Context, addr string, headers http.Header) {

	ctx, cancel := context.WithCancel(parentCtx)
	ws.wg.Add(1)
	go func() {
		defer ws.wg.Done()
		for {
			select {
			case <-parentCtx.Done():
				logrus.Info("websocket: stopping reconnect because err: ", parentCtx.Err())
				return
			case err := <-ws.disconnected:
				cancel() // Stop any write/read pumps so we dont get duplicate write panic
				logrus.Error("websocket: disconnected")
				if websocket.IsCloseError(err, websocket.CloseNormalClosure) {
					logrus.Info("websocket: Skipping reconnect due to CloseNormalClosure")
					return
				}
				logrus.Info("websocket: Reconnect because error: ", err)
				go func() {
					time.Sleep(5 * time.Second)
					ctx, cancel = context.WithCancel(parentCtx)
					err := ws.ConnectContext(ctx, addr, headers)
					if err != nil {
						logrus.Error("websocket: Reconnect failed with error: ", err)
					}
				}()
			}
		}
	}()
	go ws.ConnectContext(ctx, addr, headers)
	<-ws.connected
	return
}

func (ws *websocketClient) Wait() {
	ws.wg.Wait()
}

func (ws *websocketClient) Read() <-chan []byte {
	return ws.read
}

// WriteJSON writes interface{} encoded as JSON to our connection
func (ws *websocketClient) WriteJSON(v interface{}) error {
	errCh := make(chan error, 1)
	select {
	case ws.write <- func() {
		err := ws.conn.WriteJSON(v)
		errCh <- err
	}:
	default:
		errCh <- fmt.Errorf("websocket: no one listening on write channel")
	}
	return <-errCh
}

func (ws *websocketClient) readPump() {
	ws.wg.Add(1)
	go func() {
		defer ws.wg.Done()
		ws.conn.SetReadDeadline(time.Now().Add(pongWait))
		ws.conn.SetPongHandler(func(string) error { ws.conn.SetReadDeadline(time.Now().Add(pongWait)); return nil })
		for {
			_, message, err := ws.conn.ReadMessage()
			if err != nil {
				logrus.Error("websocket: readPump error:", err)
				ws.wasDisconnected(err)
				return
			}
			logrus.Debugf("websocket: readPump got msg: %s", message)
			select {
			case ws.read <- message:
			default:
			}
		}
	}()
}

func (ws *websocketClient) writePump(ctx context.Context) chan struct{} {
	ready := make(chan struct{})
	ws.wg.Add(1)
	go func() {
		defer ws.wg.Done()
		ticker := time.NewTicker(pingPeriod)
		defer ticker.Stop()
		for {
			select {
			case t := <-ws.write:
				t()
			case <-ctx.Done():
				logrus.Error("websocket: Stopping writePump because err: ", ctx.Err())
				err := ws.conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
				if err != nil {
					logrus.Error("websocket: write close:", err)
					return
				}
				return
			case <-ticker.C:
				if err := ws.conn.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(writeWait)); err != nil {
					logrus.Error("websocket: ping:", err)
				}
			case <-ready:
			}
		}
	}()
	return ready
}

func (ws *websocketClient) wasDisconnected(err error) {
	select {
	case ws.disconnected <- err:
	default:
	}
}

func (ws *websocketClient) wasConnected() {
	select {
	case ws.connected <- struct{}{}:
	default:
	}
}
<|endoftext|>


<commit_before><commit_msg>Added sorting functions, by name or by level+name.<commit_after><|endoftext|>


<commit_before>package textmate

import (
	"code.google.com/p/log4go"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/quarnster/parser"
	"io/ioutil"
	"lime/3rdparty/libs/rubex"
	"lime/backend/loaders"
	"strconv"
	"strings"
)

const maxiter = 10000

type (
	Regex struct {
		re        *rubex.Regexp
		lastIndex int
		lastFound int
		lastData  string
	}

	Language struct {
		UnpatchedLanguage
	}

	LanguageProvider map[string]*Language

	UnpatchedLanguage struct {
		FileTypes      []string
		FirstLineMatch string
		RootPattern    RootPattern `json:"patterns"`
		Repository     map[string]*Pattern
		ScopeName      string
	}

	Named struct {
		Name string
	}

	Captures map[string]Named

	MatchObject []int

	Pattern struct {
		Named
		Include        string
		Match          Regex
		Captures       Captures
		Begin          Regex
		BeginCaptures  Captures
		End            Regex
		EndCaptures    Captures
		Patterns       []*Pattern
		owner          *Language // needed for include directives
		cachedData     string
		cachedPat      *Pattern
		cachedPatterns []*Pattern
		cachedMatch    MatchObject
		hits           int
		misses         int
	}
	RootPattern struct {
		Pattern
	}

	LanguageParser struct {
		Language *Language
		root     parser.Node
	}
)

var (
	Provider = make(LanguageProvider)
	failed   = make(map[string]bool)
)

func (t LanguageProvider) GetLanguage(id string) (*Language, error) {
	if v, ok := t[id]; !ok {
		return nil, errors.New("Can't handle id " + id)
	} else {
		return v, nil
	}
}

func (t LanguageProvider) Load(fn string) error {
	if d, err := ioutil.ReadFile(fn); err != nil {
		return fmt.Errorf("Couldn't load file %s: %s", fn, err)
	} else {
		var l Language
		if err := loaders.LoadPlist(d, &l); err != nil {
			return err
		} else {
			t[l.ScopeName] = &l
		}
	}
	return nil
}

func (p Pattern) String() (ret string) {
	ret = fmt.Sprintf(`---------------------------------------
Name:    %s
Match:   %s
Begin:   %s
End:     %s
Include: %s
`, p.Name, p.Match, p.Begin, p.End, p.Include)
	ret += fmt.Sprintf("<Sub-Patterns>\n")
	for i := range p.Patterns {
		inner := fmt.Sprintf("%s", p.Patterns[i])
		ret += fmt.Sprintf("\t%s\n", strings.Replace(strings.Replace(inner, "\t", "\t\t", -1), "\n", "\n\t", -1))
	}
	ret += fmt.Sprintf("</Sub-Patterns>\n---------------------------------------")
	return
}

func (r Regex) String() string {
	if r.re == nil {
		return "nil"
	}
	return fmt.Sprintf("%s   // %d, %d", r.re.String(), r.lastIndex, r.lastFound)
}

func (r *RootPattern) String() (ret string) {
	for i := range r.Patterns {
		ret += fmt.Sprintf("\t%s\n", r.Patterns[i])
	}
	return
}

func (s *Language) String() string {
	return fmt.Sprintf("%s\n%s", s.ScopeName, s.RootPattern)
}

func (p *Pattern) setOwner(l *Language) {
	p.owner = l
	for i := range p.Patterns {
		p.Patterns[i].setOwner(l)
	}
}

func (l *Language) UnmarshalJSON(data []byte) error {
	if err := json.Unmarshal(data, &l.UnpatchedLanguage); err != nil {
		return err
	}
	l.RootPattern.setOwner(l)
	for k := range l.Repository {
		l.Repository[k].setOwner(l)
	}
	return nil
}

func (r *RootPattern) UnmarshalJSON(data []byte) error {
	return json.Unmarshal(data, &r.Patterns)
}

func (r *Regex) UnmarshalJSON(data []byte) error {
	str := string(data[1 : len(data)-1])
	str = strings.Replace(str, "\\\\", "\\", -1)
	str = strings.Replace(str, "\\n", "\n", -1)
	str = strings.Replace(str, "\\t", "\t", -1)
	if re, err := rubex.Compile(str); err != nil {
		log4go.Warn("Couldn't compile language pattern %s: %s", str, err)
	} else {
		r.re = re
	}
	return nil
}

func (m MatchObject) fix(add int) {
	for i := range m {
		if m[i] != -1 {
			m[i] += add
		}
	}
}

func (r *Regex) Find(data string, pos int) MatchObject {
	if r.lastData != data || r.lastIndex > pos {
		r.lastData = data
		r.lastFound = 0
	}
	r.lastIndex = pos
	for r.lastFound < len(data) {
		ret := r.re.FindStringSubmatchIndex(data[r.lastFound:])
		if ret == nil {
			break
		} else if (ret[0] + r.lastFound) < pos {
			if ret[0] == 0 {
				r.lastFound++
			} else {
				r.lastFound += ret[0]
			}
			continue
		}
		mo := MatchObject(ret)
		mo.fix(r.lastFound)
		return mo
	}
	return nil
}

func (p *Pattern) FirstMatch(data string, pos int) (pat *Pattern, ret MatchObject) {
	startIdx := -1
	for i := 0; i < len(p.cachedPatterns); {
		ip, im := p.cachedPatterns[i].Cache(data, pos)
		if im != nil && im[0] != im[1] {
			if startIdx < 0 || startIdx > im[0] {
				startIdx, pat, ret = im[0], ip, im
				// This match is right at the start, we're not going to find a better pattern than this,
				// so stop the search
				if im[0] == pos {
					break
				}
			}
			i++
		} else {
			// If it wasn't found now, it'll never be found, so the pattern can be popped from the cache
			copy(p.cachedPatterns[i:], p.cachedPatterns[i+1:])
			p.cachedPatterns = p.cachedPatterns[:len(p.cachedPatterns)-1]
		}
	}
	return
}

func (p *Pattern) Cache(data string, pos int) (pat *Pattern, ret MatchObject) {
	if p.cachedData == data {
		if p.cachedMatch == nil {
			return nil, nil
		}
		if p.cachedMatch[0] >= pos {
			p.hits++
			return p.cachedPat, p.cachedMatch
		}
	} else {
		p.cachedPatterns = nil
	}
	if p.cachedPatterns == nil {
		p.cachedPatterns = make([]*Pattern, len(p.Patterns))
		copy(p.cachedPatterns, p.Patterns)
	}
	p.misses++

	if p.Match.re != nil {
		pat, ret = p, p.Match.Find(data, pos)
	} else if p.Begin.re != nil {
		pat, ret = p, p.Begin.Find(data, pos)
	} else if p.Include != "" {
		if z := p.Include[0]; z == '#' {
			key := p.Include[1:]
			if p2, ok := p.owner.Repository[key]; ok {
				pat, ret = p2.Cache(data, pos)
			} else {
				log4go.Warn("Not found in repository: %s", p.Include)
			}
		} else if z == '$' {
			// TODO(q): Implement tmLanguage $ include directives
			log4go.Warn("Unhandled include directive: %s", p.Include)
		} else if l, err := Provider.GetLanguage(p.Include); err != nil {
			if !failed[p.Include] {
				log4go.Warn("Include directive %s failed: %s", p.Include, err)
			}
			failed[p.Include] = true
		} else {
			return l.RootPattern.Cache(data, pos)
		}
	} else {
		pat, ret = p.FirstMatch(data, pos)
	}
	p.cachedData = data
	p.cachedMatch = ret
	p.cachedPat = pat

	return
}

func (p *Pattern) CreateCaptureNodes(data string, pos int, d parser.DataSource, mo MatchObject, parent *parser.Node, cap Captures) {
	ranges := make([]parser.Range, len(mo)/2)
	parentIndex := make([]int, len(ranges))
	parents := make([]*parser.Node, len(parentIndex))
	for i := range ranges {
		ranges[i] = parser.Range{mo[i*2+0], mo[i*2+1]}
		if i < 2 {
			parents[i] = parent
			continue
		}
		r := ranges[i]
		for j := i - 1; j >= 0; j-- {
			if ranges[j].Contains(r) {
				parentIndex[i] = j
				break
			}
		}
	}

	for k, v := range cap {
		i64, err := strconv.ParseInt(k, 10, 32)
		if i := int(i64); err == nil && i < len(parents) {
			if ranges[i].Start == -1 {
				continue
			}
			child := &parser.Node{Name: v.Name, Range: ranges[i], P: d}
			parents[i] = child
			if i == 0 {
				parent.Append(child)
				continue
			}
			var p *parser.Node
			for p == nil {
				i = parentIndex[i]
				p = parents[i]
			}
			p.Append(child)
		}
	}
}

func (p *Pattern) CreateNode(data string, pos int, d parser.DataSource, mo MatchObject) *parser.Node {
	ret := parser.Node{Name: p.Name, Range: parser.Range{mo[0], mo[1]}, P: d}
	if p.Match.re != nil {
		p.CreateCaptureNodes(data, pos, d, mo, &ret, p.Captures)
	} else if p.Begin.re != nil {
		if len(p.BeginCaptures) > 0 {
			p.CreateCaptureNodes(data, pos, d, mo, &ret, p.BeginCaptures)
		} else {
			p.CreateCaptureNodes(data, pos, d, mo, &ret, p.Captures)
		}

		if p.End.re != nil {
			var (
				found  = false
				i, end int
			)
			for i, end = ret.Range.End, len(data); i < len(data); {
				endmatch := p.End.Find(data, i)
				if endmatch != nil {
					end = endmatch[1]
				} else {
					if !found {
						// oops.. no end found at all, set it to the next line
						if e2 := strings.IndexRune(data[i:], '\n'); e2 != -1 {
							end = i + e2
						}
						break
					} else {
						end = i
						break
					}
				}
				if (endmatch == nil || (endmatch != nil && endmatch[0] != i)) && len(p.cachedPatterns) > 0 {
					// Might be more recursive patterns to apply BEFORE the end is reached
					pattern2, match2 := p.FirstMatch(data, i)
					if match2 != nil &&
						((endmatch == nil && match2[0] < end) ||
							(endmatch != nil && match2[0] < endmatch[0])) {

						found = true
						r := pattern2.CreateNode(data, i, d, match2)
						ret.Append(r)
						i = r.Range.End
						continue
					}
				}
				if endmatch != nil {
					if len(p.EndCaptures) > 0 {
						p.CreateCaptureNodes(data, i, d, endmatch, &ret, p.EndCaptures)
					} else {
						p.CreateCaptureNodes(data, i, d, endmatch, &ret, p.Captures)
					}
				}
				break
			}
			ret.Range.End = end
		}
	}
	ret.UpdateRange()
	return &ret
}

type dp struct {
	data []rune
}

func (d *dp) Data(a, b int) string {
	return string(d.data[a:b])
}

func (lp *LanguageParser) RootNode() *parser.Node {
	return &lp.root
}

func (lp *LanguageParser) patch(lut []int, node *parser.Node) {
	node.Range.Start = lut[node.Range.Start]
	node.Range.End = lut[node.Range.End]
	for _, child := range node.Children {
		lp.patch(lut, child)
	}
}

func (lp *LanguageParser) Parse(data string) bool {
	d := &dp{[]rune(data)}
	lp.root = parser.Node{P: d, Name: lp.Language.ScopeName}
	iter := maxiter
	for i := 0; i < len(data) && iter > 0; iter-- {
		pat, ret := lp.Language.RootPattern.Cache(data, i)
		nl := strings.IndexAny(data[i:], "\n\r")

		if nl != -1 {
			nl += i
		}
		if ret == nil {
			break
		} else if nl > 0 && nl <= ret[0] {
			i = nl
			for i < len(data) && (data[i] == '\n' || data[i] == '\r') {
				i++
			}
		} else {
			n := pat.CreateNode(data, i, d, ret)
			lp.root.Append(n)

			i = n.Range.End
		}
	}
	lp.root.UpdateRange()
	lut := make([]int, len(data))
	j := 0
	for i := range data {
		lut[i] = j
		j++
	}
	lp.patch(lut, &lp.root)
	return true
}
<commit_msg>Don't patch empty data.<commit_after>package textmate

import (
	"code.google.com/p/log4go"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/quarnster/parser"
	"io/ioutil"
	"lime/3rdparty/libs/rubex"
	"lime/backend/loaders"
	"strconv"
	"strings"
)

const maxiter = 10000

type (
	Regex struct {
		re        *rubex.Regexp
		lastIndex int
		lastFound int
		lastData  string
	}

	Language struct {
		UnpatchedLanguage
	}

	LanguageProvider map[string]*Language

	UnpatchedLanguage struct {
		FileTypes      []string
		FirstLineMatch string
		RootPattern    RootPattern `json:"patterns"`
		Repository     map[string]*Pattern
		ScopeName      string
	}

	Named struct {
		Name string
	}

	Captures map[string]Named

	MatchObject []int

	Pattern struct {
		Named
		Include        string
		Match          Regex
		Captures       Captures
		Begin          Regex
		BeginCaptures  Captures
		End            Regex
		EndCaptures    Captures
		Patterns       []*Pattern
		owner          *Language // needed for include directives
		cachedData     string
		cachedPat      *Pattern
		cachedPatterns []*Pattern
		cachedMatch    MatchObject
		hits           int
		misses         int
	}
	RootPattern struct {
		Pattern
	}

	LanguageParser struct {
		Language *Language
		root     parser.Node
	}
)

var (
	Provider = make(LanguageProvider)
	failed   = make(map[string]bool)
)

func (t LanguageProvider) GetLanguage(id string) (*Language, error) {
	if v, ok := t[id]; !ok {
		return nil, errors.New("Can't handle id " + id)
	} else {
		return v, nil
	}
}

func (t LanguageProvider) Load(fn string) error {
	if d, err := ioutil.ReadFile(fn); err != nil {
		return fmt.Errorf("Couldn't load file %s: %s", fn, err)
	} else {
		var l Language
		if err := loaders.LoadPlist(d, &l); err != nil {
			return err
		} else {
			t[l.ScopeName] = &l
		}
	}
	return nil
}

func (p Pattern) String() (ret string) {
	ret = fmt.Sprintf(`---------------------------------------
Name:    %s
Match:   %s
Begin:   %s
End:     %s
Include: %s
`, p.Name, p.Match, p.Begin, p.End, p.Include)
	ret += fmt.Sprintf("<Sub-Patterns>\n")
	for i := range p.Patterns {
		inner := fmt.Sprintf("%s", p.Patterns[i])
		ret += fmt.Sprintf("\t%s\n", strings.Replace(strings.Replace(inner, "\t", "\t\t", -1), "\n", "\n\t", -1))
	}
	ret += fmt.Sprintf("</Sub-Patterns>\n---------------------------------------")
	return
}

func (r Regex) String() string {
	if r.re == nil {
		return "nil"
	}
	return fmt.Sprintf("%s   // %d, %d", r.re.String(), r.lastIndex, r.lastFound)
}

func (r *RootPattern) String() (ret string) {
	for i := range r.Patterns {
		ret += fmt.Sprintf("\t%s\n", r.Patterns[i])
	}
	return
}

func (s *Language) String() string {
	return fmt.Sprintf("%s\n%s", s.ScopeName, s.RootPattern)
}

func (p *Pattern) setOwner(l *Language) {
	p.owner = l
	for i := range p.Patterns {
		p.Patterns[i].setOwner(l)
	}
}

func (l *Language) UnmarshalJSON(data []byte) error {
	if err := json.Unmarshal(data, &l.UnpatchedLanguage); err != nil {
		return err
	}
	l.RootPattern.setOwner(l)
	for k := range l.Repository {
		l.Repository[k].setOwner(l)
	}
	return nil
}

func (r *RootPattern) UnmarshalJSON(data []byte) error {
	return json.Unmarshal(data, &r.Patterns)
}

func (r *Regex) UnmarshalJSON(data []byte) error {
	str := string(data[1 : len(data)-1])
	str = strings.Replace(str, "\\\\", "\\", -1)
	str = strings.Replace(str, "\\n", "\n", -1)
	str = strings.Replace(str, "\\t", "\t", -1)
	if re, err := rubex.Compile(str); err != nil {
		log4go.Warn("Couldn't compile language pattern %s: %s", str, err)
	} else {
		r.re = re
	}
	return nil
}

func (m MatchObject) fix(add int) {
	for i := range m {
		if m[i] != -1 {
			m[i] += add
		}
	}
}

func (r *Regex) Find(data string, pos int) MatchObject {
	if r.lastData != data || r.lastIndex > pos {
		r.lastData = data
		r.lastFound = 0
	}
	r.lastIndex = pos
	for r.lastFound < len(data) {
		ret := r.re.FindStringSubmatchIndex(data[r.lastFound:])
		if ret == nil {
			break
		} else if (ret[0] + r.lastFound) < pos {
			if ret[0] == 0 {
				r.lastFound++
			} else {
				r.lastFound += ret[0]
			}
			continue
		}
		mo := MatchObject(ret)
		mo.fix(r.lastFound)
		return mo
	}
	return nil
}

func (p *Pattern) FirstMatch(data string, pos int) (pat *Pattern, ret MatchObject) {
	startIdx := -1
	for i := 0; i < len(p.cachedPatterns); {
		ip, im := p.cachedPatterns[i].Cache(data, pos)
		if im != nil && im[0] != im[1] {
			if startIdx < 0 || startIdx > im[0] {
				startIdx, pat, ret = im[0], ip, im
				// This match is right at the start, we're not going to find a better pattern than this,
				// so stop the search
				if im[0] == pos {
					break
				}
			}
			i++
		} else {
			// If it wasn't found now, it'll never be found, so the pattern can be popped from the cache
			copy(p.cachedPatterns[i:], p.cachedPatterns[i+1:])
			p.cachedPatterns = p.cachedPatterns[:len(p.cachedPatterns)-1]
		}
	}
	return
}

func (p *Pattern) Cache(data string, pos int) (pat *Pattern, ret MatchObject) {
	if p.cachedData == data {
		if p.cachedMatch == nil {
			return nil, nil
		}
		if p.cachedMatch[0] >= pos {
			p.hits++
			return p.cachedPat, p.cachedMatch
		}
	} else {
		p.cachedPatterns = nil
	}
	if p.cachedPatterns == nil {
		p.cachedPatterns = make([]*Pattern, len(p.Patterns))
		copy(p.cachedPatterns, p.Patterns)
	}
	p.misses++

	if p.Match.re != nil {
		pat, ret = p, p.Match.Find(data, pos)
	} else if p.Begin.re != nil {
		pat, ret = p, p.Begin.Find(data, pos)
	} else if p.Include != "" {
		if z := p.Include[0]; z == '#' {
			key := p.Include[1:]
			if p2, ok := p.owner.Repository[key]; ok {
				pat, ret = p2.Cache(data, pos)
			} else {
				log4go.Warn("Not found in repository: %s", p.Include)
			}
		} else if z == '$' {
			// TODO(q): Implement tmLanguage $ include directives
			log4go.Warn("Unhandled include directive: %s", p.Include)
		} else if l, err := Provider.GetLanguage(p.Include); err != nil {
			if !failed[p.Include] {
				log4go.Warn("Include directive %s failed: %s", p.Include, err)
			}
			failed[p.Include] = true
		} else {
			return l.RootPattern.Cache(data, pos)
		}
	} else {
		pat, ret = p.FirstMatch(data, pos)
	}
	p.cachedData = data
	p.cachedMatch = ret
	p.cachedPat = pat

	return
}

func (p *Pattern) CreateCaptureNodes(data string, pos int, d parser.DataSource, mo MatchObject, parent *parser.Node, cap Captures) {
	ranges := make([]parser.Range, len(mo)/2)
	parentIndex := make([]int, len(ranges))
	parents := make([]*parser.Node, len(parentIndex))
	for i := range ranges {
		ranges[i] = parser.Range{mo[i*2+0], mo[i*2+1]}
		if i < 2 {
			parents[i] = parent
			continue
		}
		r := ranges[i]
		for j := i - 1; j >= 0; j-- {
			if ranges[j].Contains(r) {
				parentIndex[i] = j
				break
			}
		}
	}

	for k, v := range cap {
		i64, err := strconv.ParseInt(k, 10, 32)
		if i := int(i64); err == nil && i < len(parents) {
			if ranges[i].Start == -1 {
				continue
			}
			child := &parser.Node{Name: v.Name, Range: ranges[i], P: d}
			parents[i] = child
			if i == 0 {
				parent.Append(child)
				continue
			}
			var p *parser.Node
			for p == nil {
				i = parentIndex[i]
				p = parents[i]
			}
			p.Append(child)
		}
	}
}

func (p *Pattern) CreateNode(data string, pos int, d parser.DataSource, mo MatchObject) *parser.Node {
	ret := parser.Node{Name: p.Name, Range: parser.Range{mo[0], mo[1]}, P: d}
	if p.Match.re != nil {
		p.CreateCaptureNodes(data, pos, d, mo, &ret, p.Captures)
	} else if p.Begin.re != nil {
		if len(p.BeginCaptures) > 0 {
			p.CreateCaptureNodes(data, pos, d, mo, &ret, p.BeginCaptures)
		} else {
			p.CreateCaptureNodes(data, pos, d, mo, &ret, p.Captures)
		}

		if p.End.re != nil {
			var (
				found  = false
				i, end int
			)
			for i, end = ret.Range.End, len(data); i < len(data); {
				endmatch := p.End.Find(data, i)
				if endmatch != nil {
					end = endmatch[1]
				} else {
					if !found {
						// oops.. no end found at all, set it to the next line
						if e2 := strings.IndexRune(data[i:], '\n'); e2 != -1 {
							end = i + e2
						}
						break
					} else {
						end = i
						break
					}
				}
				if (endmatch == nil || (endmatch != nil && endmatch[0] != i)) && len(p.cachedPatterns) > 0 {
					// Might be more recursive patterns to apply BEFORE the end is reached
					pattern2, match2 := p.FirstMatch(data, i)
					if match2 != nil &&
						((endmatch == nil && match2[0] < end) ||
							(endmatch != nil && match2[0] < endmatch[0])) {

						found = true
						r := pattern2.CreateNode(data, i, d, match2)
						ret.Append(r)
						i = r.Range.End
						continue
					}
				}
				if endmatch != nil {
					if len(p.EndCaptures) > 0 {
						p.CreateCaptureNodes(data, i, d, endmatch, &ret, p.EndCaptures)
					} else {
						p.CreateCaptureNodes(data, i, d, endmatch, &ret, p.Captures)
					}
				}
				break
			}
			ret.Range.End = end
		}
	}
	ret.UpdateRange()
	return &ret
}

type dp struct {
	data []rune
}

func (d *dp) Data(a, b int) string {
	return string(d.data[a:b])
}

func (lp *LanguageParser) RootNode() *parser.Node {
	return &lp.root
}

func (lp *LanguageParser) patch(lut []int, node *parser.Node) {
	node.Range.Start = lut[node.Range.Start]
	node.Range.End = lut[node.Range.End]
	for _, child := range node.Children {
		lp.patch(lut, child)
	}
}

func (lp *LanguageParser) Parse(data string) bool {
	d := &dp{[]rune(data)}
	lp.root = parser.Node{P: d, Name: lp.Language.ScopeName}
	iter := maxiter
	for i := 0; i < len(data) && iter > 0; iter-- {
		pat, ret := lp.Language.RootPattern.Cache(data, i)
		nl := strings.IndexAny(data[i:], "\n\r")

		if nl != -1 {
			nl += i
		}
		if ret == nil {
			break
		} else if nl > 0 && nl <= ret[0] {
			i = nl
			for i < len(data) && (data[i] == '\n' || data[i] == '\r') {
				i++
			}
		} else {
			n := pat.CreateNode(data, i, d, ret)
			lp.root.Append(n)

			i = n.Range.End
		}
	}
	lp.root.UpdateRange()
	if len(data) != 0 {
		lut := make([]int, len(data))
		j := 0
		for i := range data {
			lut[i] = j
			j++
		}
		lp.patch(lut, &lp.root)
	}
	return true
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"crypto/tls"
	"fmt"
	"log"

	fabric "github.com/nimona/go-nimona-fabric"
)

func main() {
	peerA, err := newPeer("PeerA")
	if err != nil {
		log.Fatal("Could not create peer A", err)
	}

	peerB, err := newPeer("PeerB")
	if err != nil {
		log.Fatal("Could not create peer B", err)
	}

	log.Println("Peer A address:", peerA.GetAddresses())

	for _, addr := range peerA.GetAddresses() {
		endpoint := addr + "/tls/yamux/router/identity/ping"
		log.Println("-------- Dialing", endpoint)
		if err := peerB.DialContext(context.Background(), endpoint); err != nil {
			log.Println("Dial error", err)
		}
		endpoint = addr + "/tls/yamux/router/ping"
		log.Println("-------- SECOND Dial", endpoint)
		if err := peerB.DialContext(context.Background(), endpoint); err != nil {
			log.Println("Dial error", err)
		}
	}
}

func newPeer(peerID string) (*fabric.Fabric, error) {
	ctx := context.Background()
	crt, err := GenX509KeyPair()
	if err != nil {
		fmt.Println("Cert creation error", err)
		return nil, err
	}

	yamux := fabric.NewYamux()
	router := fabric.NewRouter()
	identity := &fabric.IdentityProtocol{Local: peerID}
	tls := &fabric.SecProtocol{
		Config: tls.Config{
			Certificates:       []tls.Certificate{crt},
			InsecureSkipVerify: true,
		},
	}
	ping := &Ping{}

	tcp := fabric.NewTransportTCP("0.0.0.0", 0)
	// ws := fabric.NewTransportWebsocket("0.0.0.0", 0)

	f := fabric.New(ctx)

	f.AddTransport(yamux, []fabric.Protocol{router})
	f.AddTransport(tcp, []fabric.Protocol{tls, yamux, router})
	// f.AddTransport(ws, []fabric.Protocol{tls, yamux, router})

	f.AddProtocol(router)
	f.AddProtocol(tls)
	f.AddProtocol(yamux)
	f.AddProtocol(identity)
	f.AddProtocol(ping)

	router.AddRoute(ping)
	router.AddRoute(identity, ping)

	if err := f.Listen(ctx); err != nil {
		log.Fatal("Could not listen for peer A", err)
	}

	return f, nil
}
<commit_msg>Fix example<commit_after>package main

import (
	"context"
	"crypto/tls"
	"fmt"
	"log"

	fabric "github.com/nimona/go-nimona-fabric"
)

func main() {
	peerA, err := newPeer("PeerA")
	if err != nil {
		log.Fatal("Could not create peer A", err)
	}

	peerB, err := newPeer("PeerB")
	if err != nil {
		log.Fatal("Could not create peer B", err)
	}

	log.Println("Peer A address:", peerA.GetAddresses())

	for _, addr := range peerA.GetAddresses() {
		endpoint := addr + "/tls/yamux/router/identity/ping"
		log.Println("-------- Dialing", endpoint)
		if err := peerB.DialContext(context.Background(), endpoint); err != nil {
			log.Println("Dial error", err)
		}
		endpoint = addr + "/tls/yamux/router/ping"
		log.Println("-------- SECOND Dial", endpoint)
		if err := peerB.DialContext(context.Background(), endpoint); err != nil {
			log.Println("Dial error", err)
		}
	}
}

func newPeer(peerID string) (*fabric.Fabric, error) {
	ctx := context.Background()
	crt, err := GenX509KeyPair()
	if err != nil {
		fmt.Println("Cert creation error", err)
		return nil, err
	}

	yamux := fabric.NewYamux()
	router := fabric.NewRouter()
	identity := &fabric.IdentityProtocol{Local: peerID}
	tls := &fabric.SecProtocol{
		Config: tls.Config{
			Certificates:       []tls.Certificate{crt},
			InsecureSkipVerify: true,
		},
	}
	ping := &Ping{}

	tcp := fabric.NewTransportTCP("0.0.0.0", 0)
	ws := fabric.NewTransportWebsocket("0.0.0.0", 0)

	f := fabric.New(ctx)

	f.AddTransport(yamux, []fabric.Protocol{router})
	f.AddTransport(tcp, []fabric.Protocol{tls, yamux, router})
	f.AddTransport(ws, []fabric.Protocol{tls, yamux, router})

	f.AddProtocol(router)
	f.AddProtocol(tls)
	f.AddProtocol(yamux)
	f.AddProtocol(identity)
	f.AddProtocol(ping)

	router.AddRoute(ping)
	router.AddRoute(identity, ping)

	return f, nil
}
<|endoftext|>


<commit_before>package e2e

import (
	"testing"

	"github.com/stretchr/testify/assert"

	. "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
	"github.com/argoproj/argo-cd/test/e2e/fixture"
	. "github.com/argoproj/argo-cd/test/e2e/fixture/app"
)

func TestKustomize2AppSource(t *testing.T) {

	patchLabelMatchesFor := func(kind string) func(app *Application) {
		return func(app *Application) {
			name := "k2-patched-guestbook-ui"
			labelValue, err := fixture.Run(
				"", "kubectl", "-n="+fixture.DeploymentNamespace(),
				"get", kind, name,
				"-ojsonpath={.metadata.labels.patched-by}")
			assert.NoError(t, err)
			assert.Equal(t, "argo-cd", labelValue, "wrong value of 'patched-by' label of %s %s", kind, name)
		}
	}

	Given(t).
		Path(guestbookPath).
		NamePrefix("k2-").
		When().
		Create().
		Refresh(RefreshTypeHard).
		PatchApp(`[
			{
				"op": "replace",
				"path": "/spec/source/kustomize/namePrefix",
				"value": "k2-patched-"
			},
			{
				"op": "add",
				"path": "/spec/source/kustomize/commonLabels",
				"value": {
					"patched-by": "argo-cd"
				}
			}
		]`).
		Then().
		Expect(Success("")).
		When().
		Sync().
		Then().
		And(patchLabelMatchesFor("Service")).
		And(patchLabelMatchesFor("Deployment"))
}

// when we have a config map generator, AND the ignore annotation, it is ignored in the app's sync status
func TestSyncStatusOptionIgnore(t *testing.T) {
	var mapName string
	Given(t).
		Path("kustomize-cm-gen").
		When().
		Create().
		Sync().
		Then().
		Expect(OperationPhaseIs(OperationSucceeded)).
		Expect(SyncStatusIs(SyncStatusCodeSynced)).
		Expect(HealthIs(HealthStatusHealthy)).
		And(func(app *Application) {
			resourceStatus := app.Status.Resources[0]
			assert.Contains(t, resourceStatus.Name, "my-map-")
			assert.Equal(t, SyncStatusCodeSynced, resourceStatus.Status)

			mapName = resourceStatus.Name
		}).
		When().
		// we now force generation of a second CM
		PatchFile("kustomization.yaml", `[{"op": "replace", "path": "/configMapGenerator/0/literals/0", "value": "foo=baz"}]`).
		Refresh(RefreshTypeHard).
		Then().
		// this is standard logging from the command - tough one - true statement
		When().
		Sync().
		Then().
		Expect(Error("1 resources require pruning")).
		Expect(OperationPhaseIs(OperationSucceeded)).
		// this is a key check - we expect the app to be healthy because, even though we have a resources that needs
		// pruning, because it is annotated with IgnoreExtraneous it should not contribute to the sync status
		Expect(SyncStatusIs(SyncStatusCodeSynced)).
		Expect(HealthIs(HealthStatusHealthy)).
		And(func(app *Application) {
			assert.Equal(t, 2, len(app.Status.Resources))
			// new map in-sync
			{
				resourceStatus := app.Status.Resources[0]
				assert.Contains(t, resourceStatus.Name, "my-map-")
				// make sure we've a new map with changed name
				assert.NotEqual(t, mapName, resourceStatus.Name)
				assert.Equal(t, SyncStatusCodeSynced, resourceStatus.Status)
			}
			// old map is out of sync
			{
				resourceStatus := app.Status.Resources[1]
				assert.Equal(t, mapName, resourceStatus.Name)
				assert.Equal(t, SyncStatusCodeOutOfSync, resourceStatus.Status)
			}
		})
}

// make sure we can create an app which has a SSH remote base
func TestKustomizeSSHRemoteBase(t *testing.T) {
	Given(t).
		// not the best test, as we should have two remote repos both with the same SSH private key
		SSHRepo().
		Path("remote-base").
		When().
		Create().
		Sync().
		Then().
		Expect(OperationPhaseIs(OperationSucceeded)).
		Expect(ResourceSyncStatusIs("ConfigMap", "my-map", SyncStatusCodeSynced))
}

// make sure we can create an app which has a SSH remote base
func TestKustomizeDeclarativeInvalidApp(t *testing.T) {
	Given(t).
		Path("invalid-kustomize").
		When().
		Declarative("declarative-apps/app.yaml").
		Then().
		Expect(Success("")).
		Expect(HealthIs(HealthStatusHealthy)).
		Expect(SyncStatusIs(SyncStatusCodeUnknown)).
		Expect(Condition(ApplicationConditionComparisonError, "invalid-kustomize/does-not-exist.yaml: no such file or directory"))
}
<commit_msg>Fixes TestKustomize2AppSource. Closes #1800 (#1801)<commit_after>package e2e

import (
	"testing"

	"github.com/stretchr/testify/assert"

	. "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
	"github.com/argoproj/argo-cd/test/e2e/fixture"
	. "github.com/argoproj/argo-cd/test/e2e/fixture/app"
)

func TestKustomize2AppSource(t *testing.T) {

	patchLabelMatchesFor := func(kind string) func(app *Application) {
		return func(app *Application) {
			name := "k2-patched-guestbook-ui"
			labelValue, err := fixture.Run(
				"", "kubectl", "-n="+fixture.DeploymentNamespace(),
				"get", kind, name,
				"-ojsonpath={.metadata.labels.patched-by}")
			assert.NoError(t, err)
			assert.Equal(t, "argo-cd", labelValue, "wrong value of 'patched-by' label of %s %s", kind, name)
		}
	}

	Given(t).
		Path(guestbookPath).
		NamePrefix("k2-").
		When().
		Create().
		Refresh(RefreshTypeHard).
		PatchApp(`[
			{
				"op": "replace",
				"path": "/spec/source/kustomize/namePrefix",
				"value": "k2-patched-"
			},
			{
				"op": "add",
				"path": "/spec/source/kustomize/commonLabels",
				"value": {
					"patched-by": "argo-cd"
				}
			}
		]`).
		Then().
		Expect(Success("")).
		When().
		Sync().
		Then().
		Expect(Success("")).
		Expect(OperationPhaseIs(OperationSucceeded)).
		Expect(SyncStatusIs(SyncStatusCodeSynced)).
		Expect(HealthIs(HealthStatusHealthy)).
		And(patchLabelMatchesFor("Service")).
		And(patchLabelMatchesFor("Deployment"))
}

// when we have a config map generator, AND the ignore annotation, it is ignored in the app's sync status
func TestSyncStatusOptionIgnore(t *testing.T) {
	var mapName string
	Given(t).
		Path("kustomize-cm-gen").
		When().
		Create().
		Sync().
		Then().
		Expect(OperationPhaseIs(OperationSucceeded)).
		Expect(SyncStatusIs(SyncStatusCodeSynced)).
		Expect(HealthIs(HealthStatusHealthy)).
		And(func(app *Application) {
			resourceStatus := app.Status.Resources[0]
			assert.Contains(t, resourceStatus.Name, "my-map-")
			assert.Equal(t, SyncStatusCodeSynced, resourceStatus.Status)

			mapName = resourceStatus.Name
		}).
		When().
		// we now force generation of a second CM
		PatchFile("kustomization.yaml", `[{"op": "replace", "path": "/configMapGenerator/0/literals/0", "value": "foo=baz"}]`).
		Refresh(RefreshTypeHard).
		Then().
		// this is standard logging from the command - tough one - true statement
		When().
		Sync().
		Then().
		Expect(Error("1 resources require pruning")).
		Expect(OperationPhaseIs(OperationSucceeded)).
		// this is a key check - we expect the app to be healthy because, even though we have a resources that needs
		// pruning, because it is annotated with IgnoreExtraneous it should not contribute to the sync status
		Expect(SyncStatusIs(SyncStatusCodeSynced)).
		Expect(HealthIs(HealthStatusHealthy)).
		And(func(app *Application) {
			assert.Equal(t, 2, len(app.Status.Resources))
			// new map in-sync
			{
				resourceStatus := app.Status.Resources[0]
				assert.Contains(t, resourceStatus.Name, "my-map-")
				// make sure we've a new map with changed name
				assert.NotEqual(t, mapName, resourceStatus.Name)
				assert.Equal(t, SyncStatusCodeSynced, resourceStatus.Status)
			}
			// old map is out of sync
			{
				resourceStatus := app.Status.Resources[1]
				assert.Equal(t, mapName, resourceStatus.Name)
				assert.Equal(t, SyncStatusCodeOutOfSync, resourceStatus.Status)
			}
		})
}

// make sure we can create an app which has a SSH remote base
func TestKustomizeSSHRemoteBase(t *testing.T) {
	Given(t).
		// not the best test, as we should have two remote repos both with the same SSH private key
		SSHRepo().
		Path("remote-base").
		When().
		Create().
		Sync().
		Then().
		Expect(OperationPhaseIs(OperationSucceeded)).
		Expect(ResourceSyncStatusIs("ConfigMap", "my-map", SyncStatusCodeSynced))
}

// make sure we can create an app which has a SSH remote base
func TestKustomizeDeclarativeInvalidApp(t *testing.T) {
	Given(t).
		Path("invalid-kustomize").
		When().
		Declarative("declarative-apps/app.yaml").
		Then().
		Expect(Success("")).
		Expect(HealthIs(HealthStatusHealthy)).
		Expect(SyncStatusIs(SyncStatusCodeUnknown)).
		Expect(Condition(ApplicationConditionComparisonError, "invalid-kustomize/does-not-exist.yaml: no such file or directory"))
}
<|endoftext|>


<commit_before>package plugins

import (
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/cenk/backoff"
	"github.com/fatih/color"
	marathon "github.com/gambol99/go-marathon"
	consul "github.com/hashicorp/consul/api"

	"github.com/InnovaCo/serve/manifest"
)

func init() {
	manifest.PluginRegestry.Add("deploy.marathon", DeployMarathon{})
}

type DeployMarathon struct{}

func (p DeployMarathon) Run(data manifest.Manifest) error {
	if data.GetBool("purge") {
		return p.Uninstall(data)
	} else {
		return p.Install(data)
	}
}

func (p DeployMarathon) Install(data manifest.Manifest) error {
	marathonApi, err := MarathonClient(data.GetString("marathon-host"))
	if err != nil {
		return err
	}

	fullName := data.GetString("app-name")

	bs, bf, bmax := 1.0, 2.0, 30.0
	app := &marathon.Application{
		BackoffSeconds:        &bs,
		BackoffFactor:         &bf,
		MaxLaunchDelaySeconds: &bmax,
	}

	app.Name(fullName)
	app.Command(fmt.Sprintf("serve-tools consul supervisor --service '%s' --port $PORT0 start %s", fullName, data.GetString("cmd")))
	app.Count(data.GetInt("instances"))
	app.Memory(float64(data.GetInt("mem")))

	if cpu, err := strconv.ParseFloat(data.GetString("cpu"), 64); err == nil {
		app.CPU(cpu)
	}

	if constrs := data.GetString("constraints"); constrs != "" {
		cs := strings.SplitN(constrs, ":", 2)
		app.AddConstraint(cs[0], "CLUSTER", cs[1])
		app.AddLabel(cs[0], cs[1])
	}

	for k, v := range data.GetMap("environment") {
		app.AddEnv(k, fmt.Sprintf("%s", v.Unwrap()))
	}

	app.AddUris(data.GetString("package-uri"))

	if _, err := marathonApi.UpdateApplication(app, false); err != nil {
		color.Yellow("marathon <- %s", app)
		return err
	}

	color.Green("marathon <- %s", app)

	consulApi, err := ConsulClient(data.GetString("consul-host"))
	if err != nil {
		return err
	}

	if err := registerPluginData("deploy.marathon", data.GetString("app-name"), data.String(), data.GetString("consul-host")); err != nil {
		return err
	}

	return backoff.Retry(func() error {
		services, _, err := consulApi.Health().Service(fullName, "", true, nil)

		if err != nil {
			log.Println(color.RedString("Error in check health in consul: %v", err))
			return err
		}

		if len(services) == 0 {
			log.Printf("Service `%s` not started yet! Retry...", fullName)
			return fmt.Errorf("Service `%s` not started!", fullName)
		}

		log.Println(color.GreenString("Service `%s` successfully started!", fullName))
		return nil
	}, backoff.NewExponentialBackOff())
}

func (p DeployMarathon) Uninstall(data manifest.Manifest) error {
	marathonApi, err := MarathonClient(data.GetString("marathon-host"))
	if err != nil {
		return err
	}

	name := data.GetString("app-name")

	if _, err := marathonApi.Application(name); err == nil {
		if _, err := marathonApi.DeleteApplication(name, false); err != nil {
			return err
		}
	} else {
		log.Println(color.YellowString("App `%s` doesnt exists in marathon!", name))
	}

	return deletePluginData("deploy.marathon", name, data.GetString("consul-host"))
}

func MarathonClient(marathonHost string) (marathon.Marathon, error) {
	conf := marathon.NewDefaultConfig()
	conf.URL = fmt.Sprintf("http://%s:8080", marathonHost)
	conf.LogOutput = os.Stdout
	return marathon.NewClient(conf)
}

func ConsulClient(consulHost string) (*consul.Client, error) {
	conf := consul.DefaultConfig()
	conf.Address = consulHost + ":8500"
	return consul.NewClient(conf)
}

func putConsulKv(client *consul.Client, key string, value string) error {
	log.Printf("consul put `%s`: %s", key, value)
	_, err := client.KV().Put(&consul.KVPair{Key: strings.TrimPrefix(key, "/"), Value: []byte(value)}, nil)
	return err
}

func listConsulKv(client *consul.Client, prefix string, q *consul.QueryOptions) (consul.KVPairs, error) {
	log.Printf("consul list `%s`", prefix)
	list, _, err := client.KV().List(prefix, q)
	return list, err
}

func delConsulKv(client *consul.Client, key string) error {
	log.Printf("consul delete `%s`", key)
	_, err := client.KV().Delete(strings.TrimPrefix(key, "/"), nil)
	return err
}

func registerPluginData(plugin string, packageName string, data string, consulHost string) error {
	consulApi, err := ConsulClient(consulHost)
	if err != nil {
		return err
	}

	return putConsulKv(consulApi, "services/data/"+packageName+"/"+plugin, data)
}

func deletePluginData(plugin string, packageName string, consulHost string) error {
	log.Println(color.YellowString("Delete %s for %s package in consul", plugin, packageName))
	consulApi, err := ConsulClient(consulHost)
	if err != nil {
		return err
	}

	return delConsulKv(consulApi, "services/data/"+packageName+"/"+plugin)
}

func markAsOutdated(client *consul.Client, name string, delay time.Duration) error {
	log.Printf("Mark service `%s` as outdated\n", name)
	json := fmt.Sprintf(`{"endOfLife":%d}`, time.Now().Add(delay).UnixNano()/int64(time.Millisecond))
	return putConsulKv(client, "services/outdated/"+name, json)
}
<commit_msg>= marathon: log requests to os.Stderr<commit_after>package plugins

import (
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/cenk/backoff"
	"github.com/fatih/color"
	marathon "github.com/gambol99/go-marathon"
	consul "github.com/hashicorp/consul/api"

	"github.com/InnovaCo/serve/manifest"
)

func init() {
	manifest.PluginRegestry.Add("deploy.marathon", DeployMarathon{})
}

type DeployMarathon struct{}

func (p DeployMarathon) Run(data manifest.Manifest) error {
	if data.GetBool("purge") {
		return p.Uninstall(data)
	} else {
		return p.Install(data)
	}
}

func (p DeployMarathon) Install(data manifest.Manifest) error {
	marathonApi, err := MarathonClient(data.GetString("marathon-host"))
	if err != nil {
		return err
	}

	fullName := data.GetString("app-name")

	bs, bf, bmax := 1.0, 2.0, 30.0
	app := &marathon.Application{
		BackoffSeconds:        &bs,
		BackoffFactor:         &bf,
		MaxLaunchDelaySeconds: &bmax,
	}

	app.Name(fullName)
	app.Command(fmt.Sprintf("serve-tools consul supervisor --service '%s' --port $PORT0 start %s", fullName, data.GetString("cmd")))
	app.Count(data.GetInt("instances"))
	app.Memory(float64(data.GetInt("mem")))

	if cpu, err := strconv.ParseFloat(data.GetString("cpu"), 64); err == nil {
		app.CPU(cpu)
	}

	if constrs := data.GetString("constraints"); constrs != "" {
		cs := strings.SplitN(constrs, ":", 2)
		app.AddConstraint(cs[0], "CLUSTER", cs[1])
		app.AddLabel(cs[0], cs[1])
	}

	for k, v := range data.GetMap("environment") {
		app.AddEnv(k, fmt.Sprintf("%s", v.Unwrap()))
	}

	app.AddUris(data.GetString("package-uri"))

	if _, err := marathonApi.UpdateApplication(app, false); err != nil {
		color.Yellow("marathon <- %s", app)
		return err
	}

	color.Green("marathon <- %s", app)

	consulApi, err := ConsulClient(data.GetString("consul-host"))
	if err != nil {
		return err
	}

	if err := registerPluginData("deploy.marathon", data.GetString("app-name"), data.String(), data.GetString("consul-host")); err != nil {
		return err
	}

	return backoff.Retry(func() error {
		services, _, err := consulApi.Health().Service(fullName, "", true, nil)

		if err != nil {
			log.Println(color.RedString("Error in check health in consul: %v", err))
			return err
		}

		if len(services) == 0 {
			log.Printf("Service `%s` not started yet! Retry...", fullName)
			return fmt.Errorf("Service `%s` not started!", fullName)
		}

		log.Println(color.GreenString("Service `%s` successfully started!", fullName))
		return nil
	}, backoff.NewExponentialBackOff())
}

func (p DeployMarathon) Uninstall(data manifest.Manifest) error {
	marathonApi, err := MarathonClient(data.GetString("marathon-host"))
	if err != nil {
		return err
	}

	name := data.GetString("app-name")

	if _, err := marathonApi.Application(name); err == nil {
		if _, err := marathonApi.DeleteApplication(name, false); err != nil {
			return err
		}
	} else {
		log.Println(color.YellowString("App `%s` doesnt exists in marathon!", name))
	}

	return deletePluginData("deploy.marathon", name, data.GetString("consul-host"))
}

func MarathonClient(marathonHost string) (marathon.Marathon, error) {
	conf := marathon.NewDefaultConfig()
	conf.URL = fmt.Sprintf("http://%s:8080", marathonHost)
	conf.LogOutput = os.Stderr
	return marathon.NewClient(conf)
}

func ConsulClient(consulHost string) (*consul.Client, error) {
	conf := consul.DefaultConfig()
	conf.Address = consulHost + ":8500"
	return consul.NewClient(conf)
}

func putConsulKv(client *consul.Client, key string, value string) error {
	log.Printf("consul put `%s`: %s", key, value)
	_, err := client.KV().Put(&consul.KVPair{Key: strings.TrimPrefix(key, "/"), Value: []byte(value)}, nil)
	return err
}

func listConsulKv(client *consul.Client, prefix string, q *consul.QueryOptions) (consul.KVPairs, error) {
	log.Printf("consul list `%s`", prefix)
	list, _, err := client.KV().List(prefix, q)
	return list, err
}

func delConsulKv(client *consul.Client, key string) error {
	log.Printf("consul delete `%s`", key)
	_, err := client.KV().Delete(strings.TrimPrefix(key, "/"), nil)
	return err
}

func registerPluginData(plugin string, packageName string, data string, consulHost string) error {
	consulApi, err := ConsulClient(consulHost)
	if err != nil {
		return err
	}

	return putConsulKv(consulApi, "services/data/"+packageName+"/"+plugin, data)
}

func deletePluginData(plugin string, packageName string, consulHost string) error {
	log.Println(color.YellowString("Delete %s for %s package in consul", plugin, packageName))
	consulApi, err := ConsulClient(consulHost)
	if err != nil {
		return err
	}

	return delConsulKv(consulApi, "services/data/"+packageName+"/"+plugin)
}

func markAsOutdated(client *consul.Client, name string, delay time.Duration) error {
	log.Printf("Mark service `%s` as outdated\n", name)
	json := fmt.Sprintf(`{"endOfLife":%d}`, time.Now().Add(delay).UnixNano()/int64(time.Millisecond))
	return putConsulKv(client, "services/outdated/"+name, json)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/petemoore/taskcluster-client-go/utils"
	"github.com/streadway/amqp"
)

func main() {
	// connection, err := amqp.Dial("amqps://pulse.mozilla.org/exchange/taskcluster-queue/v1/task-defined")
	connection, err := amqp.Dial("amqp://localhost/")
	utils.ExitOnFail(err)
	defer connection.Close()
	channel, err := connection.Channel()
	utils.ExitOnFail(err)
	_, err = channel.QueueDeclare("hello", false, false, false, false, nil)
	msg := amqp.Publishing{
		ContentType: "application/json",
		Body:        []byte(`{"name":"pmoore"}`)}
	channel.Publish("", "hello", false, false, msg)
	utils.ExitOnFail(err)
	fmt.Println("Published message")
}
<commit_msg>Work in progress<commit_after>package exchange

import (
	"reflect"
	"strings"
)

type TaskDefined struct {
	RoutingKeyKind string `mwords:"*"`
	TaskId         string `mwords:"*"`
	RunId          string `mwords:"*"`
	WorkerGroup    string `mwords:"*"`
	WorkerId       string `mwords:"*"`
	ProvisionerId  string `mwords:"*"`
	WorkerType     string `mwords:"*"`
	SchedulerId    string `mwords:"*"`
	TaskGroupId    string `mwords:"*"`
	Reserved       string `mwords:"#"`
}

func (x TaskDefined) RoutingKey() string {
	return generateRoutingKey(&x)
}

func (x TaskDefined) ExchangeName() string {
	return "exchange/taskcluster-queue/v1/task-defined"
}

func generateRoutingKey(x *TaskDefined) string {
	val := reflect.ValueOf(x).Elem()
	p := make([]string, 0, val.NumField())
	for i := 0; i < val.NumField(); i++ {
		valueField := val.Field(i)
		typeField := val.Type().Field(i)
		tag := typeField.Tag
		if t := tag.Get("mwords"); t != "" {
			if v := valueField.Interface(); v == "" {
				p = append(p, t)
			} else {
				p = append(p, v.(string))
			}
		}
	}
	return strings.Join(p, ".")
}
<|endoftext|>


<commit_before><commit_msg>Add getDigit into MBS<commit_after><|endoftext|>


<commit_before>// The experiments package holds various experiments with NEAT.
package experiments

import (
	"github.com/yaricom/goNEAT/neat/genetics"
	"github.com/yaricom/goNEAT/neat"
	"fmt"
	"time"
)

// The interface describing evaluator for one epoch of evolution.
type EpochEvaluator interface {
	EpochEvaluate(pop *genetics.Population, epoch *Epoch, context *neat.NeatContext) (err error)
}

// The Experiment execution entry point
func (ex *Experiment) Execute(context *neat.NeatContext, start_genome *genetics.Genome, epoch_executor EpochEvaluator) (err error) {
	if ex.Trials == nil {
		ex.Trials = make(Trials, context.NumRuns)
	}

	var pop *genetics.Population
	for run := 0; run < context.NumRuns; run++ {
		neat.InfoLog("\n>>>>> Spawning new population ")
		pop, err = genetics.NewPopulation(start_genome, context)
		if err != nil {
			neat.InfoLog("Failed to spawn new population from start genome")
			return err
		} else {
			neat.InfoLog("OK <<<<<")
		}
		neat.InfoLog(">>>>> Verifying spawned population ")
		_, err = pop.Verify()
		if err != nil {
			neat.ErrorLog("\n!!!!! Population verification failed !!!!!")
			return err
		} else {
			neat.InfoLog("OK <<<<<")
		}

		// start new trial
		trial := Trial {
			Id:run,
		}

		for gen := 0; gen < context.NumGenerations; gen++ {
			neat.InfoLog(fmt.Sprintf(">>>>> Epoch:%3d\tRun: %d\n", gen, run))
			epoch := Epoch{
				Id:gen,
			}
			err = epoch_executor.EpochEvaluate(pop, &epoch, context)
			if err != nil {
				neat.InfoLog(fmt.Sprintf("!!!!! Epoch %d evaluation failed !!!!!\n", gen))
				return err
			}
			epoch.Executed = time.Now()
			trial.Epochs = append(trial.Epochs, epoch)
			if epoch.Solved {
				neat.InfoLog(fmt.Sprintf(">>>>> The winner organism found in epoch %d! <<<<<\n", gen))
				break
			}
		}
		// store trial into experiment
		ex.Trials[run] = trial
	}

	return nil
}
<commit_msg>Added trial run observer interface<commit_after>// The experiments package holds various experiments with NEAT.
package experiments

import (
	"github.com/yaricom/goNEAT/neat/genetics"
	"github.com/yaricom/goNEAT/neat"
	"fmt"
	"time"
)

// The interface describing evaluator for one epoch of evolution.
type EpochEvaluator interface {
	// Invoked to evaluate one epoch of evolution over provided population of organisms within given
	// execution context.
	EpochEvaluate(pop *genetics.Population, epoch *Epoch, context *neat.NeatContext) (err error)
}

// The interface to describe trial lifecycle observer interested to receive lifecycle notifications
type TrialRunObserver interface {
	// Invoked to notify that new trial run just started before any epoch evaluation in that trial run
	TrialRunStarted(trial *Trial)
}

// The Experiment execution entry point
func (ex *Experiment) Execute(context *neat.NeatContext, start_genome *genetics.Genome, executor interface{}) (err error) {
	if ex.Trials == nil {
		ex.Trials = make(Trials, context.NumRuns)
	}

	var pop *genetics.Population
	for run := 0; run < context.NumRuns; run++ {
		neat.InfoLog("\n>>>>> Spawning new population ")
		pop, err = genetics.NewPopulation(start_genome, context)
		if err != nil {
			neat.InfoLog("Failed to spawn new population from start genome")
			return err
		} else {
			neat.InfoLog("OK <<<<<")
		}
		neat.InfoLog(">>>>> Verifying spawned population ")
		_, err = pop.Verify()
		if err != nil {
			neat.ErrorLog("\n!!!!! Population verification failed !!!!!")
			return err
		} else {
			neat.InfoLog("OK <<<<<")
		}

		// start new trial
		trial := Trial {
			Id:run,
		}

		if trialObserver, ok := executor.(TrialRunObserver); ok {
			trialObserver.TrialRunStarted(&trial) // optional
		}

		epoch_evaluator := executor.(EpochEvaluator) // mandatory

		for gen := 0; gen < context.NumGenerations; gen++ {
			neat.InfoLog(fmt.Sprintf(">>>>> Epoch:%3d\tRun: %d\n", gen, run))
			epoch := Epoch{
				Id:gen,
			}
			err = epoch_evaluator.EpochEvaluate(pop, &epoch, context)
			if err != nil {
				neat.InfoLog(fmt.Sprintf("!!!!! Epoch %d evaluation failed !!!!!\n", gen))
				return err
			}
			epoch.Executed = time.Now()
			trial.Epochs = append(trial.Epochs, epoch)
			if epoch.Solved {
				neat.InfoLog(fmt.Sprintf(">>>>> The winner organism found in epoch %d! <<<<<\n", gen))
				break
			}
		}
		// store trial into experiment
		ex.Trials[run] = trial
	}

	return nil
}
<|endoftext|>


<commit_before>package exporter

import (
	"testing"
	"strings"
)

func TestAllRegexpsCompile(t *testing.T) {
	patterns := loadPatternDir(t)
	for pattern := range *patterns {
		_, err := Compile("%{"+pattern+"}", patterns)
		if err != nil {
			t.Errorf("%v", err.Error())
		}
	}
}

func TestUnknownGrokPattern(t *testing.T) {
	patterns := loadPatternDir(t)
	_, err := Compile("%{USER} [a-z] %{SOME_UNKNOWN_PATTERN}.*", patterns)
	if err == nil || ! strings.Contains(err.Error(), "SOME_UNKNOWN_PATTERN") {
		t.Error("expected error message saying which pattern is undefined.")
	}
}

func TestInvalidRegexp(t *testing.T) {
	patterns := loadPatternDir(t)
	_, err := Compile("%{USER} [a-z] \\", patterns) // wrong because regex cannot end with backslash
	if err == nil || ! strings.Contains(err.Error(), "%{USER} [a-z] \\") {
		t.Error("expected error message saying which pattern is invalid.")
	}
}

func TestNamedCaptureGroup(t *testing.T) {
	patterns := loadPatternDir(t)
	regex, err := Compile("User %{USER:user} has logged in.", patterns)
	if err != nil {
		t.Error(err)
	}
	found := regex.Gsub("User fabian has logged in.", "\\k<user>")
	if found != "fabian" {
		t.Errorf("Expected to capture 'fabian', but captured '%v'.", found)
	}
}
<commit_msg>go fmt<commit_after>package exporter

import (
	"strings"
	"testing"
)

func TestAllRegexpsCompile(t *testing.T) {
	patterns := loadPatternDir(t)
	for pattern := range *patterns {
		_, err := Compile("%{"+pattern+"}", patterns)
		if err != nil {
			t.Errorf("%v", err.Error())
		}
	}
}

func TestUnknownGrokPattern(t *testing.T) {
	patterns := loadPatternDir(t)
	_, err := Compile("%{USER} [a-z] %{SOME_UNKNOWN_PATTERN}.*", patterns)
	if err == nil || !strings.Contains(err.Error(), "SOME_UNKNOWN_PATTERN") {
		t.Error("expected error message saying which pattern is undefined.")
	}
}

func TestInvalidRegexp(t *testing.T) {
	patterns := loadPatternDir(t)
	_, err := Compile("%{USER} [a-z] \\", patterns) // wrong because regex cannot end with backslash
	if err == nil || !strings.Contains(err.Error(), "%{USER} [a-z] \\") {
		t.Error("expected error message saying which pattern is invalid.")
	}
}

func TestNamedCaptureGroup(t *testing.T) {
	patterns := loadPatternDir(t)
	regex, err := Compile("User %{USER:user} has logged in.", patterns)
	if err != nil {
		t.Error(err)
	}
	found := regex.Gsub("User fabian has logged in.", "\\k<user>")
	if found != "fabian" {
		t.Errorf("Expected to capture 'fabian', but captured '%v'.", found)
	}
}
<|endoftext|>