<commit_before>package gorm_test

import (
	"fmt"
	"testing"
)

func TestBelongsTo(t *testing.T) {
	DB.DropTable(Category{}, Post{})
	DB.CreateTable(Category{}, Post{})

	post := Post{
		Title:        "post 1",
		Body:         "body 1",
		Category:     Category{Name: "Category 1"},
		MainCategory: Category{Name: "Main Category 1"},
	}

	if err := DB.Save(&post).Error; err != nil {
		t.Errorf("Got errors when save post", err.Error())
	}

	// Query
	var category Category
	DB.Model(&post).Association("Category").Find(&category)
	if category.Name != "Category 1" {
		t.Errorf("Query has one relations with Association")
	}

	var mainCategory Category
	DB.Model(&post).Association("MainCategory").Find(&mainCategory)
	if mainCategory.Name != "Main Category 1" {
		t.Errorf("Query has one relations with Association")
	}

	var category1 Category
	DB.Model(&post).Related(&category1)
	if category1.Name != "Category 1" {
		t.Errorf("Query has one relations with Related")
	}

	// Append
	var category2 = Category{
		Name: "Category 2",
	}
	DB.Model(&post).Association("Category").Append(&category2)

	if category2.Id == 0 {
		t.Errorf("Category should has ID when created with Append")
	}

	var category21 Category
	DB.Model(&post).Related(&category21)

	if category21.Name != "Category 2" {
		t.Errorf("Category should be updated with Append")
	}

	// Replace
	var category3 = Category{
		Name: "Category 3",
	}
	DB.Model(&post).Association("Category").Replace(&category3)

	if category3.Id == 0 {
		t.Errorf("Category should has ID when created with Replace")
	}

	var category31 Category
	DB.Model(&post).Related(&category31)
	if category31.Name != "Category 3" {
		t.Errorf("Category should be updated with Replace")
	}

	// Delete
	DB.Model(&post).Association("Category").Delete(&category2)
	DB.First(&post, post.Id)
	if DB.Model(&post).Related(&Category{}).RecordNotFound() {
		t.Errorf("Should not delete any category when Delete a unrelated Category")
	}

	DB.Model(&post).Association("Category").Delete(&category3)

	var category41 Category
	DB.Model(&post).Related(&category41)
	if category41.Name != "" {
		t.Errorf("Category should be deleted with Delete")
	}

	// Clear
	DB.Model(&post).Association("Category").Append(&Category{
		Name: "Category 2",
	})

	if DB.Model(&post).Related(&Category{}).RecordNotFound() {
		t.Errorf("Should find category after append")
	}

	DB.Model(&post).Association("Category").Clear()

	if !DB.Model(&post).Related(&Category{}).RecordNotFound() {
		t.Errorf("Should not find any category after Clear")
	}
}

func TestHasOneAndHasManyAssociation(t *testing.T) {
	DB.DropTable(Category{}, Post{}, Comment{})
	DB.CreateTable(Category{}, Post{}, Comment{})

	post := Post{
		Title:        "post 1",
		Body:         "body 1",
		Comments:     []*Comment{{Content: "Comment 1"}, {Content: "Comment 2"}},
		Category:     Category{Name: "Category 1"},
		MainCategory: Category{Name: "Main Category 1"},
	}

	if err := DB.Save(&post).Error; err != nil {
		t.Errorf("Got errors when save post", err.Error())
	}

	if err := DB.First(&Category{}, "name = ?", "Category 1").Error; err != nil {
		t.Errorf("Category should be saved", err.Error())
	}

	var p Post
	DB.First(&p, post.Id)

	if post.CategoryId.Int64 == 0 || p.CategoryId.Int64 == 0 || post.MainCategoryId == 0 || p.MainCategoryId == 0 {
		t.Errorf("Category Id should exist")
	}

	if DB.First(&Comment{}, "content = ?", "Comment 1").Error != nil {
		t.Errorf("Comment 1 should be saved")
	}
	if post.Comments[0].PostId == 0 {
		t.Errorf("Comment Should have post id")
	}

	var comment Comment
	if DB.First(&comment, "content = ?", "Comment 2").Error != nil {
		t.Errorf("Comment 2 should be saved")
	}

	if comment.PostId == 0 {
		t.Errorf("Comment 2 Should have post id")
	}

	comment3 := Comment{Content: "Comment 3", Post: Post{Title: "Title 3", Body: "Body 3"}}
	DB.Save(&comment3)
}

func TestRelated(t *testing.T) {
	user := User{
		Name:            "jinzhu",
		BillingAddress:  Address{Address1: "Billing Address - Address 1"},
		ShippingAddress: Address{Address1: "Shipping Address - Address 1"},
		Emails:          []Email{{Email: "jinzhu@example.com"}, {Email: "jinzhu-2@example@example.com"}},
		CreditCard:      CreditCard{Number: "1234567890"},
		Company:         Company{Name: "company1"},
	}

	DB.Save(&user)

	if user.CreditCard.ID == 0 {
		t.Errorf("After user save, credit card should have id")
	}

	if user.BillingAddress.ID == 0 {
		t.Errorf("After user save, billing address should have id")
	}

	if user.Emails[0].Id == 0 {
		t.Errorf("After user save, billing address should have id")
	}

	var emails []Email
	DB.Model(&user).Related(&emails)
	if len(emails) != 2 {
		t.Errorf("Should have two emails")
	}

	var emails2 []Email
	DB.Model(&user).Where("email = ?", "jinzhu@example.com").Related(&emails2)
	if len(emails2) != 1 {
		t.Errorf("Should have two emails")
	}

	var emails3 []*Email
	DB.Model(&user).Related(&emails3)
	if len(emails3) != 2 {
		t.Errorf("Should have two emails")
	}

	var user1 User
	DB.Model(&user).Related(&user1.Emails)
	if len(user1.Emails) != 2 {
		t.Errorf("Should have only one email match related condition")
	}

	var address1 Address
	DB.Model(&user).Related(&address1, "BillingAddressId")
	if address1.Address1 != "Billing Address - Address 1" {
		t.Errorf("Should get billing address from user correctly")
	}

	user1 = User{}
	DB.Model(&address1).Related(&user1, "BillingAddressId")
	if DB.NewRecord(user1) {
		t.Errorf("Should get user from address correctly")
	}

	var user2 User
	DB.Model(&emails[0]).Related(&user2)
	if user2.Id != user.Id || user2.Name != user.Name {
		t.Errorf("Should get user from email correctly")
	}

	var creditcard CreditCard
	var user3 User
	DB.First(&creditcard, "number = ?", "1234567890")
	DB.Model(&creditcard).Related(&user3)
	if user3.Id != user.Id || user3.Name != user.Name {
		t.Errorf("Should get user from credit card correctly")
	}

	if !DB.Model(&CreditCard{}).Related(&User{}).RecordNotFound() {
		t.Errorf("RecordNotFound for Related")
	}

	var company Company
	if DB.Model(&user).Related(&company, "Company").RecordNotFound() || company.Name != "company1" {
		t.Errorf("RecordNotFound for Related")
	}
}

func TestManyToMany(t *testing.T) {
	DB.Raw("delete from languages")
	var languages = []Language{{Name: "ZH"}, {Name: "EN"}}
	user := User{Name: "Many2Many", Languages: languages}
	DB.Save(&user)

	// Query
	var newLanguages []Language
	DB.Model(&user).Related(&newLanguages, "Languages")
	if len(newLanguages) != len([]string{"ZH", "EN"}) {
		t.Errorf("Query many to many relations")
	}

	DB.Model(&user).Association("Languages").Find(&newLanguages)
	if len(newLanguages) != len([]string{"ZH", "EN"}) {
		t.Errorf("Should be able to find many to many relations")
	}

	if DB.Model(&user).Association("Languages").Count() != len([]string{"ZH", "EN"}) {
		t.Errorf("Count should return correct result")
	}

	// Append
	DB.Model(&user).Association("Languages").Append(&Language{Name: "DE"})
	if DB.Where("name = ?", "DE").First(&Language{}).RecordNotFound() {
		t.Errorf("New record should be saved when append")
	}

	languageA := Language{Name: "AA"}
	DB.Save(&languageA)
	DB.Model(&User{Id: user.Id}).Association("Languages").Append(&languageA)

	languageC := Language{Name: "CC"}
	DB.Save(&languageC)
	DB.Model(&user).Association("Languages").Append(&[]Language{{Name: "BB"}, languageC})

	DB.Model(&User{Id: user.Id}).Association("Languages").Append(&[]Language{{Name: "DD"}, {Name: "EE"}})

	totalLanguages := []string{"ZH", "EN", "DE", "AA", "BB", "CC", "DD", "EE"}

	if DB.Model(&user).Association("Languages").Count() != len(totalLanguages) {
		t.Errorf("All appended languages should be saved")
	}

	// Delete
	user.Languages = []Language{}
	DB.Model(&user).Association("Languages").Find(&user.Languages)

	var language Language
	DB.Where("name = ?", "EE").First(&language)
	DB.Model(&user).Association("Languages").Delete(language, &language)

	if DB.Model(&user).Association("Languages").Count() != len(totalLanguages)-1 || len(user.Languages) != len(totalLanguages)-1 {
		t.Errorf("Relations should be deleted with Delete")
	}
	if DB.Where("name = ?", "EE").First(&Language{}).RecordNotFound() {
		t.Errorf("Language EE should not be deleted")
	}

	DB.Where("name IN (?)", []string{"CC", "DD"}).Find(&languages)

	user2 := User{Name: "Many2Many_User2", Languages: languages}
	DB.Save(&user2)

	DB.Model(&user).Association("Languages").Delete(languages, &languages)
	if DB.Model(&user).Association("Languages").Count() != len(totalLanguages)-3 || len(user.Languages) != len(totalLanguages)-3 {
		t.Errorf("Relations should be deleted with Delete")
	}

	if DB.Model(&user2).Association("Languages").Count() == 0 {
		t.Errorf("Other user's relations should not be deleted")
	}

	// Replace
	var languageB Language
	DB.Where("name = ?", "BB").First(&languageB)
	DB.Model(&user).Association("Languages").Replace(languageB)
	if len(user.Languages) != 1 || DB.Model(&user).Association("Languages").Count() != 1 {
		t.Errorf("Relations should be replaced")
	}

	DB.Model(&user).Association("Languages").Replace()
	if len(user.Languages) != 0 || DB.Model(&user).Association("Languages").Count() != 0 {
		t.Errorf("Relations should be replaced with empty")
	}

	DB.Model(&user).Association("Languages").Replace(&[]Language{{Name: "FF"}, {Name: "JJ"}})
	if len(user.Languages) != 2 || DB.Model(&user).Association("Languages").Count() != len([]string{"FF", "JJ"}) {
		t.Errorf("Relations should be replaced")
	}

	// Clear
	DB.Model(&user).Association("Languages").Clear()
	if len(user.Languages) != 0 || DB.Model(&user).Association("Languages").Count() != 0 {
		t.Errorf("Relations should be cleared")
	}
}

func TestForeignKey(t *testing.T) {
	for _, structField := range DB.NewScope(&User{}).GetStructFields() {
		for _, foreignKey := range []string{"BillingAddressID", "ShippingAddressId", "CompanyID"} {
			if structField.Name == foreignKey && !structField.IsForeignKey {
				t.Errorf(fmt.Sprintf("%v should be foreign key", foreignKey))
			}
		}
	}

	for _, structField := range DB.NewScope(&Email{}).GetStructFields() {
		for _, foreignKey := range []string{"UserId"} {
			if structField.Name == foreignKey && !structField.IsForeignKey {
				t.Errorf(fmt.Sprintf("%v should be foreign key", foreignKey))
			}
		}
	}

	for _, structField := range DB.NewScope(&Post{}).GetStructFields() {
		for _, foreignKey := range []string{"CategoryId", "MainCategoryId"} {
			if structField.Name == foreignKey && !structField.IsForeignKey {
				t.Errorf(fmt.Sprintf("%v should be foreign key", foreignKey))
			}
		}
	}

	for _, structField := range DB.NewScope(&Comment{}).GetStructFields() {
		for _, foreignKey := range []string{"PostId"} {
			if structField.Name == foreignKey && !structField.IsForeignKey {
				t.Errorf(fmt.Sprintf("%v should be foreign key", foreignKey))
			}
		}
	}
}
<commit_msg>Update BelongsTo test<commit_after>package gorm_test

import (
	"fmt"
	"testing"
)

func TestBelongsTo(t *testing.T) {
	DB.DropTable(Category{}, Post{})
	DB.CreateTable(Category{}, Post{})

	post := Post{
		Title:        "post 1",
		Body:         "body 1",
		Category:     Category{Name: "Category 1"},
		MainCategory: Category{Name: "Main Category 1"},
	}

	if err := DB.Save(&post).Error; err != nil {
		t.Errorf("Got errors when save post", err.Error())
	}

	if post.Category.Id == 0 || post.MainCategory.Id == 0 {
		t.Errorf("Category's primary key should be updated")
	}

	if post.CategoryId.Int64 == 0 || post.MainCategoryId == 0 {
		t.Errorf("post's foreign key should be updated")
	}

	// Query
	var category1 Category
	DB.Model(&post).Association("Category").Find(&category1)
	if category1.Name != "Category 1" {
		t.Errorf("Query has one relations with Association")
	}

	var mainCategory1 Category
	DB.Model(&post).Association("MainCategory").Find(&mainCategory1)
	if mainCategory1.Name != "Main Category 1" {
		t.Errorf("Query has one relations with Association")
	}

	var category11 Category
	DB.Model(&post).Related(&category11)
	if category11.Name != "Category 1" {
		t.Errorf("Query has one relations with Related")
	}

	// Append
	var category2 = Category{
		Name: "Category 2",
	}
	DB.Model(&post).Association("Category").Append(&category2)

	if category2.Id == 0 {
		t.Errorf("Category should has ID when created with Append")
	}

	var category21 Category
	DB.Model(&post).Related(&category21)

	if category21.Name != "Category 2" {
		t.Errorf("Category should be updated with Append")
	}

	// Replace
	var category3 = Category{
		Name: "Category 3",
	}
	DB.Model(&post).Association("Category").Replace(&category3)

	if category3.Id == 0 {
		t.Errorf("Category should has ID when created with Replace")
	}

	var category31 Category
	DB.Model(&post).Related(&category31)
	if category31.Name != "Category 3" {
		t.Errorf("Category should be updated with Replace")
	}

	// Delete
	DB.Model(&post).Association("Category").Delete(&category2)
	DB.First(&post, post.Id)
	if DB.Model(&post).Related(&Category{}).RecordNotFound() {
		t.Errorf("Should not delete any category when Delete a unrelated Category")
	}

	DB.Model(&post).Association("Category").Delete(&category3)

	var category41 Category
	DB.Model(&post).Related(&category41)
	if category41.Name != "" {
		t.Errorf("Category should be deleted with Delete")
	}

	// Clear
	DB.Model(&post).Association("Category").Append(&Category{
		Name: "Category 2",
	})

	if DB.Model(&post).Related(&Category{}).RecordNotFound() {
		t.Errorf("Should find category after append")
	}

	DB.Model(&post).Association("Category").Clear()

	if !DB.Model(&post).Related(&Category{}).RecordNotFound() {
		t.Errorf("Should not find any category after Clear")
	}
}

func TestHasMany(t *testing.T) {
	DB.DropTable(Post{}, Comment{})
	DB.CreateTable(Post{}, Comment{})

	post := Post{
		Title:    "post 1",
		Body:     "body 1",
		Comments: []*Comment{{Content: "Comment 1"}, {Content: "Comment 2"}},
	}

	if err := DB.Save(&post).Error; err != nil {
		t.Errorf("Got errors when save post", err.Error())
	}

	// Query
	// Append
	// Delete
	// Replace
	// Clear
}

func TestHasOneAndHasManyAssociation(t *testing.T) {
	DB.DropTable(Category{}, Post{}, Comment{})
	DB.CreateTable(Category{}, Post{}, Comment{})

	post := Post{
		Title:        "post 1",
		Body:         "body 1",
		Comments:     []*Comment{{Content: "Comment 1"}, {Content: "Comment 2"}},
		Category:     Category{Name: "Category 1"},
		MainCategory: Category{Name: "Main Category 1"},
	}

	if err := DB.Save(&post).Error; err != nil {
		t.Errorf("Got errors when save post", err.Error())
	}

	if err := DB.First(&Category{}, "name = ?", "Category 1").Error; err != nil {
		t.Errorf("Category should be saved", err.Error())
	}

	var p Post
	DB.First(&p, post.Id)

	if post.CategoryId.Int64 == 0 || p.CategoryId.Int64 == 0 || post.MainCategoryId == 0 || p.MainCategoryId == 0 {
		t.Errorf("Category Id should exist")
	}

	if DB.First(&Comment{}, "content = ?", "Comment 1").Error != nil {
		t.Errorf("Comment 1 should be saved")
	}
	if post.Comments[0].PostId == 0 {
		t.Errorf("Comment Should have post id")
	}

	var comment Comment
	if DB.First(&comment, "content = ?", "Comment 2").Error != nil {
		t.Errorf("Comment 2 should be saved")
	}

	if comment.PostId == 0 {
		t.Errorf("Comment 2 Should have post id")
	}

	comment3 := Comment{Content: "Comment 3", Post: Post{Title: "Title 3", Body: "Body 3"}}
	DB.Save(&comment3)
}

func TestRelated(t *testing.T) {
	user := User{
		Name:            "jinzhu",
		BillingAddress:  Address{Address1: "Billing Address - Address 1"},
		ShippingAddress: Address{Address1: "Shipping Address - Address 1"},
		Emails:          []Email{{Email: "jinzhu@example.com"}, {Email: "jinzhu-2@example@example.com"}},
		CreditCard:      CreditCard{Number: "1234567890"},
		Company:         Company{Name: "company1"},
	}

	DB.Save(&user)

	if user.CreditCard.ID == 0 {
		t.Errorf("After user save, credit card should have id")
	}

	if user.BillingAddress.ID == 0 {
		t.Errorf("After user save, billing address should have id")
	}

	if user.Emails[0].Id == 0 {
		t.Errorf("After user save, billing address should have id")
	}

	var emails []Email
	DB.Model(&user).Related(&emails)
	if len(emails) != 2 {
		t.Errorf("Should have two emails")
	}

	var emails2 []Email
	DB.Model(&user).Where("email = ?", "jinzhu@example.com").Related(&emails2)
	if len(emails2) != 1 {
		t.Errorf("Should have two emails")
	}

	var emails3 []*Email
	DB.Model(&user).Related(&emails3)
	if len(emails3) != 2 {
		t.Errorf("Should have two emails")
	}

	var user1 User
	DB.Model(&user).Related(&user1.Emails)
	if len(user1.Emails) != 2 {
		t.Errorf("Should have only one email match related condition")
	}

	var address1 Address
	DB.Model(&user).Related(&address1, "BillingAddressId")
	if address1.Address1 != "Billing Address - Address 1" {
		t.Errorf("Should get billing address from user correctly")
	}

	user1 = User{}
	DB.Model(&address1).Related(&user1, "BillingAddressId")
	if DB.NewRecord(user1) {
		t.Errorf("Should get user from address correctly")
	}

	var user2 User
	DB.Model(&emails[0]).Related(&user2)
	if user2.Id != user.Id || user2.Name != user.Name {
		t.Errorf("Should get user from email correctly")
	}

	var creditcard CreditCard
	var user3 User
	DB.First(&creditcard, "number = ?", "1234567890")
	DB.Model(&creditcard).Related(&user3)
	if user3.Id != user.Id || user3.Name != user.Name {
		t.Errorf("Should get user from credit card correctly")
	}

	if !DB.Model(&CreditCard{}).Related(&User{}).RecordNotFound() {
		t.Errorf("RecordNotFound for Related")
	}

	var company Company
	if DB.Model(&user).Related(&company, "Company").RecordNotFound() || company.Name != "company1" {
		t.Errorf("RecordNotFound for Related")
	}
}

func TestManyToMany(t *testing.T) {
	DB.Raw("delete from languages")
	var languages = []Language{{Name: "ZH"}, {Name: "EN"}}
	user := User{Name: "Many2Many", Languages: languages}
	DB.Save(&user)

	// Query
	var newLanguages []Language
	DB.Model(&user).Related(&newLanguages, "Languages")
	if len(newLanguages) != len([]string{"ZH", "EN"}) {
		t.Errorf("Query many to many relations")
	}

	DB.Model(&user).Association("Languages").Find(&newLanguages)
	if len(newLanguages) != len([]string{"ZH", "EN"}) {
		t.Errorf("Should be able to find many to many relations")
	}

	if DB.Model(&user).Association("Languages").Count() != len([]string{"ZH", "EN"}) {
		t.Errorf("Count should return correct result")
	}

	// Append
	DB.Model(&user).Association("Languages").Append(&Language{Name: "DE"})
	if DB.Where("name = ?", "DE").First(&Language{}).RecordNotFound() {
		t.Errorf("New record should be saved when append")
	}

	languageA := Language{Name: "AA"}
	DB.Save(&languageA)
	DB.Model(&User{Id: user.Id}).Association("Languages").Append(&languageA)

	languageC := Language{Name: "CC"}
	DB.Save(&languageC)
	DB.Model(&user).Association("Languages").Append(&[]Language{{Name: "BB"}, languageC})

	DB.Model(&User{Id: user.Id}).Association("Languages").Append(&[]Language{{Name: "DD"}, {Name: "EE"}})

	totalLanguages := []string{"ZH", "EN", "DE", "AA", "BB", "CC", "DD", "EE"}

	if DB.Model(&user).Association("Languages").Count() != len(totalLanguages) {
		t.Errorf("All appended languages should be saved")
	}

	// Delete
	user.Languages = []Language{}
	DB.Model(&user).Association("Languages").Find(&user.Languages)

	var language Language
	DB.Where("name = ?", "EE").First(&language)
	DB.Model(&user).Association("Languages").Delete(language, &language)

	if DB.Model(&user).Association("Languages").Count() != len(totalLanguages)-1 || len(user.Languages) != len(totalLanguages)-1 {
		t.Errorf("Relations should be deleted with Delete")
	}
	if DB.Where("name = ?", "EE").First(&Language{}).RecordNotFound() {
		t.Errorf("Language EE should not be deleted")
	}

	DB.Where("name IN (?)", []string{"CC", "DD"}).Find(&languages)

	user2 := User{Name: "Many2Many_User2", Languages: languages}
	DB.Save(&user2)

	DB.Model(&user).Association("Languages").Delete(languages, &languages)
	if DB.Model(&user).Association("Languages").Count() != len(totalLanguages)-3 || len(user.Languages) != len(totalLanguages)-3 {
		t.Errorf("Relations should be deleted with Delete")
	}

	if DB.Model(&user2).Association("Languages").Count() == 0 {
		t.Errorf("Other user's relations should not be deleted")
	}

	// Replace
	var languageB Language
	DB.Where("name = ?", "BB").First(&languageB)
	DB.Model(&user).Association("Languages").Replace(languageB)
	if len(user.Languages) != 1 || DB.Model(&user).Association("Languages").Count() != 1 {
		t.Errorf("Relations should be replaced")
	}

	DB.Model(&user).Association("Languages").Replace()
	if len(user.Languages) != 0 || DB.Model(&user).Association("Languages").Count() != 0 {
		t.Errorf("Relations should be replaced with empty")
	}

	DB.Model(&user).Association("Languages").Replace(&[]Language{{Name: "FF"}, {Name: "JJ"}})
	if len(user.Languages) != 2 || DB.Model(&user).Association("Languages").Count() != len([]string{"FF", "JJ"}) {
		t.Errorf("Relations should be replaced")
	}

	// Clear
	DB.Model(&user).Association("Languages").Clear()
	if len(user.Languages) != 0 || DB.Model(&user).Association("Languages").Count() != 0 {
		t.Errorf("Relations should be cleared")
	}
}

func TestForeignKey(t *testing.T) {
	for _, structField := range DB.NewScope(&User{}).GetStructFields() {
		for _, foreignKey := range []string{"BillingAddressID", "ShippingAddressId", "CompanyID"} {
			if structField.Name == foreignKey && !structField.IsForeignKey {
				t.Errorf(fmt.Sprintf("%v should be foreign key", foreignKey))
			}
		}
	}

	for _, structField := range DB.NewScope(&Email{}).GetStructFields() {
		for _, foreignKey := range []string{"UserId"} {
			if structField.Name == foreignKey && !structField.IsForeignKey {
				t.Errorf(fmt.Sprintf("%v should be foreign key", foreignKey))
			}
		}
	}

	for _, structField := range DB.NewScope(&Post{}).GetStructFields() {
		for _, foreignKey := range []string{"CategoryId", "MainCategoryId"} {
			if structField.Name == foreignKey && !structField.IsForeignKey {
				t.Errorf(fmt.Sprintf("%v should be foreign key", foreignKey))
			}
		}
	}

	for _, structField := range DB.NewScope(&Comment{}).GetStructFields() {
		for _, foreignKey := range []string{"PostId"} {
			if structField.Name == foreignKey && !structField.IsForeignKey {
				t.Errorf(fmt.Sprintf("%v should be foreign key", foreignKey))
			}
		}
	}
}
<|endoftext|>


<commit_before>package audio

import (
	"sync"
	"time"
)

type realtimeStream struct {
	stream       Stream
	lastError    error
	buffer       []int32
	readPosition int
	usageLock    *sync.Mutex
}

// NewRealtimeStream converts a stream into a buffered stream for use in
// realtime applications, such as audio over a network.
func NewRealtimeStream(stream Stream, bufferSize int) Stream {
	newStream := &realtimeStream{
		stream:       stream,
		lastError:    nil,
		buffer:       make([]int32, bufferSize),
		readPosition: bufferSize,
		usageLock:    new(sync.Mutex),
	}

	go newStream.run()
	return newStream
}

func (r *realtimeStream) run() {
	buffer := make([]int32, 1024)
	for {
		n, err := r.stream.Read(buffer)
		r.usageLock.Lock()
		r.buffer = append(r.buffer[n:], buffer[:n]...)

		r.readPosition -= n
		if r.readPosition < 0 {
			r.readPosition = len(r.buffer) / 2
		}

		if err != nil {
			r.lastError = err
			r.usageLock.Unlock()
			return
		}
		r.usageLock.Unlock()
	}
}

func (r *realtimeStream) Read(dst interface{}) (int, error) {
	dstLen := SliceLength(dst)
	r.usageLock.Lock()
	if dstLen > len(r.buffer)/2 {
		r.usageLock.Unlock()
		return 0, ErrBufferTooLarge
	}
	r.usageLock.Unlock()

	for {
		r.usageLock.Lock()
		available := (len(r.buffer) - r.readPosition)
		if available >= dstLen || r.lastError != nil {
			if dstLen > available {
				err := ReadFromInt32(dst, r.buffer[r.readPosition:], available)
				r.readPosition += available
				if r.lastError != nil {
					r.usageLock.Unlock()
					return available, r.lastError
				}

				r.usageLock.Unlock()
				return available, err
			}

			err := ReadFromInt32(dst, r.buffer[r.readPosition:], dstLen)
			r.readPosition += dstLen
			if r.lastError != nil {
				r.usageLock.Unlock()
				return available, r.lastError
			}

			r.usageLock.Unlock()
			return dstLen, err
		}

		r.usageLock.Unlock()
		time.Sleep(time.Millisecond * 10)
	}
}

func (r *realtimeStream) SampleRate() int {
	return r.stream.SampleRate()
}
<commit_msg>Do not ErrBufferTooLarge like who thought that was a good idea???<commit_after>package audio

import (
	"sync"
	"time"
)

type realtimeStream struct {
	stream       Stream
	lastError    error
	buffer       []int32
	readPosition int
	usageLock    *sync.Mutex
}

// NewRealtimeStream converts a stream into a buffered stream for use in
// realtime applications, such as audio over a network.
func NewRealtimeStream(stream Stream, bufferSize int) Stream {
	newStream := &realtimeStream{
		stream:       stream,
		lastError:    nil,
		buffer:       make([]int32, bufferSize),
		readPosition: bufferSize,
		usageLock:    new(sync.Mutex),
	}

	go newStream.run()
	return newStream
}

func (r *realtimeStream) run() {
	buffer := make([]int32, 1024)
	for {
		n, err := r.stream.Read(buffer)
		r.usageLock.Lock()
		r.buffer = append(r.buffer[n:], buffer[:n]...)

		r.readPosition -= n
		if r.readPosition < 0 {
			r.readPosition = len(r.buffer) / 2
		}

		if err != nil {
			r.lastError = err
			r.usageLock.Unlock()
			return
		}
		r.usageLock.Unlock()
	}
}

func (r *realtimeStream) Read(dst interface{}) (int, error) {
	dstLen := SliceLength(dst)
	r.usageLock.Lock()
	if dstLen > len(r.buffer)/2 {
		dstLen = len(r.buffer) / 2
	}
	r.usageLock.Unlock()

	for {
		r.usageLock.Lock()
		available := (len(r.buffer) - r.readPosition)
		if available >= dstLen || r.lastError != nil {
			if dstLen > available {
				err := ReadFromInt32(dst, r.buffer[r.readPosition:], available)
				r.readPosition += available
				if r.lastError != nil {
					r.usageLock.Unlock()
					return available, r.lastError
				}

				r.usageLock.Unlock()
				return available, err
			}

			err := ReadFromInt32(dst, r.buffer[r.readPosition:], dstLen)
			r.readPosition += dstLen
			if r.lastError != nil {
				r.usageLock.Unlock()
				return available, r.lastError
			}

			r.usageLock.Unlock()
			return dstLen, err
		}

		r.usageLock.Unlock()
		time.Sleep(time.Millisecond * 10)
	}
}

func (r *realtimeStream) SampleRate() int {
	return r.stream.SampleRate()
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"context"
	"fmt"
	"io/ioutil"
	"regexp"
	"time"

	"github.com/blang/semver"

	"github.com/ovh/cds/sdk"
	"github.com/ovh/cds/sdk/log"
	"github.com/ovh/cds/sdk/vcs/git"
)

func runGitTag(w *currentWorker) BuiltInAction {
	return func(ctx context.Context, a *sdk.Action, buildID int64, params *[]sdk.Parameter, sendLog LoggerFunc) sdk.Result {
		tagPrerelease := sdk.ParameterFind(&a.Parameters, "tagPrerelease")
		tagMetadata := sdk.ParameterFind(&a.Parameters, "tagMetadata")
		tagLevel := sdk.ParameterFind(&a.Parameters, "tagLevel")
		tagMessage := sdk.ParameterFind(&a.Parameters, "tagMessage")
		path := sdk.ParameterFind(&a.Parameters, "path")

		tagLevelValid := true
		if tagLevel == nil || tagLevel.Value == "" {
			tagLevelValid = false
		} else if tagLevel.Value != "major" && tagLevel.Value != "minor" && tagLevel.Value != "patch" {
			tagLevelValid = false
		}

		if !tagLevelValid {
			res := sdk.Result{
				Status: sdk.StatusFail.String(),
				Reason: "Tag level is mandatory. It must be: 'major' or 'minor' or 'patch'",
			}
			sendLog(res.Reason)
			return res
		}

		gitURL, auth, errR := extractVCSInformations(*params)
		if errR != nil {
			res := sdk.Result{
				Status: sdk.StatusFail.String(),
				Reason: errR.Error(),
			}
			sendLog(res.Reason)
			return res
		}

		var msg = ""
		if tagMessage != nil {
			msg = tagMessage.Value
		}

		cdsSemver := sdk.ParameterFind(params, "cds.semver")
		if cdsSemver == nil || cdsSemver.Value == "" {
			res := sdk.Result{
				Status: sdk.StatusFail.String(),
				Reason: fmt.Sprintf("cds.semver is empty"),
			}
			sendLog(res.Reason)
			return res
		}

		smver, errT := semver.Make(cdsSemver.Value)
		if errT != nil {
			res := sdk.Result{
				Status: sdk.StatusFail.String(),
				Reason: fmt.Sprintf("cds.version '%s' is not semver compatible", cdsSemver.Value),
			}
			sendLog(res.Reason)
			return res
		}
		smver.Build = nil
		smver.Pre = nil

		switch tagLevel.Value {
		case "major":
			smver.Major++
		case "minor":
			smver.Minor++
		default:
			smver.Patch++
		}

		r, _ := regexp.Compile("^([0-9A-Za-z\\-.]+)$")
		// prerelease version notes: example: alpha, rc-1, ...
		if tagPrerelease != nil && tagPrerelease.Value != "" {
			if !r.MatchString(tagPrerelease.Value) {
				res := sdk.Result{
					Status: sdk.StatusFail.String(),
					Reason: fmt.Sprintf("tagPrerelease '%s' must comprise only ASCII alphanumerics and hyphen [0-9A-Za-z-.].", tagPrerelease.Value),
				}
				sendLog(res.Reason)
				return res
			} else {
				smver.Pre = []semver.PRVersion{{VersionStr: tagPrerelease.Value}}
			}
		}

		// metadata: this content is after '+'
		if tagMetadata != nil && tagMetadata.Value != "" {
			if !r.MatchString(tagMetadata.Value) {
				res := sdk.Result{
					Status: sdk.StatusFail.String(),
					Reason: fmt.Sprintf("tagMetadata '%s' must comprise only ASCII alphanumerics and hyphen [0-9A-Za-z-.].", tagMetadata.Value),
				}
				sendLog(res.Reason)
				return res
			} else {
				smver.Build = []string{tagMetadata.Value}
			}
		}

		var userTag string
		userTrig := sdk.ParameterFind(params, "cds.triggered_by.username")
		if userTrig != nil && userTrig.Value != "" {
			userTag = userTrig.Value
		} else {
			gitAuthor := sdk.ParameterFind(params, "git.author")
			if gitAuthor != nil && gitAuthor.Value != "" {
				userTag = gitAuthor.Value
			}
		}

		if userTag == "" {
			res := sdk.Result{
				Status: sdk.StatusFail.String(),
				Reason: "No user find to perform tag",
			}
			sendLog(res.Reason)
			return res
		}

		//Prepare all options - tag options
		var tagOpts = &git.TagOpts{
			Message:  msg,
			Name:     smver.String(),
			Username: userTag,
		}

		if auth.SignKey.ID != "" {
			tagOpts.SignKey = auth.SignKey.Private
			tagOpts.SignID = auth.SignKey.ID

			if err := ioutil.WriteFile("pgp.pub.key", []byte(auth.SignKey.Public), 0600); err != nil {
				res := sdk.Result{
					Status: sdk.StatusFail.String(),
					Reason: "Cannot create pgp key file.",
				}
				sendLog(res.Reason)
				return res
			}
			if err := ioutil.WriteFile("pgp.key", []byte(tagOpts.SignKey), 0600); err != nil {
				res := sdk.Result{
					Status: sdk.StatusFail.String(),
					Reason: "Cannot create pgp key file.",
				}
				sendLog(res.Reason)
				return res
			}
		}

		// Run Git command

		//Prepare all options - logs
		stdErr := new(bytes.Buffer)
		stdOut := new(bytes.Buffer)

		output := &git.OutputOpts{
			Stderr: stdErr,
			Stdout: stdOut,
		}

		git.LogFunc = log.Info

		if path != nil {
			tagOpts.Path = path.Value
		}

		//Perform the git tag
		err := git.TagCreate(gitURL, auth, tagOpts, output)

		//Send the logs
		if len(stdOut.Bytes()) > 0 {
			sendLog(stdOut.String())
		}
		if len(stdErr.Bytes()) > 0 {
			sendLog(stdErr.String())
		}

		if err != nil {
			res := sdk.Result{
				Status: sdk.StatusFail.String(),
				Reason: fmt.Sprintf("Unable to git tag: %s", err),
			}
			sendLog(res.Reason)
			return res
		}

		semverVar := sdk.Variable{
			Name:  "cds.release.version",
			Type:  sdk.StringVariable,
			Value: tagOpts.Name,
		}
		_, errV := w.addVariableInPipelineBuild(semverVar, params)
		if errV != nil {
			res := sdk.Result{
				Status: sdk.StatusFail.String(),
				Reason: fmt.Sprintf("Unable to save semver variable: %s", errV),
			}
			sendLog(res.Reason)
			return res
		}
		time.Sleep(5 * time.Second)
		return sdk.Result{Status: sdk.StatusSuccess.String()}
	}
}
<commit_msg>fix(worker): lint (#2725)<commit_after>package main

import (
	"bytes"
	"context"
	"fmt"
	"io/ioutil"
	"regexp"
	"time"

	"github.com/blang/semver"

	"github.com/ovh/cds/sdk"
	"github.com/ovh/cds/sdk/log"
	"github.com/ovh/cds/sdk/vcs/git"
)

func runGitTag(w *currentWorker) BuiltInAction {
	return func(ctx context.Context, a *sdk.Action, buildID int64, params *[]sdk.Parameter, sendLog LoggerFunc) sdk.Result {
		tagPrerelease := sdk.ParameterFind(&a.Parameters, "tagPrerelease")
		tagMetadata := sdk.ParameterFind(&a.Parameters, "tagMetadata")
		tagLevel := sdk.ParameterFind(&a.Parameters, "tagLevel")
		tagMessage := sdk.ParameterFind(&a.Parameters, "tagMessage")
		path := sdk.ParameterFind(&a.Parameters, "path")

		tagLevelValid := true
		if tagLevel == nil || tagLevel.Value == "" {
			tagLevelValid = false
		} else if tagLevel.Value != "major" && tagLevel.Value != "minor" && tagLevel.Value != "patch" {
			tagLevelValid = false
		}

		if !tagLevelValid {
			res := sdk.Result{
				Status: sdk.StatusFail.String(),
				Reason: "Tag level is mandatory. It must be: 'major' or 'minor' or 'patch'",
			}
			sendLog(res.Reason)
			return res
		}

		gitURL, auth, errR := extractVCSInformations(*params)
		if errR != nil {
			res := sdk.Result{
				Status: sdk.StatusFail.String(),
				Reason: errR.Error(),
			}
			sendLog(res.Reason)
			return res
		}

		var msg = ""
		if tagMessage != nil {
			msg = tagMessage.Value
		}

		cdsSemver := sdk.ParameterFind(params, "cds.semver")
		if cdsSemver == nil || cdsSemver.Value == "" {
			res := sdk.Result{
				Status: sdk.StatusFail.String(),
				Reason: fmt.Sprintf("cds.semver is empty"),
			}
			sendLog(res.Reason)
			return res
		}

		smver, errT := semver.Make(cdsSemver.Value)
		if errT != nil {
			res := sdk.Result{
				Status: sdk.StatusFail.String(),
				Reason: fmt.Sprintf("cds.version '%s' is not semver compatible", cdsSemver.Value),
			}
			sendLog(res.Reason)
			return res
		}
		smver.Build = nil
		smver.Pre = nil

		switch tagLevel.Value {
		case "major":
			smver.Major++
		case "minor":
			smver.Minor++
		default:
			smver.Patch++
		}

		r, _ := regexp.Compile("^([0-9A-Za-z\\-.]+)$")
		// prerelease version notes: example: alpha, rc-1, ...
		if tagPrerelease != nil && tagPrerelease.Value != "" {
			if !r.MatchString(tagPrerelease.Value) {
				res := sdk.Result{
					Status: sdk.StatusFail.String(),
					Reason: fmt.Sprintf("tagPrerelease '%s' must comprise only ASCII alphanumerics and hyphen [0-9A-Za-z-.].", tagPrerelease.Value),
				}
				sendLog(res.Reason)
				return res
			}
			smver.Pre = []semver.PRVersion{{VersionStr: tagPrerelease.Value}}
		}

		// metadata: this content is after '+'
		if tagMetadata != nil && tagMetadata.Value != "" {
			if !r.MatchString(tagMetadata.Value) {
				res := sdk.Result{
					Status: sdk.StatusFail.String(),
					Reason: fmt.Sprintf("tagMetadata '%s' must comprise only ASCII alphanumerics and hyphen [0-9A-Za-z-.].", tagMetadata.Value),
				}
				sendLog(res.Reason)
				return res
			}
			smver.Build = []string{tagMetadata.Value}
		}

		var userTag string
		userTrig := sdk.ParameterFind(params, "cds.triggered_by.username")
		if userTrig != nil && userTrig.Value != "" {
			userTag = userTrig.Value
		} else {
			gitAuthor := sdk.ParameterFind(params, "git.author")
			if gitAuthor != nil && gitAuthor.Value != "" {
				userTag = gitAuthor.Value
			}
		}

		if userTag == "" {
			res := sdk.Result{
				Status: sdk.StatusFail.String(),
				Reason: "No user find to perform tag",
			}
			sendLog(res.Reason)
			return res
		}

		//Prepare all options - tag options
		var tagOpts = &git.TagOpts{
			Message:  msg,
			Name:     smver.String(),
			Username: userTag,
		}

		if auth.SignKey.ID != "" {
			tagOpts.SignKey = auth.SignKey.Private
			tagOpts.SignID = auth.SignKey.ID

			if err := ioutil.WriteFile("pgp.pub.key", []byte(auth.SignKey.Public), 0600); err != nil {
				res := sdk.Result{
					Status: sdk.StatusFail.String(),
					Reason: "Cannot create pgp key file.",
				}
				sendLog(res.Reason)
				return res
			}
			if err := ioutil.WriteFile("pgp.key", []byte(tagOpts.SignKey), 0600); err != nil {
				res := sdk.Result{
					Status: sdk.StatusFail.String(),
					Reason: "Cannot create pgp key file.",
				}
				sendLog(res.Reason)
				return res
			}
		}

		// Run Git command

		//Prepare all options - logs
		stdErr := new(bytes.Buffer)
		stdOut := new(bytes.Buffer)

		output := &git.OutputOpts{
			Stderr: stdErr,
			Stdout: stdOut,
		}

		git.LogFunc = log.Info

		if path != nil {
			tagOpts.Path = path.Value
		}

		//Perform the git tag
		err := git.TagCreate(gitURL, auth, tagOpts, output)

		//Send the logs
		if len(stdOut.Bytes()) > 0 {
			sendLog(stdOut.String())
		}
		if len(stdErr.Bytes()) > 0 {
			sendLog(stdErr.String())
		}

		if err != nil {
			res := sdk.Result{
				Status: sdk.StatusFail.String(),
				Reason: fmt.Sprintf("Unable to git tag: %s", err),
			}
			sendLog(res.Reason)
			return res
		}

		semverVar := sdk.Variable{
			Name:  "cds.release.version",
			Type:  sdk.StringVariable,
			Value: tagOpts.Name,
		}
		_, errV := w.addVariableInPipelineBuild(semverVar, params)
		if errV != nil {
			res := sdk.Result{
				Status: sdk.StatusFail.String(),
				Reason: fmt.Sprintf("Unable to save semver variable: %s", errV),
			}
			sendLog(res.Reason)
			return res
		}
		time.Sleep(5 * time.Second)
		return sdk.Result{Status: sdk.StatusSuccess.String()}
	}
}
<|endoftext|>


<commit_before>// Copyright 2013 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package backend

import (
	"code.google.com/p/log4go"
	"strings"
)

type (
	// An event callback dealing with View events.
	ViewEventCallback func(v *View)
	// A ViewEvent is simply a bunch of ViewEventCallbacks.
	ViewEvent []ViewEventCallback

	// The return value returned from a QueryContextCallback.
	QueryContextReturn int

	// The context is queried when trying to figure out what action should be performed when
	// certain conditions are met.
	//
	// Context is just a string identifier, an optional comparison operator, an optional operand, and an optional
	// match_all boolean. The data of the context is optionally provided together with a key binding and the key's
	// action will only be considered if the context conditions are met.
	//
	// Exactly how these values are interpreted is up to the individual context handlers, which may be fully
	// customized by implementing the callback in a plugin.
	//
	// For instance pressing the key 'j' will have a different meaning when in a VI command mode emulation
	// and when in a VI insert mode emulation. A plugin would then define two key binding entries for 'j',
	// describe the key binding context to be able to discern which action is appropriate when 'j' is then pressed.
	QueryContextCallback func(v *View, key string, operator Op, operand interface{}, match_all bool) QueryContextReturn

	// A QueryContextEvent is simply a bunch of QueryContextCallbacks.
	QueryContextEvent []QueryContextCallback

	// A WindowEventCallback deals with Window events.
	WindowEventCallback func(w *Window)
	// A WindowEvent is simply a bunch of WindowEventCallbacks.
	WindowEvent []WindowEventCallback
)

const (
	True    QueryContextReturn = iota //< Returned when the context query matches.
	False                             //< Returned when the context query does not match.
	Unknown                           //< Returned when the QueryContextCallback does not know how to deal with the given context.
)

// Add the provided ViewEventCallback to this ViewEvent
// TODO(.): Support removing ViewEventCallbacks?
func (ve *ViewEvent) Add(cb ViewEventCallback) {
	*ve = append(*ve, cb)
}

// Trigger this ViewEvent by calling all the registered callbacks in order of registration.
func (ve ViewEvent) Call(v *View) {
	log4go.Finest("ViewEvent")
	for i := range ve {
		ve[i](v)
	}
}

// Add the provided QueryContextCallback to the QueryContextEvent.
// TODO(.): Support removing QueryContextCallbacks?
func (qe *QueryContextEvent) Add(cb QueryContextCallback) {
	*qe = append(*qe, cb)
}

// Searches for a QueryContextCallback and returns the result of the first callback being able to deal with this
// context, or Unknown if no such callback was found.
func (qe QueryContextEvent) Call(v *View, key string, operator Op, operand interface{}, match_all bool) QueryContextReturn {
	log4go.Fine("Query context: %s, %v, %v, %v", key, operator, operand, match_all)
	for i := range qe {
		r := qe[i](v, key, operator, operand, match_all)
		if r != Unknown {
			return r
		}
	}
	log4go.Fine("Unknown context: %s", key)
	return Unknown
}

// Add the provided WindowEventCallback to this WindowEvent.
// TODO(.): Support removing WindowEventCallbacks?
func (we *WindowEvent) Add(cb WindowEventCallback) {
	*we = append(*we, cb)
}

// Trigger this WindowEvent by calling all the registered callbacks in order of registration.
func (we WindowEvent) Call(w *Window) {
	log4go.Finest("WindowEvent")
	for i := range we {
		we[i](w)
	}
}

var (
	OnNew               ViewEvent //< Called when a new view is created
	OnLoad              ViewEvent //< Called when loading a view's buffer has finished
	OnActivated         ViewEvent //< Called when a view gains input focus.
	OnDeactivated       ViewEvent //< Called when a view loses input focus.
	OnPreClose          ViewEvent //< Called when a view is about to be closed.
	OnClose             ViewEvent //< Called when a view has been closed.
	OnPreSave           ViewEvent //< Called just before a view's buffer is saved.
	OnPostSave          ViewEvent //< Called after a view's buffer has been saved.
	OnModified          ViewEvent //< Called when the contents of a view's underlying buffer has changed.
	OnSelectionModified ViewEvent //< Called when a view's Selection/cursor has changed.

	OnNewWindow    WindowEvent       //< Called when a new window has been created.
	OnQueryContext QueryContextEvent //< Called when context is being queried.
)

func init() {
	// Register functionality dealing with a couple of built in contexts
	OnQueryContext.Add(func(v *View, key string, operator Op, operand interface{}, match_all bool) QueryContextReturn {
		if strings.HasPrefix(key, "setting.") && operator == OpEqual {
			c, ok := v.Settings().Get(key[8:]).(bool)
			if c && ok {
				return True
			}
			return False
		} else if key == "num_selections" {
			opf, _ := operand.(float64)
			op := int(opf)

			switch operator {
			case OpEqual:
				if op == v.Sel().Len() {
					return True
				}
				return False
			case OpNotEqual:
				if op != v.Sel().Len() {
					return True
				}
				return False
			}
		}
		return Unknown
	})

	OnLoad.Add(func(view *View) {
		editor := GetEditor()
		editor.Watch(NewWatchedUserFile(view))
	})
}
<commit_msg>backend: Add lookup tables for event names<commit_after>// Copyright 2013 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package backend

import (
	"code.google.com/p/log4go"
	"strings"
)

type (
	// An event callback dealing with View events.
	ViewEventCallback func(v *View)
	// A ViewEvent is simply a bunch of ViewEventCallbacks.
	ViewEvent []ViewEventCallback

	// The return value returned from a QueryContextCallback.
	QueryContextReturn int

	// The context is queried when trying to figure out what action should be performed when
	// certain conditions are met.
	//
	// Context is just a string identifier, an optional comparison operator, an optional operand, and an optional
	// match_all boolean. The data of the context is optionally provided together with a key binding and the key's
	// action will only be considered if the context conditions are met.
	//
	// Exactly how these values are interpreted is up to the individual context handlers, which may be fully
	// customized by implementing the callback in a plugin.
	//
	// For instance pressing the key 'j' will have a different meaning when in a VI command mode emulation
	// and when in a VI insert mode emulation. A plugin would then define two key binding entries for 'j',
	// describe the key binding context to be able to discern which action is appropriate when 'j' is then pressed.
	QueryContextCallback func(v *View, key string, operator Op, operand interface{}, match_all bool) QueryContextReturn

	// A QueryContextEvent is simply a bunch of QueryContextCallbacks.
	QueryContextEvent []QueryContextCallback

	// A WindowEventCallback deals with Window events.
	WindowEventCallback func(w *Window)
	// A WindowEvent is simply a bunch of WindowEventCallbacks.
	WindowEvent []WindowEventCallback
)

const (
	True    QueryContextReturn = iota //< Returned when the context query matches.
	False                             //< Returned when the context query does not match.
	Unknown                           //< Returned when the QueryContextCallback does not know how to deal with the given context.
)

// Add the provided ViewEventCallback to this ViewEvent
// TODO(.): Support removing ViewEventCallbacks?
func (ve *ViewEvent) Add(cb ViewEventCallback) {
	*ve = append(*ve, cb)
}

// Trigger this ViewEvent by calling all the registered callbacks in order of registration.
func (ve *ViewEvent) Call(v *View) {
	log4go.Finest("%s(%v)", evNames[ve], v.Id())
	for _, ev := range *ve {
		ev(v)
	}
}

// Add the provided QueryContextCallback to the QueryContextEvent.
// TODO(.): Support removing QueryContextCallbacks?
func (qe *QueryContextEvent) Add(cb QueryContextCallback) {
	*qe = append(*qe, cb)
}

// Searches for a QueryContextCallback and returns the result of the first callback being able to deal with this
// context, or Unknown if no such callback was found.
func (qe QueryContextEvent) Call(v *View, key string, operator Op, operand interface{}, match_all bool) QueryContextReturn {
	log4go.Fine("Query context: %s, %v, %v, %v", key, operator, operand, match_all)
	for i := range qe {
		r := qe[i](v, key, operator, operand, match_all)
		if r != Unknown {
			return r
		}
	}
	log4go.Fine("Unknown context: %s", key)
	return Unknown
}

// Add the provided WindowEventCallback to this WindowEvent.
// TODO(.): Support removing WindowEventCallbacks?
func (we *WindowEvent) Add(cb WindowEventCallback) {
	*we = append(*we, cb)
}

// Trigger this WindowEvent by calling all the registered callbacks in order of registration.
func (we *WindowEvent) Call(w *Window) {
	log4go.Finest("%s(%v)", wevNames[we], w.Id())
	for _, ev := range *we {
		ev(w)
	}
}

var (
	OnNew               ViewEvent //< Called when a new view is created
	OnLoad              ViewEvent //< Called when loading a view's buffer has finished
	OnActivated         ViewEvent //< Called when a view gains input focus.
	OnDeactivated       ViewEvent //< Called when a view loses input focus.
	OnPreClose          ViewEvent //< Called when a view is about to be closed.
	OnClose             ViewEvent //< Called when a view has been closed.
	OnPreSave           ViewEvent //< Called just before a view's buffer is saved.
	OnPostSave          ViewEvent //< Called after a view's buffer has been saved.
	OnModified          ViewEvent //< Called when the contents of a view's underlying buffer has changed.
	OnSelectionModified ViewEvent //< Called when a view's Selection/cursor has changed.

	OnNewWindow    WindowEvent       //< Called when a new window has been created.
	OnQueryContext QueryContextEvent //< Called when context is being queried.
)

var (
	evNames = map[*ViewEvent]string{
		&OnNew:               "OnNew",
		&OnLoad:              "OnLoad",
		&OnActivated:         "OnActivated",
		&OnDeactivated:       "OnDeactivated",
		&OnPreClose:          "OnPreClose",
		&OnClose:             "OnClose",
		&OnPreSave:           "OnPreSave",
		&OnPostSave:          "OnPostSave",
		&OnModified:          "OnModified",
		&OnSelectionModified: "OnSelectionModified",
	}
	wevNames = map[*WindowEvent]string{
		&OnNewWindow: "OnNewWindow",
	}
)

func init() {
	// Register functionality dealing with a couple of built in contexts
	OnQueryContext.Add(func(v *View, key string, operator Op, operand interface{}, match_all bool) QueryContextReturn {
		if strings.HasPrefix(key, "setting.") && operator == OpEqual {
			c, ok := v.Settings().Get(key[8:]).(bool)
			if c && ok {
				return True
			}
			return False
		} else if key == "num_selections" {
			opf, _ := operand.(float64)
			op := int(opf)

			switch operator {
			case OpEqual:
				if op == v.Sel().Len() {
					return True
				}
				return False
			case OpNotEqual:
				if op != v.Sel().Len() {
					return True
				}
				return False
			}
		}
		return Unknown
	})

	OnLoad.Add(func(view *View) {
		editor := GetEditor()
		editor.Watch(NewWatchedUserFile(view))
	})
}
<|endoftext|>


<commit_before>package testsummaries

import (
	"fmt"
	"log"
	"strconv"
	"time"

	"github.com/bitrise-io/go-xcode/plistutil"
	"github.com/bitrise-steplib/steps-xcode-test/pretty"
)

// ScreenshotsType descdribes the screenshot atttachment's type
type ScreenshotsType string

// const ...
const (
	ScreenshotsLegacy        ScreenshotsType = "ScreenshotsLegacy"
	ScreenshotsAsAttachments ScreenshotsType = "ScreenshotsAsAttachments"
	ScreenshotsNone          ScreenshotsType = "ScreenshotsNone"
)

// FailureSummary describes a failed test
type FailureSummary struct {
	FileName             string
	LineNumber           uint64
	Message              string
	IsPerformanceFailure bool
}

// Screenshot describes a screenshot attached to a Activity
type Screenshot struct {
	FileName    string
	TimeCreated time.Time
}

// Activity describes a single xcode UI test activity
type Activity struct {
	Title         string
	UUID          string
	Screenshots   []Screenshot
	SubActivities []Activity
}

// TestResult describes a single UI test's output
type TestResult struct {
	ID          string
	Status      string
	FailureInfo []FailureSummary
	Activities  []Activity
}

// New parses an *_TestSummaries.plist and returns an array containing test results and screenshots
func New(testSummariesPth string) ([]TestResult, error) {
	testSummariesPlistData, err := plistutil.NewPlistDataFromFile(testSummariesPth)
	if err != nil {
		return nil, fmt.Errorf("failed to parse TestSummaries file: %s, error: %s", testSummariesPth, err)
	}

	return parseTestSummaries(testSummariesPlistData)
}

func parseTestSummaries(testSummariesContent plistutil.PlistData) ([]TestResult, error) {
	testableSummaries, found := testSummariesContent.GetMapStringInterfaceArray("TestableSummaries")
	if !found {
		return nil, fmt.Errorf("failed to parse test summaries plist, key TestableSummaries is not a string map")
	}

	var testResults []TestResult
	for _, testableSummariesItem := range testableSummaries {
		tests, found := testableSummariesItem.GetMapStringInterfaceArray("Tests")
		if !found {
			return nil, fmt.Errorf("failed to parse test summaries plist, key Tests is not a string map")
		}

		for _, testsItem := range tests {
			lastSubtests, err := collectLastSubtests(testsItem)
			if err != nil {
				return nil, err
			}
			log.Printf("lastSubtests %s", pretty.Object(lastSubtests))

			for _, test := range lastSubtests {
				testID, found := test.GetString("TestIdentifier")
				if !found {
					return nil, fmt.Errorf("key TestIdentifier not found for test")
				}
				testStatus, found := test.GetString("TestStatus")
				if !found {
					return nil, fmt.Errorf("key TestStatus not found for test")
				}
				var failureSummaries []FailureSummary
				if testStatus == "Failure" {
					failureSummariesData, found := test.GetMapStringInterfaceArray("FailureSummaries")
					if !found {
						return nil, fmt.Errorf("no failure summaries found for failing test")
					}
					failureSummaries, err = parseFailureSummaries(failureSummariesData)
					if err != nil {
						return nil, fmt.Errorf("failed to parse failure summaries, error: %s", err)
					}
				}
				var activitySummaries []Activity
				{
					activitySummariesData, found := test.GetMapStringInterfaceArray("ActivitySummaries")
					if !found {
						log.Printf("no activity summaries found for test: %s", test)
					}
					activitySummaries, err = parseActivites(activitySummariesData)
					if err != nil {
						return nil, fmt.Errorf("failed to parse activities, error: %s", err)
					}
				}
				testResults = append(testResults, TestResult{
					ID:          testID,
					Status:      testStatus,
					FailureInfo: failureSummaries,
					Activities:  activitySummaries,
				})
			}
		}
	}
	return testResults, nil
}

func collectLastSubtests(testsItem plistutil.PlistData) ([]plistutil.PlistData, error) {
	var walk func(plistutil.PlistData) []plistutil.PlistData
	walk = func(item plistutil.PlistData) []plistutil.PlistData {
		subtests, found := item.GetMapStringInterfaceArray("Subtests")
		if !found {
			return []plistutil.PlistData{item}
		}
		var lastSubtests []plistutil.PlistData
		for _, subtest := range subtests {
			last := walk(subtest)
			lastSubtests = append(lastSubtests, last...)
		}
		return lastSubtests
	}

	return walk(testsItem), nil
}

func parseFailureSummaries(failureSummariesData []plistutil.PlistData) ([]FailureSummary, error) {
	var failureSummaries = make([]FailureSummary, len(failureSummariesData))
	for i, failureSummary := range failureSummariesData {
		fileName, found := failureSummary.GetString("FileName")
		if !found {
			return nil, fmt.Errorf("key FileName not found for FailureSummaries: %s", pretty.Object(failureSummariesData))
		}
		lineNumber, found := failureSummary.GetUInt64("LineNumber")
		if !found {
			return nil, fmt.Errorf("key lineNumber not found for FailureSummaries: %s", pretty.Object(failureSummariesData))
		}
		message, found := failureSummary.GetString("Message")
		if !found {
			return nil, fmt.Errorf("key Message not found for FailureSummaries: %s", pretty.Object(failureSummariesData))
		}
		isPerformanceFailure, found := failureSummary.GetBool("PerformanceFailure")
		if !found {
			return nil, fmt.Errorf("key PerformanceFailure not found for FailureSummaries: %s", pretty.Object(failureSummariesData))
		}
		failureSummaries[i] = FailureSummary{
			FileName:             fileName,
			LineNumber:           lineNumber,
			Message:              message,
			IsPerformanceFailure: isPerformanceFailure,
		}
	}
	return failureSummaries, nil
}

func parseActivites(activitySummariesData []plistutil.PlistData) ([]Activity, error) {
	var activities = make([]Activity, len(activitySummariesData))
	for i, activity := range activitySummariesData {
		title, found := activity.GetString("Title")
		if !found {
			return nil, fmt.Errorf("key Title not found for activity: %s", pretty.Object(activity))
		}
		UUID, found := activity.GetString("UUID")
		if !found {
			return nil, fmt.Errorf("key UUID not found for activity: %s", pretty.Object(activity))
		}
		timeStampFloat, found := activity.GetFloat64("StartTimeInterval")
		if !found {
			return nil, fmt.Errorf("key StartTimeInterval not found for activity: %s", pretty.Object(activity))
		}
		timeStamp := TimestampToTime(timeStampFloat)
		screenshots, err := parseSceenshots(activity, UUID, timeStamp)
		if err != nil {
			return nil, fmt.Errorf("Screenshot invalid format, error: %s", err)
		}
		var subActivities []Activity
		if subActivitiesData, found := activity.GetMapStringInterfaceArray("SubActivities"); found {
			if subActivities, err = parseActivites(subActivitiesData); err != nil {
				return nil, err
			}
		} else {
			log.Printf("No subactivities found for activity: %s", pretty.Object(activity))
		}
		activities[i] = Activity{
			Title:         title,
			UUID:          UUID,
			Screenshots:   screenshots,
			SubActivities: subActivities,
		}
	}
	return activities, nil
}

func parseSceenshots(activitySummary plistutil.PlistData, activityUUID string, activityStartTime time.Time) ([]Screenshot, error) {
	getAttachmentType := func(item map[string]interface{}) ScreenshotsType {
		value, found := item["Attachments"]
		if found {
			return ScreenshotsAsAttachments
		}
		value, found = item["HasScreenshotData"]
		if found {
			hasScreenshot, casted := value.(bool)
			if casted && hasScreenshot {
				return ScreenshotsLegacy
			}
		}
		return ScreenshotsNone
	}

	switch getAttachmentType(activitySummary) {
	case ScreenshotsAsAttachments:
		{
			attachmentsData, found := activitySummary.GetMapStringInterfaceArray("Attachments")
			if !found {
				return nil, fmt.Errorf("no key Attachments, or invalid format")
			}
			attachments := make([]Screenshot, len(attachmentsData))
			for i, attachment := range attachmentsData {
				filenName, found := attachment.GetString("Filename")
				if !found {
					return nil, fmt.Errorf("no key Filename found for attachment: %s", pretty.Object(attachment))
				}
				timeStampFloat, found := attachment.GetFloat64("Timestamp")
				if !found {
					return nil, fmt.Errorf("no key Timestamp found for attachment: %s", pretty.Object(attachment))
				}
				timeStamp := TimestampToTime(timeStampFloat)
				attachments[i] = Screenshot{
					FileName:    filenName,
					TimeCreated: timeStamp,
				}
			}
			return attachments, nil
		}
	case ScreenshotsLegacy:
		{
			attachments := make([]Screenshot, 2)
			for i, ext := range []string{"png", "jpg"} {
				fileName := fmt.Sprintf("Screenshot_%s.%s", activityUUID, ext)
				attachments[i] = Screenshot{
					FileName:    fileName,
					TimeCreated: activityStartTime,
				}
			}
			return attachments, nil
		}
	case ScreenshotsNone:
		{
			return nil, nil
		}
	default:
		{
			return nil, fmt.Errorf("unhandled screenshot type")
		}
	}
}

// TimestampStrToTime ...
func TimestampStrToTime(timestampStr string) (time.Time, error) {
	timestamp, err := strconv.ParseFloat(timestampStr, 64)
	if err != nil {
		return time.Time{}, err
	}

	return TimestampToTime(timestamp), nil
}

// TimestampToTime ...
func TimestampToTime(timestamp float64) time.Time {
	timestampInNanosec := int64(timestamp * float64(time.Second))
	referenceDate := time.Date(2001, 1, 1, 0, 0, 0, 0, time.UTC)
	return referenceDate.Add(time.Duration(timestampInNanosec))
}
<commit_msg>Use debug logging for testsummaries (#121)<commit_after>package testsummaries

import (
	"fmt"
	"strconv"
	"time"

	"github.com/bitrise-io/go-utils/log"
	"github.com/bitrise-io/go-xcode/plistutil"
	"github.com/bitrise-steplib/steps-xcode-test/pretty"
)

// ScreenshotsType descdribes the screenshot atttachment's type
type ScreenshotsType string

// const ...
const (
	ScreenshotsLegacy        ScreenshotsType = "ScreenshotsLegacy"
	ScreenshotsAsAttachments ScreenshotsType = "ScreenshotsAsAttachments"
	ScreenshotsNone          ScreenshotsType = "ScreenshotsNone"
)

// FailureSummary describes a failed test
type FailureSummary struct {
	FileName             string
	LineNumber           uint64
	Message              string
	IsPerformanceFailure bool
}

// Screenshot describes a screenshot attached to a Activity
type Screenshot struct {
	FileName    string
	TimeCreated time.Time
}

// Activity describes a single xcode UI test activity
type Activity struct {
	Title         string
	UUID          string
	Screenshots   []Screenshot
	SubActivities []Activity
}

// TestResult describes a single UI test's output
type TestResult struct {
	ID          string
	Status      string
	FailureInfo []FailureSummary
	Activities  []Activity
}

// New parses an *_TestSummaries.plist and returns an array containing test results and screenshots
func New(testSummariesPth string) ([]TestResult, error) {
	testSummariesPlistData, err := plistutil.NewPlistDataFromFile(testSummariesPth)
	if err != nil {
		return nil, fmt.Errorf("failed to parse TestSummaries file: %s, error: %s", testSummariesPth, err)
	}

	return parseTestSummaries(testSummariesPlistData)
}

func parseTestSummaries(testSummariesContent plistutil.PlistData) ([]TestResult, error) {
	testableSummaries, found := testSummariesContent.GetMapStringInterfaceArray("TestableSummaries")
	if !found {
		return nil, fmt.Errorf("failed to parse test summaries plist, key TestableSummaries is not a string map")
	}

	var testResults []TestResult
	for _, testableSummariesItem := range testableSummaries {
		tests, found := testableSummariesItem.GetMapStringInterfaceArray("Tests")
		if !found {
			return nil, fmt.Errorf("failed to parse test summaries plist, key Tests is not a string map")
		}

		for _, testsItem := range tests {
			lastSubtests, err := collectLastSubtests(testsItem)
			if err != nil {
				return nil, err
			}
			log.Debugf("lastSubtests %s", pretty.Object(lastSubtests))

			for _, test := range lastSubtests {
				testID, found := test.GetString("TestIdentifier")
				if !found {
					return nil, fmt.Errorf("key TestIdentifier not found for test")
				}
				testStatus, found := test.GetString("TestStatus")
				if !found {
					return nil, fmt.Errorf("key TestStatus not found for test")
				}
				var failureSummaries []FailureSummary
				if testStatus == "Failure" {
					failureSummariesData, found := test.GetMapStringInterfaceArray("FailureSummaries")
					if !found {
						return nil, fmt.Errorf("no failure summaries found for failing test")
					}
					failureSummaries, err = parseFailureSummaries(failureSummariesData)
					if err != nil {
						return nil, fmt.Errorf("failed to parse failure summaries, error: %s", err)
					}
				}
				var activitySummaries []Activity
				{
					activitySummariesData, found := test.GetMapStringInterfaceArray("ActivitySummaries")
					if !found {
						log.Infof("no activity summaries found for test: %s", test)
					}
					activitySummaries, err = parseActivites(activitySummariesData)
					if err != nil {
						return nil, fmt.Errorf("failed to parse activities, error: %s", err)
					}
				}
				testResults = append(testResults, TestResult{
					ID:          testID,
					Status:      testStatus,
					FailureInfo: failureSummaries,
					Activities:  activitySummaries,
				})
			}
		}
	}
	return testResults, nil
}

func collectLastSubtests(testsItem plistutil.PlistData) ([]plistutil.PlistData, error) {
	var walk func(plistutil.PlistData) []plistutil.PlistData
	walk = func(item plistutil.PlistData) []plistutil.PlistData {
		subtests, found := item.GetMapStringInterfaceArray("Subtests")
		if !found {
			return []plistutil.PlistData{item}
		}
		var lastSubtests []plistutil.PlistData
		for _, subtest := range subtests {
			last := walk(subtest)
			lastSubtests = append(lastSubtests, last...)
		}
		return lastSubtests
	}

	return walk(testsItem), nil
}

func parseFailureSummaries(failureSummariesData []plistutil.PlistData) ([]FailureSummary, error) {
	var failureSummaries = make([]FailureSummary, len(failureSummariesData))
	for i, failureSummary := range failureSummariesData {
		fileName, found := failureSummary.GetString("FileName")
		if !found {
			return nil, fmt.Errorf("key FileName not found for FailureSummaries: %s", pretty.Object(failureSummariesData))
		}
		lineNumber, found := failureSummary.GetUInt64("LineNumber")
		if !found {
			return nil, fmt.Errorf("key lineNumber not found for FailureSummaries: %s", pretty.Object(failureSummariesData))
		}
		message, found := failureSummary.GetString("Message")
		if !found {
			return nil, fmt.Errorf("key Message not found for FailureSummaries: %s", pretty.Object(failureSummariesData))
		}
		isPerformanceFailure, found := failureSummary.GetBool("PerformanceFailure")
		if !found {
			return nil, fmt.Errorf("key PerformanceFailure not found for FailureSummaries: %s", pretty.Object(failureSummariesData))
		}
		failureSummaries[i] = FailureSummary{
			FileName:             fileName,
			LineNumber:           lineNumber,
			Message:              message,
			IsPerformanceFailure: isPerformanceFailure,
		}
	}
	return failureSummaries, nil
}

func parseActivites(activitySummariesData []plistutil.PlistData) ([]Activity, error) {
	var activities = make([]Activity, len(activitySummariesData))
	for i, activity := range activitySummariesData {
		title, found := activity.GetString("Title")
		if !found {
			return nil, fmt.Errorf("key Title not found for activity: %s", pretty.Object(activity))
		}
		UUID, found := activity.GetString("UUID")
		if !found {
			return nil, fmt.Errorf("key UUID not found for activity: %s", pretty.Object(activity))
		}
		timeStampFloat, found := activity.GetFloat64("StartTimeInterval")
		if !found {
			return nil, fmt.Errorf("key StartTimeInterval not found for activity: %s", pretty.Object(activity))
		}
		timeStamp := TimestampToTime(timeStampFloat)
		screenshots, err := parseSceenshots(activity, UUID, timeStamp)
		if err != nil {
			return nil, fmt.Errorf("Screenshot invalid format, error: %s", err)
		}
		var subActivities []Activity
		if subActivitiesData, found := activity.GetMapStringInterfaceArray("SubActivities"); found {
			if subActivities, err = parseActivites(subActivitiesData); err != nil {
				return nil, err
			}
		} else {
			log.Debugf("No subactivities found for activity: %s", pretty.Object(activity))
		}
		activities[i] = Activity{
			Title:         title,
			UUID:          UUID,
			Screenshots:   screenshots,
			SubActivities: subActivities,
		}
	}
	return activities, nil
}

func parseSceenshots(activitySummary plistutil.PlistData, activityUUID string, activityStartTime time.Time) ([]Screenshot, error) {
	getAttachmentType := func(item map[string]interface{}) ScreenshotsType {
		value, found := item["Attachments"]
		if found {
			return ScreenshotsAsAttachments
		}
		value, found = item["HasScreenshotData"]
		if found {
			hasScreenshot, casted := value.(bool)
			if casted && hasScreenshot {
				return ScreenshotsLegacy
			}
		}
		return ScreenshotsNone
	}

	switch getAttachmentType(activitySummary) {
	case ScreenshotsAsAttachments:
		{
			attachmentsData, found := activitySummary.GetMapStringInterfaceArray("Attachments")
			if !found {
				return nil, fmt.Errorf("no key Attachments, or invalid format")
			}
			attachments := make([]Screenshot, len(attachmentsData))
			for i, attachment := range attachmentsData {
				filenName, found := attachment.GetString("Filename")
				if !found {
					return nil, fmt.Errorf("no key Filename found for attachment: %s", pretty.Object(attachment))
				}
				timeStampFloat, found := attachment.GetFloat64("Timestamp")
				if !found {
					return nil, fmt.Errorf("no key Timestamp found for attachment: %s", pretty.Object(attachment))
				}
				timeStamp := TimestampToTime(timeStampFloat)
				attachments[i] = Screenshot{
					FileName:    filenName,
					TimeCreated: timeStamp,
				}
			}
			return attachments, nil
		}
	case ScreenshotsLegacy:
		{
			attachments := make([]Screenshot, 2)
			for i, ext := range []string{"png", "jpg"} {
				fileName := fmt.Sprintf("Screenshot_%s.%s", activityUUID, ext)
				attachments[i] = Screenshot{
					FileName:    fileName,
					TimeCreated: activityStartTime,
				}
			}
			return attachments, nil
		}
	case ScreenshotsNone:
		{
			return nil, nil
		}
	default:
		{
			return nil, fmt.Errorf("unhandled screenshot type")
		}
	}
}

// TimestampStrToTime ...
func TimestampStrToTime(timestampStr string) (time.Time, error) {
	timestamp, err := strconv.ParseFloat(timestampStr, 64)
	if err != nil {
		return time.Time{}, err
	}

	return TimestampToTime(timestamp), nil
}

// TimestampToTime ...
func TimestampToTime(timestamp float64) time.Time {
	timestampInNanosec := int64(timestamp * float64(time.Second))
	referenceDate := time.Date(2001, 1, 1, 0, 0, 0, 0, time.UTC)
	return referenceDate.Add(time.Duration(timestampInNanosec))
}
<|endoftext|>


<commit_before>// Copyright 2011 The Snappy-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package snappy

import (
	"encoding/binary"
)

// We limit how far copy back-references can go, the same as the C++ code.
const maxOffset = 1 << 15

// equal4 returns whether b[i:i+4] equals b[j:j+4].
func equal4(b []byte, i, j int) bool {
	return b[i] == b[j] &&
		b[i+1] == b[j+1] &&
		b[i+2] == b[j+2] &&
		b[i+3] == b[j+3]
}

// emitLiteral writes a literal chunk and returns the number of bytes written.
func emitLiteral(dst, lit []byte) int {
	i, n := 0, uint(len(lit)-1)
	switch {
	case n < 60:
		dst[0] = uint8(n)<<2 | tagLiteral
		i = 1
	case n < 1<<8:
		dst[0] = 60<<2 | tagLiteral
		dst[1] = uint8(n)
		i = 2
	case n < 1<<16:
		dst[0] = 61<<2 | tagLiteral
		dst[1] = uint8(n)
		dst[2] = uint8(n >> 8)
		i = 3
	case n < 1<<24:
		dst[0] = 62<<2 | tagLiteral
		dst[1] = uint8(n)
		dst[2] = uint8(n >> 8)
		dst[3] = uint8(n >> 16)
		i = 4
	case int64(n) < 1<<32:
		dst[0] = 63<<2 | tagLiteral
		dst[1] = uint8(n)
		dst[2] = uint8(n >> 8)
		dst[3] = uint8(n >> 16)
		dst[4] = uint8(n >> 24)
		i = 5
	default:
		panic("snappy: source buffer is too long")
	}
	if copy(dst[i:], lit) != len(lit) {
		panic("snappy: destination buffer is too short")
	}
	return i + len(lit)
}

// emitCopy writes a copy chunk and returns the number of bytes written.
func emitCopy(dst []byte, offset, length int) int {
	i := 0
	for length > 0 {
		x := length - 4
		if 0 <= x && x < 1<<3 && offset < 1<<11 {
			dst[i+0] = uint8(offset>>8)&0x07<<5 | uint8(x)<<2 | tagCopy1
			dst[i+1] = uint8(offset)
			i += 2
			break
		}

		x = length
		if x > 1<<6 {
			x = 1 << 6
		}
		dst[i+0] = uint8(x-1)<<2 | tagCopy2
		dst[i+1] = uint8(offset)
		dst[i+2] = uint8(offset >> 8)
		i += 3
		length -= x
	}
	return i
}

// Encode returns the encoded form of src. The returned slice may be a sub-
// slice of dst if dst was large enough to hold the entire encoded block.
// Otherwise, a newly allocated slice will be returned.
// It is valid to pass a nil dst.
func Encode(dst, src []byte) ([]byte, error) {
	if n := MaxEncodedLen(len(src)); len(dst) < n {
		dst = make([]byte, n)
	}

	// The block starts with the varint-encoded length of the decompressed bytes.
	d := binary.PutUvarint(dst, uint64(len(src)))

	// Return early if src is short.
	if len(src) <= 4 {
		if len(src) != 0 {
			d += emitLiteral(dst[d:], src)
		}
		return dst[:d], nil
	}

	// Initialize the hash table. Its size ranges from 1<<8 to 1<<14 inclusive.
	const maxTableSize = 1 << 14
	shift, tableSize := uint(32-8), 1<<8
	for tableSize < maxTableSize && tableSize < len(src) {
		shift--
		tableSize *= 2
	}
	var table [maxTableSize]int

	// Iterate over the source bytes.
	var (
		s   int // The iterator position.
		t   int // The last position with the same hash as s.
		lit int // The start position of any pending literal bytes.
	)
	for s+3 < len(src) {
		// Update the hash table.
		b0, b1, b2, b3 := src[s], src[s+1], src[s+2], src[s+3]
		h := uint32(b0) | uint32(b1)<<8 | uint32(b2)<<16 | uint32(b3)<<24
		p := &table[(h*0x1e35a7bd)>>shift]
		// We need to to store values in [-1, inf) in table. To save
		// some initialization time, (re)use the table's zero value
		// and shift the values against this zero: add 1 on writes,
		// subtract 1 on reads.
		t, *p = *p-1, s+1
		// If t is invalid or src[s:s+4] differs from src[t:t+4], accumulate a literal byte.
		if t < 0 || s-t >= maxOffset || b0 != src[t] || b1 != src[t+1] || b2 != src[t+2] || b3 != src[t+3] {
			s++
			continue
		}
		// Otherwise, we have a match. First, emit any pending literal bytes.
		if lit != s {
			d += emitLiteral(dst[d:], src[lit:s])
		}
		// Extend the match to be as long as possible.
		s0 := s
		s, t = s+4, t+4
		for s < len(src) && src[s] == src[t] {
			s++
			t++
		}
		// Emit the copied bytes.
		d += emitCopy(dst[d:], s-t, s-s0)
		lit = s
	}

	// Emit any final pending literal bytes and return.
	if lit != len(src) {
		d += emitLiteral(dst[d:], src[lit:])
	}
	return dst[:d], nil
}

// MaxEncodedLen returns the maximum length of a snappy block, given its
// uncompressed length.
func MaxEncodedLen(srcLen int) int {
	// Compressed data can be defined as:
	//    compressed := item* literal*
	//    item       := literal* copy
	//
	// The trailing literal sequence has a space blowup of at most 62/60
	// since a literal of length 60 needs one tag byte + one extra byte
	// for length information.
	//
	// Item blowup is trickier to measure. Suppose the "copy" op copies
	// 4 bytes of data. Because of a special check in the encoding code,
	// we produce a 4-byte copy only if the offset is < 65536. Therefore
	// the copy op takes 3 bytes to encode, and this type of item leads
	// to at most the 62/60 blowup for representing literals.
	//
	// Suppose the "copy" op copies 5 bytes of data. If the offset is big
	// enough, it will take 5 bytes to encode the copy op. Therefore the
	// worst case here is a one-byte literal followed by a five-byte copy.
	// That is, 6 bytes of input turn into 7 bytes of "compressed" data.
	//
	// This last factor dominates the blowup, so the final estimate is:
	return 32 + srcLen + srcLen/6
}
<commit_msg>snappy-go: Remove equal4<commit_after>// Copyright 2011 The Snappy-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package snappy

import (
	"encoding/binary"
)

// We limit how far copy back-references can go, the same as the C++ code.
const maxOffset = 1 << 15

// emitLiteral writes a literal chunk and returns the number of bytes written.
func emitLiteral(dst, lit []byte) int {
	i, n := 0, uint(len(lit)-1)
	switch {
	case n < 60:
		dst[0] = uint8(n)<<2 | tagLiteral
		i = 1
	case n < 1<<8:
		dst[0] = 60<<2 | tagLiteral
		dst[1] = uint8(n)
		i = 2
	case n < 1<<16:
		dst[0] = 61<<2 | tagLiteral
		dst[1] = uint8(n)
		dst[2] = uint8(n >> 8)
		i = 3
	case n < 1<<24:
		dst[0] = 62<<2 | tagLiteral
		dst[1] = uint8(n)
		dst[2] = uint8(n >> 8)
		dst[3] = uint8(n >> 16)
		i = 4
	case int64(n) < 1<<32:
		dst[0] = 63<<2 | tagLiteral
		dst[1] = uint8(n)
		dst[2] = uint8(n >> 8)
		dst[3] = uint8(n >> 16)
		dst[4] = uint8(n >> 24)
		i = 5
	default:
		panic("snappy: source buffer is too long")
	}
	if copy(dst[i:], lit) != len(lit) {
		panic("snappy: destination buffer is too short")
	}
	return i + len(lit)
}

// emitCopy writes a copy chunk and returns the number of bytes written.
func emitCopy(dst []byte, offset, length int) int {
	i := 0
	for length > 0 {
		x := length - 4
		if 0 <= x && x < 1<<3 && offset < 1<<11 {
			dst[i+0] = uint8(offset>>8)&0x07<<5 | uint8(x)<<2 | tagCopy1
			dst[i+1] = uint8(offset)
			i += 2
			break
		}

		x = length
		if x > 1<<6 {
			x = 1 << 6
		}
		dst[i+0] = uint8(x-1)<<2 | tagCopy2
		dst[i+1] = uint8(offset)
		dst[i+2] = uint8(offset >> 8)
		i += 3
		length -= x
	}
	return i
}

// Encode returns the encoded form of src. The returned slice may be a sub-
// slice of dst if dst was large enough to hold the entire encoded block.
// Otherwise, a newly allocated slice will be returned.
// It is valid to pass a nil dst.
func Encode(dst, src []byte) ([]byte, error) {
	if n := MaxEncodedLen(len(src)); len(dst) < n {
		dst = make([]byte, n)
	}

	// The block starts with the varint-encoded length of the decompressed bytes.
	d := binary.PutUvarint(dst, uint64(len(src)))

	// Return early if src is short.
	if len(src) <= 4 {
		if len(src) != 0 {
			d += emitLiteral(dst[d:], src)
		}
		return dst[:d], nil
	}

	// Initialize the hash table. Its size ranges from 1<<8 to 1<<14 inclusive.
	const maxTableSize = 1 << 14
	shift, tableSize := uint(32-8), 1<<8
	for tableSize < maxTableSize && tableSize < len(src) {
		shift--
		tableSize *= 2
	}
	var table [maxTableSize]int

	// Iterate over the source bytes.
	var (
		s   int // The iterator position.
		t   int // The last position with the same hash as s.
		lit int // The start position of any pending literal bytes.
	)
	for s+3 < len(src) {
		// Update the hash table.
		b0, b1, b2, b3 := src[s], src[s+1], src[s+2], src[s+3]
		h := uint32(b0) | uint32(b1)<<8 | uint32(b2)<<16 | uint32(b3)<<24
		p := &table[(h*0x1e35a7bd)>>shift]
		// We need to to store values in [-1, inf) in table. To save
		// some initialization time, (re)use the table's zero value
		// and shift the values against this zero: add 1 on writes,
		// subtract 1 on reads.
		t, *p = *p-1, s+1
		// If t is invalid or src[s:s+4] differs from src[t:t+4], accumulate a literal byte.
		if t < 0 || s-t >= maxOffset || b0 != src[t] || b1 != src[t+1] || b2 != src[t+2] || b3 != src[t+3] {
			s++
			continue
		}
		// Otherwise, we have a match. First, emit any pending literal bytes.
		if lit != s {
			d += emitLiteral(dst[d:], src[lit:s])
		}
		// Extend the match to be as long as possible.
		s0 := s
		s, t = s+4, t+4
		for s < len(src) && src[s] == src[t] {
			s++
			t++
		}
		// Emit the copied bytes.
		d += emitCopy(dst[d:], s-t, s-s0)
		lit = s
	}

	// Emit any final pending literal bytes and return.
	if lit != len(src) {
		d += emitLiteral(dst[d:], src[lit:])
	}
	return dst[:d], nil
}

// MaxEncodedLen returns the maximum length of a snappy block, given its
// uncompressed length.
func MaxEncodedLen(srcLen int) int {
	// Compressed data can be defined as:
	//    compressed := item* literal*
	//    item       := literal* copy
	//
	// The trailing literal sequence has a space blowup of at most 62/60
	// since a literal of length 60 needs one tag byte + one extra byte
	// for length information.
	//
	// Item blowup is trickier to measure. Suppose the "copy" op copies
	// 4 bytes of data. Because of a special check in the encoding code,
	// we produce a 4-byte copy only if the offset is < 65536. Therefore
	// the copy op takes 3 bytes to encode, and this type of item leads
	// to at most the 62/60 blowup for representing literals.
	//
	// Suppose the "copy" op copies 5 bytes of data. If the offset is big
	// enough, it will take 5 bytes to encode the copy op. Therefore the
	// worst case here is a one-byte literal followed by a five-byte copy.
	// That is, 6 bytes of input turn into 7 bytes of "compressed" data.
	//
	// This last factor dominates the blowup, so the final estimate is:
	return 32 + srcLen + srcLen/6
}
<|endoftext|>


<commit_before>package sendgrid

import (
	"context"
	"errors"
	"net/http"
	"strconv"
	"time"

	"github.com/sendgrid/rest"
	"github.com/sendgrid/sendgrid-go/helpers/mail"
)

// Version is this client library's current version
const (
	Version        = "3.10.0"
	rateLimitRetry = 5
	rateLimitSleep = 1100
)

type options struct {
	Auth     string
	Endpoint string
	Host     string
	Subuser  string
}

// Client is the Twilio SendGrid Go client
type Client struct {
	rest.Request
}

func (o *options) baseURL() string {
	return o.Host + o.Endpoint
}

// requestNew create Request
// @return [Request] a default request object
func requestNew(options options) rest.Request {
	requestHeaders := map[string]string{
		"Authorization": options.Auth,
		"User-Agent":    "sendgrid/" + Version + ";go",
		"Accept":        "application/json",
	}

	if len(options.Subuser) != 0 {
		requestHeaders["On-Behalf-Of"] = options.Subuser
	}

	return rest.Request{
		BaseURL: options.baseURL(),
		Headers: requestHeaders,
	}
}

// Send sends an email through Twilio SendGrid
func (cl *Client) Send(email *mail.SGMailV3) (*rest.Response, error) {
	return cl.SendWithContext(context.Background(), email)
}

// SendWithContext sends an email through Twilio SendGrid with context.Context.
func (cl *Client) SendWithContext(ctx context.Context, email *mail.SGMailV3) (*rest.Response, error) {
	cl.Body = mail.GetRequestBody(email)
	return MakeRequestWithContext(ctx, cl.Request)
}

// DefaultClient is used if no custom HTTP client is defined
var DefaultClient = rest.DefaultClient

// API sets up the request to the Twilio SendGrid API, this is main interface.
// Please use the MakeRequest or MakeRequestAsync functions instead.
// (deprecated)
func API(request rest.Request) (*rest.Response, error) {
	return MakeRequest(request)
}

// MakeRequest attempts a Twilio SendGrid request synchronously.
func MakeRequest(request rest.Request) (*rest.Response, error) {
	return MakeRequestWithContext(context.Background(), request)
}

// MakeRequestWithContext attempts a Twilio SendGrid request synchronously with context.Context.
func MakeRequestWithContext(ctx context.Context, request rest.Request) (*rest.Response, error) {
	return DefaultClient.SendWithContext(ctx, request)
}

// MakeRequestRetry a synchronous request, but retry in the event of a rate
// limited response.
func MakeRequestRetry(request rest.Request) (*rest.Response, error) {
	return MakeRequestRetryWithContext(context.Background(), request)
}

// MakeRequestRetryWithContext a synchronous request with context.Context, but retry in the event of a rate
// limited response.
func MakeRequestRetryWithContext(ctx context.Context, request rest.Request) (*rest.Response, error) {
	retry := 0
	var response *rest.Response
	var err error

	for {
		select {
		case <-ctx.Done():
			return nil, ctx.Err()
		default:
		}
		response, err = MakeRequestWithContext(ctx, request)
		if err != nil {
			return nil, err
		}

		if response.StatusCode != http.StatusTooManyRequests {
			return response, nil
		}

		if retry > rateLimitRetry {
			return nil, errors.New("rate limit retry exceeded")
		}
		retry++

		resetTime := time.Now().Add(rateLimitSleep * time.Millisecond)

		reset, ok := response.Headers["X-RateLimit-Reset"]
		if ok && len(reset) > 0 {
			t, err := strconv.Atoi(reset[0])
			if err == nil {
				resetTime = time.Unix(int64(t), 0)
			}
		}
		time.Sleep(resetTime.Sub(time.Now()))
	}
}

// MakeRequestAsync attempts a request asynchronously in a new go
// routine. This function returns two channels: responses
// and errors. This function will retry in the case of a
// rate limit.
func MakeRequestAsync(request rest.Request) (chan *rest.Response, chan error) {
	return MakeRequestAsyncWithContext(context.Background(), request)
}

// MakeRequestAsyncWithContext attempts a request asynchronously in a new go
// routine with context.Context. This function returns two channels: responses
// and errors. This function will retry in the case of a
// rate limit.
func MakeRequestAsyncWithContext(ctx context.Context, request rest.Request) (chan *rest.Response, chan error) {
	r := make(chan *rest.Response)
	e := make(chan error)

	go func() {
		response, err := MakeRequestRetryWithContext(ctx, request)
		if err != nil {
			e <- err
		}
		if response != nil {
			r <- response
		}
	}()

	return r, e
}
<commit_msg>Release v3.10.1<commit_after>package sendgrid

import (
	"context"
	"errors"
	"net/http"
	"strconv"
	"time"

	"github.com/sendgrid/rest"
	"github.com/sendgrid/sendgrid-go/helpers/mail"
)

// Version is this client library's current version
const (
	Version        = "3.10.1"
	rateLimitRetry = 5
	rateLimitSleep = 1100
)

type options struct {
	Auth     string
	Endpoint string
	Host     string
	Subuser  string
}

// Client is the Twilio SendGrid Go client
type Client struct {
	rest.Request
}

func (o *options) baseURL() string {
	return o.Host + o.Endpoint
}

// requestNew create Request
// @return [Request] a default request object
func requestNew(options options) rest.Request {
	requestHeaders := map[string]string{
		"Authorization": options.Auth,
		"User-Agent":    "sendgrid/" + Version + ";go",
		"Accept":        "application/json",
	}

	if len(options.Subuser) != 0 {
		requestHeaders["On-Behalf-Of"] = options.Subuser
	}

	return rest.Request{
		BaseURL: options.baseURL(),
		Headers: requestHeaders,
	}
}

// Send sends an email through Twilio SendGrid
func (cl *Client) Send(email *mail.SGMailV3) (*rest.Response, error) {
	return cl.SendWithContext(context.Background(), email)
}

// SendWithContext sends an email through Twilio SendGrid with context.Context.
func (cl *Client) SendWithContext(ctx context.Context, email *mail.SGMailV3) (*rest.Response, error) {
	cl.Body = mail.GetRequestBody(email)
	return MakeRequestWithContext(ctx, cl.Request)
}

// DefaultClient is used if no custom HTTP client is defined
var DefaultClient = rest.DefaultClient

// API sets up the request to the Twilio SendGrid API, this is main interface.
// Please use the MakeRequest or MakeRequestAsync functions instead.
// (deprecated)
func API(request rest.Request) (*rest.Response, error) {
	return MakeRequest(request)
}

// MakeRequest attempts a Twilio SendGrid request synchronously.
func MakeRequest(request rest.Request) (*rest.Response, error) {
	return MakeRequestWithContext(context.Background(), request)
}

// MakeRequestWithContext attempts a Twilio SendGrid request synchronously with context.Context.
func MakeRequestWithContext(ctx context.Context, request rest.Request) (*rest.Response, error) {
	return DefaultClient.SendWithContext(ctx, request)
}

// MakeRequestRetry a synchronous request, but retry in the event of a rate
// limited response.
func MakeRequestRetry(request rest.Request) (*rest.Response, error) {
	return MakeRequestRetryWithContext(context.Background(), request)
}

// MakeRequestRetryWithContext a synchronous request with context.Context, but retry in the event of a rate
// limited response.
func MakeRequestRetryWithContext(ctx context.Context, request rest.Request) (*rest.Response, error) {
	retry := 0
	var response *rest.Response
	var err error

	for {
		select {
		case <-ctx.Done():
			return nil, ctx.Err()
		default:
		}
		response, err = MakeRequestWithContext(ctx, request)
		if err != nil {
			return nil, err
		}

		if response.StatusCode != http.StatusTooManyRequests {
			return response, nil
		}

		if retry > rateLimitRetry {
			return nil, errors.New("rate limit retry exceeded")
		}
		retry++

		resetTime := time.Now().Add(rateLimitSleep * time.Millisecond)

		reset, ok := response.Headers["X-RateLimit-Reset"]
		if ok && len(reset) > 0 {
			t, err := strconv.Atoi(reset[0])
			if err == nil {
				resetTime = time.Unix(int64(t), 0)
			}
		}
		time.Sleep(resetTime.Sub(time.Now()))
	}
}

// MakeRequestAsync attempts a request asynchronously in a new go
// routine. This function returns two channels: responses
// and errors. This function will retry in the case of a
// rate limit.
func MakeRequestAsync(request rest.Request) (chan *rest.Response, chan error) {
	return MakeRequestAsyncWithContext(context.Background(), request)
}

// MakeRequestAsyncWithContext attempts a request asynchronously in a new go
// routine with context.Context. This function returns two channels: responses
// and errors. This function will retry in the case of a
// rate limit.
func MakeRequestAsyncWithContext(ctx context.Context, request rest.Request) (chan *rest.Response, chan error) {
	r := make(chan *rest.Response)
	e := make(chan error)

	go func() {
		response, err := MakeRequestRetryWithContext(ctx, request)
		if err != nil {
			e <- err
		}
		if response != nil {
			r <- response
		}
	}()

	return r, e
}
<|endoftext|>


<commit_before>/*
 * Copyright 2018 the original author or authors.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

package cmd

import (
	"fmt"
	"strings"

	"path/filepath"

	projectriff_v1 "github.com/projectriff/riff/kubernetes-crds/pkg/apis/projectriff.io/v1alpha1"
	"github.com/projectriff/riff/riff-cli/cmd/utils"
	"github.com/projectriff/riff/riff-cli/pkg/initializer"
	"github.com/projectriff/riff/riff-cli/pkg/options"
	"github.com/spf13/cobra"
)

func Init(invokers []projectriff_v1.Invoker) (*cobra.Command, *options.InitOptions) {

	var initOptions = options.InitOptions{}

	var initCmd = &cobra.Command{
		Use:   "init",
		Short: "Initialize a function",
		Long:  utils.InitCmdLong(),

		RunE: func(cmd *cobra.Command, args []string) error {
			cmd.SilenceUsage = true
			if len(invokers) == 0 {
				return fmt.Errorf("Invokers must be installed, run `riff invokers apply --help` for help")
			}
			names := invokerNames(invokers)
			return fmt.Errorf("The invoker must be specified. Pick one of: %s", strings.Join(names, ", "))
		},
		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
			initOptions.UserAccount = utils.GetUseraccountWithOverride("useraccount", *cmd.Flags())
			err := validateInitOptions(&initOptions)
			if err != nil {
				return err
			}
			return nil

		},
	}

	initCmd.PersistentFlags().BoolVar(&initOptions.DryRun, "dry-run", false, "print generated function artifacts content to stdout only")
	initCmd.PersistentFlags().StringVarP(&initOptions.FilePath, "filepath", "f", "", "path or directory used for the function resources (defaults to the current directory)")
	initCmd.PersistentFlags().StringVarP(&initOptions.FunctionName, "name", "n", "", "the name of the function (defaults to the name of the current directory)")
	initCmd.PersistentFlags().StringVarP(&initOptions.Version, "version", "v", utils.DefaultValues.Version, "the version of the function image")
	initCmd.PersistentFlags().StringVar(&initOptions.InvokerVersion, "invoker-version", "", "the version of the invoker to use when building containers")
	initCmd.PersistentFlags().StringVarP(&initOptions.UserAccount, "useraccount", "u", utils.DefaultValues.UserAccount, "the Docker user account to be used for the image repository")
	initCmd.PersistentFlags().StringVarP(&initOptions.Artifact, "artifact", "a", "", "path to the function artifact, source code or jar file")
	initCmd.PersistentFlags().StringVarP(&initOptions.Input, "input", "i", "", "the name of the input topic (defaults to function name)")
	initCmd.PersistentFlags().StringVarP(&initOptions.Output, "output", "o", "", "the name of the output topic (optional)")
	initCmd.PersistentFlags().BoolVar(&initOptions.Force, "force", utils.DefaultValues.Force, "overwrite existing functions artifacts")

	initCmd.SetUsageTemplate(utils.CustomInvokerUsageTemplate)

	return initCmd, &initOptions
}

func InitInvokers(invokers []projectriff_v1.Invoker, initOptions *options.InitOptions) ([]*cobra.Command, error) {

	var initInvokerCmds []*cobra.Command
	for _, invoker := range invokers {
		invokerName := invoker.ObjectMeta.Name
		var initInvokerCmd = &cobra.Command{
			Use:   invokerName,
			Short: fmt.Sprintf("Initialize a %s function", invokerName),
			Long:  utils.InitInvokerCmdLong(invoker),
			RunE: func(cmd *cobra.Command, args []string) error {
				invoker, err := invokerForName(invokerName, invokers)
				if err != nil {
					return err
				}
				return initializer.Initialize(invoker, initOptions)
			},
		}

		handler := invoker.Spec.Handler
		if handler.Default != "" || handler.Description != "" {
			initInvokerCmd.Flags().StringVar(&initOptions.Handler, "handler", handler.Default, handler.Description)
			if handler.Default == "" {
				initInvokerCmd.MarkFlagRequired("handler")
			}
		}

		initInvokerCmds = append(initInvokerCmds, initInvokerCmd)
	}
	return initInvokerCmds, nil
}

func validateInitOptions(options *options.InitOptions) error {
	options.FilePath = filepath.Clean(options.FilePath)
	if err := validateFunctionName(&options.FunctionName, options.FilePath); err != nil {
		return err
	}

	if err := validateAndCleanArtifact(&options.Artifact, options.FilePath); err != nil {
		return err
	}

	if err := validateProtocol(&options.Protocol); err != nil {
		return err
	}
	return nil
}

func invokerForName(name string, invokers []projectriff_v1.Invoker) (projectriff_v1.Invoker, error) {
	for _, invoker := range invokers {
		if invoker.ObjectMeta.Name == name {
			return invoker, nil
		}
	}
	return projectriff_v1.Invoker{}, fmt.Errorf("No invoker found for %s", name)
}

func invokerNames(invokers []projectriff_v1.Invoker) []string {
	names := []string{}
	for _, invoker := range invokers {
		names = append(names, invoker.ObjectMeta.Name)
	}
	return names
}
<commit_msg>Align init and create command args<commit_after>/*
 * Copyright 2018 the original author or authors.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

package cmd

import (
	"fmt"
	"strings"

	"path/filepath"

	projectriff_v1 "github.com/projectriff/riff/kubernetes-crds/pkg/apis/projectriff.io/v1alpha1"
	"github.com/projectriff/riff/riff-cli/cmd/utils"
	"github.com/projectriff/riff/riff-cli/pkg/initializer"
	"github.com/projectriff/riff/riff-cli/pkg/options"
	"github.com/spf13/cobra"
)

func Init(invokers []projectriff_v1.Invoker) (*cobra.Command, *options.InitOptions) {

	var initOptions = options.InitOptions{}

	var initCmd = &cobra.Command{
		Use:   "init",
		Short: "Initialize a function",
		Long:  utils.InitCmdLong(),

		RunE: func(cmd *cobra.Command, args []string) error {
			cmd.SilenceUsage = true
			if len(invokers) == 0 {
				return fmt.Errorf("Invokers must be installed, run `riff invokers apply --help` for help")
			}
			names := invokerNames(invokers)
			return fmt.Errorf("The invoker must be specified. Pick one of: %s", strings.Join(names, ", "))
		},
		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
			initOptions.UserAccount = utils.GetUseraccountWithOverride("useraccount", *cmd.Flags())
			err := validateInitOptions(&initOptions)
			if err != nil {
				return err
			}
			return nil

		},
	}

	initCmd.PersistentFlags().BoolVar(&initOptions.DryRun, "dry-run", false, "print generated function artifacts content to stdout only")
	initCmd.PersistentFlags().StringVarP(&initOptions.FilePath, "filepath", "f", "", "path or directory used for the function resources (defaults to the current directory)")
	initCmd.PersistentFlags().StringVarP(&initOptions.FunctionName, "name", "n", "", "the name of the function (defaults to the name of the current directory)")
	initCmd.PersistentFlags().StringVarP(&initOptions.Version, "version", "v", utils.DefaultValues.Version, "the version of the function image")
	initCmd.PersistentFlags().StringVar(&initOptions.InvokerVersion, "invoker-version", "", "the version of the invoker to use when building containers")
	initCmd.PersistentFlags().StringVarP(&initOptions.UserAccount, "useraccount", "u", utils.DefaultValues.UserAccount, "the Docker user account to be used for the image repository")
	initCmd.PersistentFlags().StringVarP(&initOptions.Artifact, "artifact", "a", "", "path to the function artifact, source code or jar file")
	initCmd.PersistentFlags().StringVarP(&initOptions.Input, "input", "i", "", "the name of the input topic (defaults to function name)")
	initCmd.PersistentFlags().StringVarP(&initOptions.Output, "output", "o", "", "the name of the output topic (optional)")
	initCmd.PersistentFlags().BoolVar(&initOptions.Force, "force", utils.DefaultValues.Force, "overwrite existing functions artifacts")

	initCmd.SetUsageTemplate(utils.CustomInvokerUsageTemplate)

	return initCmd, &initOptions
}

func InitInvokers(invokers []projectriff_v1.Invoker, initOptions *options.InitOptions) ([]*cobra.Command, error) {

	var initInvokerCmds []*cobra.Command
	for _, invoker := range invokers {
		invokerName := invoker.ObjectMeta.Name
		var initInvokerCmd = &cobra.Command{
			Use:   invokerName,
			Short: fmt.Sprintf("Initialize a %s function", invokerName),
			Long:  utils.InitInvokerCmdLong(invoker),
			Args:  utils.AliasFlagToSoleArg("filepath"),
			RunE: func(cmd *cobra.Command, args []string) error {
				invoker, err := invokerForName(invokerName, invokers)
				if err != nil {
					return err
				}
				return initializer.Initialize(invoker, initOptions)
			},
		}

		handler := invoker.Spec.Handler
		if handler.Default != "" || handler.Description != "" {
			initInvokerCmd.Flags().StringVar(&initOptions.Handler, "handler", handler.Default, handler.Description)
			if handler.Default == "" {
				initInvokerCmd.MarkFlagRequired("handler")
			}
		}

		initInvokerCmds = append(initInvokerCmds, initInvokerCmd)
	}
	return initInvokerCmds, nil
}

func validateInitOptions(options *options.InitOptions) error {
	options.FilePath = filepath.Clean(options.FilePath)
	if err := validateFunctionName(&options.FunctionName, options.FilePath); err != nil {
		return err
	}

	if err := validateAndCleanArtifact(&options.Artifact, options.FilePath); err != nil {
		return err
	}

	if err := validateProtocol(&options.Protocol); err != nil {
		return err
	}
	return nil
}

func invokerForName(name string, invokers []projectriff_v1.Invoker) (projectriff_v1.Invoker, error) {
	for _, invoker := range invokers {
		if invoker.ObjectMeta.Name == name {
			return invoker, nil
		}
	}
	return projectriff_v1.Invoker{}, fmt.Errorf("No invoker found for %s", name)
}

func invokerNames(invokers []projectriff_v1.Invoker) []string {
	names := []string{}
	for _, invoker := range invokers {
		names = append(names, invoker.ObjectMeta.Name)
	}
	return names
}
<|endoftext|>