<commit_before>// Copyright 2012 Dmitry Chestnykh. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package scrypt

import (
	"bytes"
	"testing"
)

type testVector struct {
	password string
	salt     string
	N, r, p  int
	output   []byte
}

var good = []testVector{
	{
		"password",
		"salt",
		2, 10, 10,
		[]byte{
			0x48, 0x2c, 0x85, 0x8e, 0x22, 0x90, 0x55, 0xe6, 0x2f,
			0x41, 0xe0, 0xec, 0x81, 0x9a, 0x5e, 0xe1, 0x8b, 0xdb,
			0x87, 0x25, 0x1a, 0x53, 0x4f, 0x75, 0xac, 0xd9, 0x5a,
			0xc5, 0xe5, 0xa, 0xa1, 0x5f,
		},
	},
	{
		"password",
		"salt",
		16, 100, 100,
		[]byte{
			0x88, 0xbd, 0x5e, 0xdb, 0x52, 0xd1, 0xdd, 0x0, 0x18,
			0x87, 0x72, 0xad, 0x36, 0x17, 0x12, 0x90, 0x22, 0x4e,
			0x74, 0x82, 0x95, 0x25, 0xb1, 0x8d, 0x73, 0x23, 0xa5,
			0x7f, 0x91, 0x96, 0x3c, 0x37,
		},
	},
	{
		"this is a long \000 password",
		"and this is a long \000 salt",
		16384, 8, 1,
		[]byte{
			0xc3, 0xf1, 0x82, 0xee, 0x2d, 0xec, 0x84, 0x6e, 0x70,
			0xa6, 0x94, 0x2f, 0xb5, 0x29, 0x98, 0x5a, 0x3a, 0x9,
			0x76, 0x5e, 0xf0, 0x4c, 0x61, 0x29, 0x23, 0xb1, 0x7f,
			0x18, 0x55, 0x5a, 0x37, 0x7, 0x6d, 0xeb, 0x2b, 0x98,
			0x30, 0xd6, 0x9d, 0xe5, 0x49, 0x26, 0x51, 0xe4, 0x50,
			0x6a, 0xe5, 0x77, 0x6d, 0x96, 0xd4, 0xf, 0x67, 0xaa,
			0xee, 0x37, 0xe1, 0x77, 0x7b, 0x8a, 0xd5, 0xc3, 0x11,
			0x14, 0x32, 0xbb, 0x3b, 0x6f, 0x7e, 0x12, 0x64, 0x40,
			0x18, 0x79, 0xe6, 0x41, 0xae,
		},
	},
	{
		"p",
		"s",
		2, 1, 1,
		[]byte{
			0x48, 0xb0, 0xd2, 0xa8, 0xa3, 0x27, 0x26, 0x11, 0x98,
			0x4c, 0x50, 0xeb, 0xd6, 0x30, 0xaf, 0x52,
		},
	},
	// Test vectors from IETF Draft.
	// http://datatracker.ietf.org/doc/draft-josefsson-scrypt-kdf/?include_text=1
	{
		"",
		"",
		16, 1, 1,
		[]byte{
			0x77, 0xd6, 0x57, 0x62, 0x38, 0x65, 0x7b, 0x20, 0x3b, 0x19, 0xca, 0x42, 0xc1, 0x8a, 0x04, 0x97,
			0xf1, 0x6b, 0x48, 0x44, 0xe3, 0x07, 0x4a, 0xe8, 0xdf, 0xdf, 0xfa, 0x3f, 0xed, 0xe2, 0x14, 0x42,
			0xfc, 0xd0, 0x06, 0x9d, 0xed, 0x09, 0x48, 0xf8, 0x32, 0x6a, 0x75, 0x3a, 0x0f, 0xc8, 0x1f, 0x17,
			0xe8, 0xd3, 0xe0, 0xfb, 0x2e, 0x0d, 0x36, 0x28, 0xcf, 0x35, 0xe2, 0x0c, 0x38, 0xd1, 0x89, 0x06,
		},
	},
	{
		"password",
		"NaCl",
		1024, 8, 16,
		[]byte{
			0xfd, 0xba, 0xbe, 0x1c, 0x9d, 0x34, 0x72, 0x00, 0x78, 0x56, 0xe7, 0x19, 0x0d, 0x01, 0xe9, 0xfe,
			0x7c, 0x6a, 0xd7, 0xcb, 0xc8, 0x23, 0x78, 0x30, 0xe7, 0x73, 0x76, 0x63, 0x4b, 0x37, 0x31, 0x62,
			0x2e, 0xaf, 0x30, 0xd9, 0x2e, 0x22, 0xa3, 0x88, 0x6f, 0xf1, 0x09, 0x27, 0x9d, 0x98, 0x30, 0xda,
			0xc7, 0x27, 0xaf, 0xb9, 0x4a, 0x83, 0xee, 0x6d, 0x83, 0x60, 0xcb, 0xdf, 0xa2, 0xcc, 0x06, 0x40,
		},
	},
	{
		"pleaseletmein", "SodiumChloride",
		16384, 8, 1,
		[]byte{
			0x70, 0x23, 0xbd, 0xcb, 0x3a, 0xfd, 0x73, 0x48, 0x46, 0x1c, 0x06, 0xcd, 0x81, 0xfd, 0x38, 0xeb,
			0xfd, 0xa8, 0xfb, 0xba, 0x90, 0x4f, 0x8e, 0x3e, 0xa9, 0xb5, 0x43, 0xf6, 0x54, 0x5d, 0xa1, 0xf2,
			0xd5, 0x43, 0x29, 0x55, 0x61, 0x3f, 0x0f, 0xcf, 0x62, 0xd4, 0x97, 0x05, 0x24, 0x2a, 0x9a, 0xf9,
			0xe6, 0x1e, 0x85, 0xdc, 0x0d, 0x65, 0x1e, 0x40, 0xdf, 0xcf, 0x01, 0x7b, 0x45, 0x57, 0x58, 0x87,
		},
	},
	/*
	// Disabled: needs 1 GiB RAM and takes too long for a simple test.
	   {
	           "pleaseletmein", "SodiumChloride",
	           1048576, 8, 1,
	           []byte{
	              0x21 , 0x01 , 0xcb , 0x9b , 0x6a , 0x51 , 0x1a , 0xae , 0xad , 0xdb , 0xbe , 0x09 , 0xcf , 0x70 , 0xf8 , 0x81,
	              0xec , 0x56 , 0x8d , 0x57 , 0x4a , 0x2f , 0xfd , 0x4d , 0xab , 0xe5 , 0xee , 0x98 , 0x20 , 0xad , 0xaa , 0x47,
	              0x8e , 0x56 , 0xfd , 0x8f , 0x4b , 0xa5 , 0xd0 , 0x9f , 0xfa , 0x1c , 0x6d , 0x92 , 0x7c , 0x40 , 0xf4 , 0xc3,
	              0x37 , 0x30 , 0x40 , 0x49 , 0xe8 , 0xa9 , 0x52 , 0xfb , 0xcb , 0xf4 , 0x5c , 0x6f , 0xa7 , 0x7a , 0x41 , 0xa4,
	           },

	   },
	*/
}

var bad = []testVector{
	{"p", "s", 0, 1, 1, nil},                    // N == 0
	{"p", "s", 1, 1, 1, nil},                    // N == 1
	{"p", "s", 7, 8, 1, nil},                    // N is not power of 2
	{"p", "s", 16, maxInt / 2, maxInt / 2, nil}, // p * r too large
}

func TestKey(t *testing.T) {
	for _, v := range good {
		k, err := Key([]byte(v.password), []byte(v.salt), v.N, v.r, v.p, len(v.output))
		if err != nil {
			t.Errorf("got unexpected error: %s", err)
		}
		if !bytes.Equal(k, v.output) {
			t.Errorf("expected %x, got %x", v.output, k)
		}
	}
	for _, v := range bad {
		_, err := Key([]byte(v.password), []byte(v.salt), v.N, v.r, v.p, 32)
		if err == nil {
			t.Errorf("expected error, got nil")
		}
	}
}

func BenchmarkKey(b *testing.B) {
	for i := 0; i < b.N; i++ {
		Key([]byte("password"), []byte("salt"), 16384, 8, 1, 64)
	}
}
<commit_msg>s/Draft/Internet-Draft/<commit_after>// Copyright 2012 Dmitry Chestnykh. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package scrypt

import (
	"bytes"
	"testing"
)

type testVector struct {
	password string
	salt     string
	N, r, p  int
	output   []byte
}

var good = []testVector{
	{
		"password",
		"salt",
		2, 10, 10,
		[]byte{
			0x48, 0x2c, 0x85, 0x8e, 0x22, 0x90, 0x55, 0xe6, 0x2f,
			0x41, 0xe0, 0xec, 0x81, 0x9a, 0x5e, 0xe1, 0x8b, 0xdb,
			0x87, 0x25, 0x1a, 0x53, 0x4f, 0x75, 0xac, 0xd9, 0x5a,
			0xc5, 0xe5, 0xa, 0xa1, 0x5f,
		},
	},
	{
		"password",
		"salt",
		16, 100, 100,
		[]byte{
			0x88, 0xbd, 0x5e, 0xdb, 0x52, 0xd1, 0xdd, 0x0, 0x18,
			0x87, 0x72, 0xad, 0x36, 0x17, 0x12, 0x90, 0x22, 0x4e,
			0x74, 0x82, 0x95, 0x25, 0xb1, 0x8d, 0x73, 0x23, 0xa5,
			0x7f, 0x91, 0x96, 0x3c, 0x37,
		},
	},
	{
		"this is a long \000 password",
		"and this is a long \000 salt",
		16384, 8, 1,
		[]byte{
			0xc3, 0xf1, 0x82, 0xee, 0x2d, 0xec, 0x84, 0x6e, 0x70,
			0xa6, 0x94, 0x2f, 0xb5, 0x29, 0x98, 0x5a, 0x3a, 0x9,
			0x76, 0x5e, 0xf0, 0x4c, 0x61, 0x29, 0x23, 0xb1, 0x7f,
			0x18, 0x55, 0x5a, 0x37, 0x7, 0x6d, 0xeb, 0x2b, 0x98,
			0x30, 0xd6, 0x9d, 0xe5, 0x49, 0x26, 0x51, 0xe4, 0x50,
			0x6a, 0xe5, 0x77, 0x6d, 0x96, 0xd4, 0xf, 0x67, 0xaa,
			0xee, 0x37, 0xe1, 0x77, 0x7b, 0x8a, 0xd5, 0xc3, 0x11,
			0x14, 0x32, 0xbb, 0x3b, 0x6f, 0x7e, 0x12, 0x64, 0x40,
			0x18, 0x79, 0xe6, 0x41, 0xae,
		},
	},
	{
		"p",
		"s",
		2, 1, 1,
		[]byte{
			0x48, 0xb0, 0xd2, 0xa8, 0xa3, 0x27, 0x26, 0x11, 0x98,
			0x4c, 0x50, 0xeb, 0xd6, 0x30, 0xaf, 0x52,
		},
	},
	// Test vectors from IETF Internet-Draft.
	// http://datatracker.ietf.org/doc/draft-josefsson-scrypt-kdf/?include_text=1
	{
		"",
		"",
		16, 1, 1,
		[]byte{
			0x77, 0xd6, 0x57, 0x62, 0x38, 0x65, 0x7b, 0x20, 0x3b, 0x19, 0xca, 0x42, 0xc1, 0x8a, 0x04, 0x97,
			0xf1, 0x6b, 0x48, 0x44, 0xe3, 0x07, 0x4a, 0xe8, 0xdf, 0xdf, 0xfa, 0x3f, 0xed, 0xe2, 0x14, 0x42,
			0xfc, 0xd0, 0x06, 0x9d, 0xed, 0x09, 0x48, 0xf8, 0x32, 0x6a, 0x75, 0x3a, 0x0f, 0xc8, 0x1f, 0x17,
			0xe8, 0xd3, 0xe0, 0xfb, 0x2e, 0x0d, 0x36, 0x28, 0xcf, 0x35, 0xe2, 0x0c, 0x38, 0xd1, 0x89, 0x06,
		},
	},
	{
		"password",
		"NaCl",
		1024, 8, 16,
		[]byte{
			0xfd, 0xba, 0xbe, 0x1c, 0x9d, 0x34, 0x72, 0x00, 0x78, 0x56, 0xe7, 0x19, 0x0d, 0x01, 0xe9, 0xfe,
			0x7c, 0x6a, 0xd7, 0xcb, 0xc8, 0x23, 0x78, 0x30, 0xe7, 0x73, 0x76, 0x63, 0x4b, 0x37, 0x31, 0x62,
			0x2e, 0xaf, 0x30, 0xd9, 0x2e, 0x22, 0xa3, 0x88, 0x6f, 0xf1, 0x09, 0x27, 0x9d, 0x98, 0x30, 0xda,
			0xc7, 0x27, 0xaf, 0xb9, 0x4a, 0x83, 0xee, 0x6d, 0x83, 0x60, 0xcb, 0xdf, 0xa2, 0xcc, 0x06, 0x40,
		},
	},
	{
		"pleaseletmein", "SodiumChloride",
		16384, 8, 1,
		[]byte{
			0x70, 0x23, 0xbd, 0xcb, 0x3a, 0xfd, 0x73, 0x48, 0x46, 0x1c, 0x06, 0xcd, 0x81, 0xfd, 0x38, 0xeb,
			0xfd, 0xa8, 0xfb, 0xba, 0x90, 0x4f, 0x8e, 0x3e, 0xa9, 0xb5, 0x43, 0xf6, 0x54, 0x5d, 0xa1, 0xf2,
			0xd5, 0x43, 0x29, 0x55, 0x61, 0x3f, 0x0f, 0xcf, 0x62, 0xd4, 0x97, 0x05, 0x24, 0x2a, 0x9a, 0xf9,
			0xe6, 0x1e, 0x85, 0xdc, 0x0d, 0x65, 0x1e, 0x40, 0xdf, 0xcf, 0x01, 0x7b, 0x45, 0x57, 0x58, 0x87,
		},
	},
	/*
	// Disabled: needs 1 GiB RAM and takes too long for a simple test.
	   {
	           "pleaseletmein", "SodiumChloride",
	           1048576, 8, 1,
	           []byte{
	              0x21 , 0x01 , 0xcb , 0x9b , 0x6a , 0x51 , 0x1a , 0xae , 0xad , 0xdb , 0xbe , 0x09 , 0xcf , 0x70 , 0xf8 , 0x81,
	              0xec , 0x56 , 0x8d , 0x57 , 0x4a , 0x2f , 0xfd , 0x4d , 0xab , 0xe5 , 0xee , 0x98 , 0x20 , 0xad , 0xaa , 0x47,
	              0x8e , 0x56 , 0xfd , 0x8f , 0x4b , 0xa5 , 0xd0 , 0x9f , 0xfa , 0x1c , 0x6d , 0x92 , 0x7c , 0x40 , 0xf4 , 0xc3,
	              0x37 , 0x30 , 0x40 , 0x49 , 0xe8 , 0xa9 , 0x52 , 0xfb , 0xcb , 0xf4 , 0x5c , 0x6f , 0xa7 , 0x7a , 0x41 , 0xa4,
	           },

	   },
	*/
}

var bad = []testVector{
	{"p", "s", 0, 1, 1, nil},                    // N == 0
	{"p", "s", 1, 1, 1, nil},                    // N == 1
	{"p", "s", 7, 8, 1, nil},                    // N is not power of 2
	{"p", "s", 16, maxInt / 2, maxInt / 2, nil}, // p * r too large
}

func TestKey(t *testing.T) {
	for _, v := range good {
		k, err := Key([]byte(v.password), []byte(v.salt), v.N, v.r, v.p, len(v.output))
		if err != nil {
			t.Errorf("got unexpected error: %s", err)
		}
		if !bytes.Equal(k, v.output) {
			t.Errorf("expected %x, got %x", v.output, k)
		}
	}
	for _, v := range bad {
		_, err := Key([]byte(v.password), []byte(v.salt), v.N, v.r, v.p, 32)
		if err == nil {
			t.Errorf("expected error, got nil")
		}
	}
}

func BenchmarkKey(b *testing.B) {
	for i := 0; i < b.N; i++ {
		Key([]byte("password"), []byte("salt"), 16384, 8, 1, 64)
	}
}
<|endoftext|>


<commit_before>package main // sctl-cli

import (
	"fmt"
	"os"
	"path/filepath"

	sctl "github.com/CzarSimon/sctl-common"
	"github.com/CzarSimon/util"
	"github.com/kardianos/osext"
)

//Config holds configuration values
type Config struct {
	API     util.ServerConfig
	DB      util.SQLiteConfig
	App     AppConfig
	Folders FolderConfig
}

func getConfig() Config {
	return Config{
		API:     getAPIConfig(),
		App:     getAppConfig(),
		Folders: getFolderConfig(),
	}
}

// FolderConfig holds local and node folder info
type FolderConfig struct {
	Exec   string
	Target string
	Token  string
}

// getFolderConfig Returns the folder configuration
func getFolderConfig() FolderConfig {
	basePath, err := osext.ExecutableFolder()
	util.CheckErrFatal(err)
	separator := fmt.Sprintf("%c", os.PathSeparator)
	return FolderConfig{
		Exec:   filepath.Join(basePath, "sctl-data", "executables") + separator,
		Target: filepath.Join(basePath, "sctl-data", "executables"),
		Token:  filepath.Join(basePath, "sctl-data"),
	}
}

// AppConfig holds app metadata
type AppConfig struct {
	Version string
	Name    string
	Usage   string
}

func getAppConfig() AppConfig {
	return AppConfig{
		Version: "0.1",
		Name:    "service controller (sctl)",
		Usage:   "Command line tool for simplifying running services using docker swarm",
	}
}

func getAPIConfig() util.ServerConfig {
	return util.ServerConfig{
		Protocol: "http",
		Host:     "localhost",
		Port:     "19104",
	}
}

// SetupMinonDB Sets up and populates a minion db for tokens
func (env Env) SetupMinonDB() {
	tokens := env.GetTokens()
	db := sctl.ConnectTokenDB(env.config.Folders.Token)
	defer db.Close()
	_, err := db.Exec("DROP TABLE IF EXISTS TOKEN")
	util.CheckErrFatal(err)
	_, err = db.Exec(sctl.TokenSchema())
	util.CheckErrFatal(err)
	stmt, err := db.Prepare("INSERT INTO TOKEN(AUTH, MASTER, AUTH_TIMESTAMP) VALUES($1,$2,$3)")
	util.CheckErrFatal(err)
	_, err = stmt.Exec(tokens.Auth.Data, tokens.Master, tokens.Auth.Timestamp)
	util.CheckErrFatal(err)
}
<commit_msg>Corrected api port in cli config<commit_after>package main // sctl-cli

import (
	"fmt"
	"os"
	"path/filepath"

	sctl "github.com/CzarSimon/sctl-common"
	"github.com/CzarSimon/util"
	"github.com/kardianos/osext"
)

//Config holds configuration values
type Config struct {
	API     util.ServerConfig
	DB      util.SQLiteConfig
	App     AppConfig
	Folders FolderConfig
}

func getConfig() Config {
	return Config{
		API:     getAPIConfig(),
		App:     getAppConfig(),
		Folders: getFolderConfig(),
	}
}

// FolderConfig holds local and node folder info
type FolderConfig struct {
	Exec   string
	Target string
	Token  string
}

// getFolderConfig Returns the folder configuration
func getFolderConfig() FolderConfig {
	basePath, err := osext.ExecutableFolder()
	util.CheckErrFatal(err)
	separator := fmt.Sprintf("%c", os.PathSeparator)
	return FolderConfig{
		Exec:   filepath.Join(basePath, "sctl-data", "executables") + separator,
		Target: filepath.Join(basePath, "sctl-data", "executables"),
		Token:  filepath.Join(basePath, "sctl-data"),
	}
}

// AppConfig holds app metadata
type AppConfig struct {
	Version string
	Name    string
	Usage   string
}

func getAppConfig() AppConfig {
	return AppConfig{
		Version: "0.1",
		Name:    "service controller (sctl)",
		Usage:   "Command line tool for simplifying running services using docker swarm",
	}
}

func getAPIConfig() util.ServerConfig {
	return util.ServerConfig{
		Protocol: "http",
		Host:     "localhost",
		Port:     "9104",
	}
}

// SetupMinonDB Sets up and populates a minion db for tokens
func (env Env) SetupMinonDB() {
	tokens := env.GetTokens()
	db := sctl.ConnectTokenDB(env.config.Folders.Token)
	defer db.Close()
	_, err := db.Exec("DROP TABLE IF EXISTS TOKEN")
	util.CheckErrFatal(err)
	_, err = db.Exec(sctl.TokenSchema())
	util.CheckErrFatal(err)
	stmt, err := db.Prepare("INSERT INTO TOKEN(AUTH, MASTER, AUTH_TIMESTAMP) VALUES($1,$2,$3)")
	util.CheckErrFatal(err)
	_, err = stmt.Exec(tokens.Auth.Data, tokens.Master, tokens.Auth.Timestamp)
	util.CheckErrFatal(err)
}
<|endoftext|>


<commit_before>package gonf

func isBlank(r rune) bool {
	return r == ' ' || isLineBreak(r)
}

func isLineBreak(r rune) bool {
	return r == '\n'
}

func isValidForKey(r rune) bool {
	// 48 == '0'
	// 57 == '9'
	isNumber := r >= 48 && r <= 57

	// 97 == 'a'
	// 122 == 'z'
	isLower := r >= 97 && r <= 122

	// 65 == 'A'
	// 90 == 'Z'
	isUpper := r >= 65 && r <= 90

	return isNumber || isLower || isUpper
}

func searchingKeyState(l *lexer) state {
	r := l.next()

	if r == '#' {
		l.stack.push(l.state)
		l.state = inCommentState
		return l.state
	}

	if r == t_EOF {
		l.finish()
		return nil
	}

	if r == '}' {
		l.emit(t_MAP_END)
		l.state = l.stack.pop()
		return l.state
	}

	if r == ']' {
		l.emit(t_ARRAY_END)
		l.state = l.stack.pop()
		return l.state
	}

	if r == '"' {
		l.ignore()
		return inQuotedKeyState
	}

	if isBlank(r) {
		l.ignore()
		return searchingKeyState
	}

	return inKeyState
}

func inQuotedKeyState(l *lexer) state {
	r := l.next()

	if r == '"' {
		l.emit(t_KEY)
		return searchingValueState
	}

	if r == '\\' {
		return inQuotedBackslashedKeyState
	}

	return inQuotedKeyState
}

func inQuotedBackslashedKeyState(l *lexer) state {
	r := l.next()

	if r == '"' || r == '\\' {
		l.backup()
		l.backup()
		l.eat()
		l.next()
	}

	return inQuotedKeyState
}

func inKeyState(l *lexer) state {
	r := l.next()

	if isBlank(r) {
		l.emit(t_KEY)
		return searchingValueState
	}

	return inKeyState
}

func searchingValueState(l *lexer) state {
	r := l.next()

	if r == '#' {
		l.stack.push(l.state)
		l.state = inCommentState
		return l.state
	}

	if isBlank(r) {
		l.ignore()
		return searchingValueState
	}

	if r == '"' {
		l.ignore()
		return inQuotedValueState
	}

	if r == '}' {
		l.emit(t_MAP_END)
		l.state = l.stack.pop()
		return l.state
	}

	if r == ']' {
		l.emit(t_ARRAY_END)
		l.state = l.stack.pop()
		return l.state
	}

	if r == '{' {
		l.emit(t_MAP_START)
		l.stack.push(l.state)
		l.state = searchingKeyState
		return l.state
	}

	if r == '[' {
		l.emit(t_ARRAY_START)
		l.stack.push(l.state)
		l.state = searchingValueState
		return l.state
	}

	return inValueState
}

func inValueState(l *lexer) state {
	r := l.next()

	if isBlank(r) {
		l.emit(t_VALUE)
		return l.state
	}

	if r == t_EOF {
		l.emit(t_VALUE)
		l.finish()
		return nil
	}

	return inValueState
}

func inQuotedValueState(l *lexer) state {
	r := l.next()

	if r == '"' {
		l.emit(t_VALUE)
		return l.state
	}

	if r == '\\' {
		return inQuotedBackslashedValueState
	}

	return inQuotedValueState
}

func inQuotedBackslashedValueState(l *lexer) state {
	r := l.next()

	if r == '"' || r == '\\' {
		l.backup()
		l.backup()
		l.eat()
		l.next()
	}

	return inQuotedValueState
}

func inCommentState(l *lexer) state {
	r := l.next()

	if isLineBreak(r) {
		l.ignore()
		l.state = l.stack.pop()
		return l.state
	}

	if r == t_EOF {
		l.finish()
		return nil
	}

	return inCommentState
}
<commit_msg>add support to tabs<commit_after>package gonf

func isBlank(r rune) bool {
	return r == ' ' || r == '\t' || isLineBreak(r)
}

func isLineBreak(r rune) bool {
	return r == '\n'
}

func isValidForKey(r rune) bool {
	// 48 == '0'
	// 57 == '9'
	isNumber := r >= 48 && r <= 57

	// 97 == 'a'
	// 122 == 'z'
	isLower := r >= 97 && r <= 122

	// 65 == 'A'
	// 90 == 'Z'
	isUpper := r >= 65 && r <= 90

	return isNumber || isLower || isUpper
}

func searchingKeyState(l *lexer) state {
	r := l.next()

	if r == '#' {
		l.stack.push(l.state)
		l.state = inCommentState
		return l.state
	}

	if r == t_EOF {
		l.finish()
		return nil
	}

	if r == '}' {
		l.emit(t_MAP_END)
		l.state = l.stack.pop()
		return l.state
	}

	if r == ']' {
		l.emit(t_ARRAY_END)
		l.state = l.stack.pop()
		return l.state
	}

	if r == '"' {
		l.ignore()
		return inQuotedKeyState
	}

	if isBlank(r) {
		l.ignore()
		return searchingKeyState
	}

	return inKeyState
}

func inQuotedKeyState(l *lexer) state {
	r := l.next()

	if r == '"' {
		l.emit(t_KEY)
		return searchingValueState
	}

	if r == '\\' {
		return inQuotedBackslashedKeyState
	}

	return inQuotedKeyState
}

func inQuotedBackslashedKeyState(l *lexer) state {
	r := l.next()

	if r == '"' || r == '\\' {
		l.backup()
		l.backup()
		l.eat()
		l.next()
	}

	return inQuotedKeyState
}

func inKeyState(l *lexer) state {
	r := l.next()

	if isBlank(r) {
		l.emit(t_KEY)
		return searchingValueState
	}

	return inKeyState
}

func searchingValueState(l *lexer) state {
	r := l.next()

	if r == '#' {
		l.stack.push(l.state)
		l.state = inCommentState
		return l.state
	}

	if isBlank(r) {
		l.ignore()
		return searchingValueState
	}

	if r == '"' {
		l.ignore()
		return inQuotedValueState
	}

	if r == '}' {
		l.emit(t_MAP_END)
		l.state = l.stack.pop()
		return l.state
	}

	if r == ']' {
		l.emit(t_ARRAY_END)
		l.state = l.stack.pop()
		return l.state
	}

	if r == '{' {
		l.emit(t_MAP_START)
		l.stack.push(l.state)
		l.state = searchingKeyState
		return l.state
	}

	if r == '[' {
		l.emit(t_ARRAY_START)
		l.stack.push(l.state)
		l.state = searchingValueState
		return l.state
	}

	return inValueState
}

func inValueState(l *lexer) state {
	r := l.next()

	if isBlank(r) {
		l.emit(t_VALUE)
		return l.state
	}

	if r == t_EOF {
		l.emit(t_VALUE)
		l.finish()
		return nil
	}

	return inValueState
}

func inQuotedValueState(l *lexer) state {
	r := l.next()

	if r == '"' {
		l.emit(t_VALUE)
		return l.state
	}

	if r == '\\' {
		return inQuotedBackslashedValueState
	}

	return inQuotedValueState
}

func inQuotedBackslashedValueState(l *lexer) state {
	r := l.next()

	if r == '"' || r == '\\' {
		l.backup()
		l.backup()
		l.eat()
		l.next()
	}

	return inQuotedValueState
}

func inCommentState(l *lexer) state {
	r := l.next()

	if isLineBreak(r) {
		l.ignore()
		l.state = l.stack.pop()
		return l.state
	}

	if r == t_EOF {
		l.finish()
		return nil
	}

	return inCommentState
}
<|endoftext|>


<commit_before>package fasthttp

import (
	"fmt"
	"sync/atomic"
)

// HTTP status codes were stolen from net/http.
const (
	StatusContinue           = 100
	StatusSwitchingProtocols = 101

	StatusOK                   = 200
	StatusCreated              = 201
	StatusAccepted             = 202
	StatusNonAuthoritativeInfo = 203
	StatusNoContent            = 204
	StatusResetContent         = 205
	StatusPartialContent       = 206

	StatusMultipleChoices   = 300
	StatusMovedPermanently  = 301
	StatusFound             = 302
	StatusSeeOther          = 303
	StatusNotModified       = 304
	StatusUseProxy          = 305
	StatusTemporaryRedirect = 307

	StatusBadRequest                   = 400
	StatusUnauthorized                 = 401
	StatusPaymentRequired              = 402
	StatusForbidden                    = 403
	StatusNotFound                     = 404
	StatusMethodNotAllowed             = 405
	StatusNotAcceptable                = 406
	StatusProxyAuthRequired            = 407
	StatusRequestTimeout               = 408
	StatusConflict                     = 409
	StatusGone                         = 410
	StatusLengthRequired               = 411
	StatusPreconditionFailed           = 412
	StatusRequestEntityTooLarge        = 413
	StatusRequestURITooLong            = 414
	StatusUnsupportedMediaType         = 415
	StatusRequestedRangeNotSatisfiable = 416
	StatusExpectationFailed            = 417
	StatusTeapot                       = 418
	StatusPreconditionRequired         = 428
	StatusTooManyRequests              = 429
	StatusRequestHeaderFieldsTooLarge  = 431

	StatusInternalServerError           = 500
	StatusNotImplemented                = 501
	StatusBadGateway                    = 502
	StatusServiceUnavailable            = 503
	StatusGatewayTimeout                = 504
	StatusHTTPVersionNotSupported       = 505
	StatusNetworkAuthenticationRequired = 511
)

var (
	statusLines atomic.Value

	statusMessages = map[int]string{
		StatusContinue:           "Continue",
		StatusSwitchingProtocols: "SwitchingProtocols",

		StatusOK:                   "OK",
		StatusCreated:              "Created",
		StatusAccepted:             "Accepted",
		StatusNonAuthoritativeInfo: "Non-Authoritative Info",
		StatusNoContent:            "No Content",
		StatusResetContent:         "Reset Content",
		StatusPartialContent:       "Partial Content",

		StatusMultipleChoices:   "Multiple Choices",
		StatusMovedPermanently:  "Moved Permanently",
		StatusFound:             "Found",
		StatusSeeOther:          "See Other",
		StatusNotModified:       "Not Modified",
		StatusUseProxy:          "Use Proxy",
		StatusTemporaryRedirect: "Temporary Redirect",

		StatusBadRequest:                   "Bad Request",
		StatusUnauthorized:                 "Unauthorized",
		StatusPaymentRequired:              "Payment Required",
		StatusForbidden:                    "Forbidden",
		StatusNotFound:                     "Not Found",
		StatusMethodNotAllowed:             "Method Not Allowed",
		StatusNotAcceptable:                "Not Acceptable",
		StatusProxyAuthRequired:            "Proxy Auth Required",
		StatusRequestTimeout:               "Request Timeout",
		StatusConflict:                     "Conflict",
		StatusGone:                         "Gone",
		StatusLengthRequired:               "Length Required",
		StatusPreconditionFailed:           "Precondition Failed",
		StatusRequestEntityTooLarge:        "Request Entity Too Large",
		StatusRequestURITooLong:            "Request URI Too Long",
		StatusUnsupportedMediaType:         "Unsupported Media Type",
		StatusRequestedRangeNotSatisfiable: "Requested Range Not Satisfiable",
		StatusExpectationFailed:            "Expectation Failed",
		StatusTeapot:                       "Teapot",

		StatusInternalServerError:     "Internal Server Error",
		StatusNotImplemented:          "Not Implemented",
		StatusBadGateway:              "Bad Gateway",
		StatusServiceUnavailable:      "Service Unavailable",
		StatusGatewayTimeout:          "Gateway Timeout",
		StatusHTTPVersionNotSupported: "HTTP Version Not Supported",
	}
)

// StatusMessage returns HTTP status message for the given status code.
func StatusMessage(statusCode int) string {
	s := statusMessages[statusCode]
	if s == "" {
		s = "Unknown Status Code"
	}
	return s
}

func init() {
	statusLines.Store(make(map[int][]byte))
}

func statusLine(statusCode int) []byte {
	m := statusLines.Load().(map[int][]byte)
	h := m[statusCode]
	if h != nil {
		return h
	}

	statusText := StatusMessage(statusCode)

	h = []byte(fmt.Sprintf("HTTP/1.1 %d %s\r\n", statusCode, statusText))
	newM := make(map[int][]byte, len(m)+1)
	for k, v := range m {
		newM[k] = v
	}
	newM[statusCode] = h
	statusLines.Store(newM)
	return h
}
<commit_msg>Add missing messages to statusMessages (#109)<commit_after>package fasthttp

import (
	"fmt"
	"sync/atomic"
)

// HTTP status codes were stolen from net/http.
const (
	StatusContinue           = 100
	StatusSwitchingProtocols = 101

	StatusOK                   = 200
	StatusCreated              = 201
	StatusAccepted             = 202
	StatusNonAuthoritativeInfo = 203
	StatusNoContent            = 204
	StatusResetContent         = 205
	StatusPartialContent       = 206

	StatusMultipleChoices   = 300
	StatusMovedPermanently  = 301
	StatusFound             = 302
	StatusSeeOther          = 303
	StatusNotModified       = 304
	StatusUseProxy          = 305
	StatusTemporaryRedirect = 307

	StatusBadRequest                   = 400
	StatusUnauthorized                 = 401
	StatusPaymentRequired              = 402
	StatusForbidden                    = 403
	StatusNotFound                     = 404
	StatusMethodNotAllowed             = 405
	StatusNotAcceptable                = 406
	StatusProxyAuthRequired            = 407
	StatusRequestTimeout               = 408
	StatusConflict                     = 409
	StatusGone                         = 410
	StatusLengthRequired               = 411
	StatusPreconditionFailed           = 412
	StatusRequestEntityTooLarge        = 413
	StatusRequestURITooLong            = 414
	StatusUnsupportedMediaType         = 415
	StatusRequestedRangeNotSatisfiable = 416
	StatusExpectationFailed            = 417
	StatusTeapot                       = 418
	StatusPreconditionRequired         = 428
	StatusTooManyRequests              = 429
	StatusRequestHeaderFieldsTooLarge  = 431

	StatusInternalServerError           = 500
	StatusNotImplemented                = 501
	StatusBadGateway                    = 502
	StatusServiceUnavailable            = 503
	StatusGatewayTimeout                = 504
	StatusHTTPVersionNotSupported       = 505
	StatusNetworkAuthenticationRequired = 511
)

var (
	statusLines atomic.Value

	statusMessages = map[int]string{
		StatusContinue:           "Continue",
		StatusSwitchingProtocols: "SwitchingProtocols",

		StatusOK:                   "OK",
		StatusCreated:              "Created",
		StatusAccepted:             "Accepted",
		StatusNonAuthoritativeInfo: "Non-Authoritative Info",
		StatusNoContent:            "No Content",
		StatusResetContent:         "Reset Content",
		StatusPartialContent:       "Partial Content",

		StatusMultipleChoices:   "Multiple Choices",
		StatusMovedPermanently:  "Moved Permanently",
		StatusFound:             "Found",
		StatusSeeOther:          "See Other",
		StatusNotModified:       "Not Modified",
		StatusUseProxy:          "Use Proxy",
		StatusTemporaryRedirect: "Temporary Redirect",

		StatusBadRequest:                   "Bad Request",
		StatusUnauthorized:                 "Unauthorized",
		StatusPaymentRequired:              "Payment Required",
		StatusForbidden:                    "Forbidden",
		StatusNotFound:                     "Not Found",
		StatusMethodNotAllowed:             "Method Not Allowed",
		StatusNotAcceptable:                "Not Acceptable",
		StatusProxyAuthRequired:            "Proxy Auth Required",
		StatusRequestTimeout:               "Request Timeout",
		StatusConflict:                     "Conflict",
		StatusGone:                         "Gone",
		StatusLengthRequired:               "Length Required",
		StatusPreconditionFailed:           "Precondition Failed",
		StatusRequestEntityTooLarge:        "Request Entity Too Large",
		StatusRequestURITooLong:            "Request URI Too Long",
		StatusUnsupportedMediaType:         "Unsupported Media Type",
		StatusRequestedRangeNotSatisfiable: "Requested Range Not Satisfiable",
		StatusExpectationFailed:            "Expectation Failed",
		StatusTeapot:                       "Teapot",
		StatusPreconditionRequired:         "Precondition Required",
		StatusTooManyRequests:              "Too Many Requests",
		StatusRequestHeaderFieldsTooLarge:  "Request HeaderFields Too Large",

		StatusInternalServerError:           "Internal Server Error",
		StatusNotImplemented:                "Not Implemented",
		StatusBadGateway:                    "Bad Gateway",
		StatusServiceUnavailable:            "Service Unavailable",
		StatusGatewayTimeout:                "Gateway Timeout",
		StatusHTTPVersionNotSupported:       "HTTP Version Not Supported",
		StatusNetworkAuthenticationRequired: "Network Authentication Required",
	}
)

// StatusMessage returns HTTP status message for the given status code.
func StatusMessage(statusCode int) string {
	s := statusMessages[statusCode]
	if s == "" {
		s = "Unknown Status Code"
	}
	return s
}

func init() {
	statusLines.Store(make(map[int][]byte))
}

func statusLine(statusCode int) []byte {
	m := statusLines.Load().(map[int][]byte)
	h := m[statusCode]
	if h != nil {
		return h
	}

	statusText := StatusMessage(statusCode)

	h = []byte(fmt.Sprintf("HTTP/1.1 %d %s\r\n", statusCode, statusText))
	newM := make(map[int][]byte, len(m)+1)
	for k, v := range m {
		newM[k] = v
	}
	newM[statusCode] = h
	statusLines.Store(newM)
	return h
}
<|endoftext|>


<commit_before>package csaupgrade

import (
	"bytes"
	"fmt"

	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
)

const csaAnnotationName = "kubectl.kubernetes.io/last-applied-configuration"

var csaAnnotationFieldSet = fieldpath.NewSet(fieldpath.MakePathOrDie("metadata", "annotations", csaAnnotationName))

// Upgrades the Manager information for fields managed with client-side-apply (CSA)
// Prepares fields owned by `csaManager` for 'Update' operations for use now
// with the given `ssaManager` for `Apply` operations.
//
// This transformation should be performed on an object if it has been previously
// managed using client-side-apply to prepare it for future use with
// server-side-apply.
//
// Caveats:
//  1. This operation is not reversible. Information about which fields the client
//     owned will be lost in this operation.
//  2. Supports being performed either before or after initial server-side apply.
//  3. Client-side apply tends to own more fields (including fields that are defaulted),
//     this will possibly remove this defaults, they will be re-defaulted, that's fine.
//  4. Care must be taken to not overwrite the managed fields on the server if they
//     have changed before sending a patch.
//
// obj - Target of the operation which has been managed with CSA in the past
// csaManagerName - Name of FieldManager formerly used for `Update` operations
// ssaManagerName - Name of FieldManager formerly used for `Apply` operations
// Returns: a copy of the `obj` paramter with its managed fields modified so that
// it may be used with server-side apply in the future.
func UpgradeManagedFields(
	obj runtime.Object,
	csaManagerName string,
	ssaManagerName string,
) error {
	accessor, err := meta.Accessor(obj)
	if err != nil {
		return fmt.Errorf("error accessing object metadata: %w", err)
	}

	// Create managed fields clone since we modify the values
	var managedFields []metav1.ManagedFieldsEntry
	managedFields = append(managedFields, accessor.GetManagedFields()...)

	// Locate SSA manager
	replaceIndex, managerExists := findFirstIndex(managedFields,
		func(entry metav1.ManagedFieldsEntry) bool {
			return entry.Manager == ssaManagerName &&
				entry.Operation == metav1.ManagedFieldsOperationApply &&
				entry.Subresource == ""
		})

	if !managerExists {
		// SSA manager does not exist. Find the most recent matching CSA manager,
		// convert it to an SSA manager.
		//
		// (find first index, since managed fields are sorted so that most recent is
		//  first in the list)
		replaceIndex, managerExists = findFirstIndex(managedFields,
			func(entry metav1.ManagedFieldsEntry) bool {
				return entry.Manager == csaManagerName &&
					entry.Operation == metav1.ManagedFieldsOperationUpdate &&
					entry.Subresource == ""
			})

		if !managerExists {
			// There are no CSA managers that need to be converted. Nothing to do
			// Return early
			return nil
		}

		// Convert CSA manager into SSA manager
		managedFields[replaceIndex].Operation = metav1.ManagedFieldsOperationApply
		managedFields[replaceIndex].Manager = ssaManagerName
	}
	err = unionManagerIntoIndex(managedFields, replaceIndex, csaManagerName)
	if err != nil {
		return err
	}

	// Create version of managed fields which has no CSA managers with the given name
	filteredManagers := filter(managedFields, func(entry metav1.ManagedFieldsEntry) bool {
		return !(entry.Manager == csaManagerName &&
			entry.Operation == metav1.ManagedFieldsOperationUpdate &&
			entry.Subresource == "")
	})

	// Wipe out last-applied-configuration annotation if it exists
	annotations := accessor.GetAnnotations()
	delete(annotations, csaAnnotationName)

	// Commit changes to object
	accessor.SetAnnotations(annotations)
	accessor.SetManagedFields(filteredManagers)

	return nil
}

// Locates an Update manager entry named `csaManagerName` with the same APIVersion
// as the manager at the targetIndex. Unions both manager's fields together
// into the manager specified by `targetIndex`. No other managers are modified.
func unionManagerIntoIndex(entries []metav1.ManagedFieldsEntry, targetIndex int, csaManagerName string) error {
	ssaManager := entries[targetIndex]

	// find Update manager of same APIVersion, union ssa fields with it.
	// discard all other Update managers of the same name
	csaManagerIndex, csaManagerExists := findFirstIndex(entries,
		func(entry metav1.ManagedFieldsEntry) bool {
			return entry.Manager == csaManagerName &&
				entry.Operation == metav1.ManagedFieldsOperationUpdate &&
				entry.Subresource == "" &&
				entry.APIVersion == ssaManager.APIVersion
		})

	targetFieldSet, err := decodeManagedFieldsEntrySet(ssaManager)
	if err != nil {
		return fmt.Errorf("failed to convert fields to set: %w", err)
	}

	combinedFieldSet := &targetFieldSet

	// Union the csa manager with the existing SSA manager. Do nothing if
	// there was no good candidate found
	if csaManagerExists {
		csaManager := entries[csaManagerIndex]

		csaFieldSet, err := decodeManagedFieldsEntrySet(csaManager)
		if err != nil {
			return fmt.Errorf("failed to convert fields to set: %w", err)
		}

		combinedFieldSet = combinedFieldSet.Union(&csaFieldSet)
	}

	// Ensure that the resultant fieldset does not include the
	// last applied annotation
	combinedFieldSet = combinedFieldSet.Difference(csaAnnotationFieldSet)

	// Encode the fields back to the serialized format
	err = encodeManagedFieldsEntrySet(&entries[targetIndex], *combinedFieldSet)
	if err != nil {
		return fmt.Errorf("failed to encode field set: %w", err)
	}

	return nil
}

func findFirstIndex[T any](
	collection []T,
	predicate func(T) bool,
) (int, bool) {
	for idx, entry := range collection {
		if predicate(entry) {
			return idx, true
		}
	}

	return -1, false
}

func filter[T any](
	collection []T,
	predicate func(T) bool,
) []T {
	result := make([]T, 0, len(collection))

	for _, value := range collection {
		if predicate(value) {
			result = append(result, value)
		}
	}

	if len(result) == 0 {
		return nil
	}

	return result
}

// Included from fieldmanager.internal to avoid dependency cycle
// FieldsToSet creates a set paths from an input trie of fields
func decodeManagedFieldsEntrySet(f metav1.ManagedFieldsEntry) (s fieldpath.Set, err error) {
	err = s.FromJSON(bytes.NewReader(f.FieldsV1.Raw))
	return s, err
}

// SetToFields creates a trie of fields from an input set of paths
func encodeManagedFieldsEntrySet(f *metav1.ManagedFieldsEntry, s fieldpath.Set) (err error) {
	f.FieldsV1.Raw, err = s.ToJSON()
	return err
}
<commit_msg>remove inaccurate comment<commit_after>package csaupgrade

import (
	"bytes"
	"fmt"

	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
)

const csaAnnotationName = "kubectl.kubernetes.io/last-applied-configuration"

var csaAnnotationFieldSet = fieldpath.NewSet(fieldpath.MakePathOrDie("metadata", "annotations", csaAnnotationName))

// Upgrades the Manager information for fields managed with client-side-apply (CSA)
// Prepares fields owned by `csaManager` for 'Update' operations for use now
// with the given `ssaManager` for `Apply` operations.
//
// This transformation should be performed on an object if it has been previously
// managed using client-side-apply to prepare it for future use with
// server-side-apply.
//
// Caveats:
//  1. This operation is not reversible. Information about which fields the client
//     owned will be lost in this operation.
//  2. Supports being performed either before or after initial server-side apply.
//  3. Client-side apply tends to own more fields (including fields that are defaulted),
//     this will possibly remove this defaults, they will be re-defaulted, that's fine.
//  4. Care must be taken to not overwrite the managed fields on the server if they
//     have changed before sending a patch.
//
// obj - Target of the operation which has been managed with CSA in the past
// csaManagerName - Name of FieldManager formerly used for `Update` operations
// ssaManagerName - Name of FieldManager formerly used for `Apply` operations
func UpgradeManagedFields(
	obj runtime.Object,
	csaManagerName string,
	ssaManagerName string,
) error {
	accessor, err := meta.Accessor(obj)
	if err != nil {
		return fmt.Errorf("error accessing object metadata: %w", err)
	}

	// Create managed fields clone since we modify the values
	var managedFields []metav1.ManagedFieldsEntry
	managedFields = append(managedFields, accessor.GetManagedFields()...)

	// Locate SSA manager
	replaceIndex, managerExists := findFirstIndex(managedFields,
		func(entry metav1.ManagedFieldsEntry) bool {
			return entry.Manager == ssaManagerName &&
				entry.Operation == metav1.ManagedFieldsOperationApply &&
				entry.Subresource == ""
		})

	if !managerExists {
		// SSA manager does not exist. Find the most recent matching CSA manager,
		// convert it to an SSA manager.
		//
		// (find first index, since managed fields are sorted so that most recent is
		//  first in the list)
		replaceIndex, managerExists = findFirstIndex(managedFields,
			func(entry metav1.ManagedFieldsEntry) bool {
				return entry.Manager == csaManagerName &&
					entry.Operation == metav1.ManagedFieldsOperationUpdate &&
					entry.Subresource == ""
			})

		if !managerExists {
			// There are no CSA managers that need to be converted. Nothing to do
			// Return early
			return nil
		}

		// Convert CSA manager into SSA manager
		managedFields[replaceIndex].Operation = metav1.ManagedFieldsOperationApply
		managedFields[replaceIndex].Manager = ssaManagerName
	}
	err = unionManagerIntoIndex(managedFields, replaceIndex, csaManagerName)
	if err != nil {
		return err
	}

	// Create version of managed fields which has no CSA managers with the given name
	filteredManagers := filter(managedFields, func(entry metav1.ManagedFieldsEntry) bool {
		return !(entry.Manager == csaManagerName &&
			entry.Operation == metav1.ManagedFieldsOperationUpdate &&
			entry.Subresource == "")
	})

	// Wipe out last-applied-configuration annotation if it exists
	annotations := accessor.GetAnnotations()
	delete(annotations, csaAnnotationName)

	// Commit changes to object
	accessor.SetAnnotations(annotations)
	accessor.SetManagedFields(filteredManagers)

	return nil
}

// Locates an Update manager entry named `csaManagerName` with the same APIVersion
// as the manager at the targetIndex. Unions both manager's fields together
// into the manager specified by `targetIndex`. No other managers are modified.
func unionManagerIntoIndex(entries []metav1.ManagedFieldsEntry, targetIndex int, csaManagerName string) error {
	ssaManager := entries[targetIndex]

	// find Update manager of same APIVersion, union ssa fields with it.
	// discard all other Update managers of the same name
	csaManagerIndex, csaManagerExists := findFirstIndex(entries,
		func(entry metav1.ManagedFieldsEntry) bool {
			return entry.Manager == csaManagerName &&
				entry.Operation == metav1.ManagedFieldsOperationUpdate &&
				entry.Subresource == "" &&
				entry.APIVersion == ssaManager.APIVersion
		})

	targetFieldSet, err := decodeManagedFieldsEntrySet(ssaManager)
	if err != nil {
		return fmt.Errorf("failed to convert fields to set: %w", err)
	}

	combinedFieldSet := &targetFieldSet

	// Union the csa manager with the existing SSA manager. Do nothing if
	// there was no good candidate found
	if csaManagerExists {
		csaManager := entries[csaManagerIndex]

		csaFieldSet, err := decodeManagedFieldsEntrySet(csaManager)
		if err != nil {
			return fmt.Errorf("failed to convert fields to set: %w", err)
		}

		combinedFieldSet = combinedFieldSet.Union(&csaFieldSet)
	}

	// Ensure that the resultant fieldset does not include the
	// last applied annotation
	combinedFieldSet = combinedFieldSet.Difference(csaAnnotationFieldSet)

	// Encode the fields back to the serialized format
	err = encodeManagedFieldsEntrySet(&entries[targetIndex], *combinedFieldSet)
	if err != nil {
		return fmt.Errorf("failed to encode field set: %w", err)
	}

	return nil
}

func findFirstIndex[T any](
	collection []T,
	predicate func(T) bool,
) (int, bool) {
	for idx, entry := range collection {
		if predicate(entry) {
			return idx, true
		}
	}

	return -1, false
}

func filter[T any](
	collection []T,
	predicate func(T) bool,
) []T {
	result := make([]T, 0, len(collection))

	for _, value := range collection {
		if predicate(value) {
			result = append(result, value)
		}
	}

	if len(result) == 0 {
		return nil
	}

	return result
}

// Included from fieldmanager.internal to avoid dependency cycle
// FieldsToSet creates a set paths from an input trie of fields
func decodeManagedFieldsEntrySet(f metav1.ManagedFieldsEntry) (s fieldpath.Set, err error) {
	err = s.FromJSON(bytes.NewReader(f.FieldsV1.Raw))
	return s, err
}

// SetToFields creates a trie of fields from an input set of paths
func encodeManagedFieldsEntrySet(f *metav1.ManagedFieldsEntry, s fieldpath.Set) (err error) {
	f.FieldsV1.Raw, err = s.ToJSON()
	return err
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/kyma-project/kyma/components/event-bus/internal/knative/subscription/controller/subscription"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"github.com/go-logr/logr"
	pushv1alpha1 "github.com/kyma-project/kyma/components/event-bus/api/push/eventing.kyma-project.io/v1alpha1"
	"github.com/kyma-project/kyma/components/event-bus/internal/common"
	eav1alpha1 "github.com/kyma-project/kyma/components/event-bus/internal/ea/apis/applicationconnector.kyma-project.io/v1alpha1"
	"github.com/kyma-project/kyma/components/event-bus/internal/knative/subscription/controller/eventactivation"
	"github.com/kyma-project/kyma/components/event-bus/internal/knative/subscription/opts"
	"sigs.k8s.io/controller-runtime/pkg/client/config"
	"sigs.k8s.io/controller-runtime/pkg/manager"
	logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
	"sigs.k8s.io/controller-runtime/pkg/runtime/signals"
)

func main() {
	sckOpts := opts.ParseFlags()

	logf.SetLogger(logf.ZapLogger(false))
	log := logf.Log.WithName("entrypoint")

	// Get a config to talk to the apiserver
	log.Info("setting up client for manager")
	cfg, err := config.GetConfig()
	if err != nil {
		log.Error(err, "unable to set up client config")
		os.Exit(1)
	}

	// Create a new Cmd to provide shared dependencies and start components
	log.Info("setting up manager")
	mgr, err := manager.New(cfg, manager.Options{})
	if err != nil {
		log.Error(err, "unable to set up overall controller manager")
		os.Exit(1)
	}

	log.Info("Registering Components.")

	// Setup Scheme for all resources
	log.Info("setting up scheme")
	if err := pushv1alpha1.AddToScheme(mgr.GetScheme()); err != nil {
		log.Error(err, "unable to add push APIs to scheme")
		os.Exit(1)
	}
	if err := eav1alpha1.AddToScheme(mgr.GetScheme()); err != nil {
		log.Error(err, "unable to add event activation APIs to scheme")
		os.Exit(1)
	}

	// Setup all Controllers
	log.Info("Setting up Subscription Controller")
	_, err = subscription.ProvideController(mgr, sckOpts)
	if err != nil {
		log.Error(err,"Unable to create Subscription controller")
		os.Exit(1)
	}

	log.Info("Setting up Event Activation Controller")
	_, err = eventactivation.ProvideController(mgr)
	if err != nil {
		log.Error(err,"Unable to create Event Activation controller")
		os.Exit(1)
	}

	// Set up healthcheck handlers
	serveMux := http.NewServeMux()
	serveMux.Handle("/v1/status/live", statusLiveHandler(&mgr, log))
	serveMux.Handle("/v1/status/ready", statusReadyHandler(&mgr, log))

	// Start HTTP server for healthchecks
	log.Info("HTTP server starting on", "port", sckOpts.Port)
	go func() {
		if err := http.ListenAndServe(fmt.Sprintf(":%v", sckOpts.Port), serveMux); err != nil {
			log.Error(err, "HTTP server failed with error")
		}
	}()

	signalChannel := make(chan os.Signal, 2)
	signal.Notify(signalChannel, os.Interrupt,
		syscall.SIGTERM, syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT)
	go func() {
		sig := <-signalChannel
		switch sig {
		case os.Interrupt:
			println("Subscription controller manager signaled with: os.Interrupt")
			println("Signal: ", sig)
		case syscall.SIGTERM:
			println("Subscription controller manager signaled with: SIGTERM")
			println("Signal: ", sig)
		case syscall.SIGHUP:
			println("Subscription controller manager signaled with: SIGHUP")
			println("Signal: ", sig)
		case syscall.SIGINT:
			println("Subscription controller manager signaled with: SIGINT")
			println("Signal: ", sig)
		case syscall.SIGQUIT:
			println("Subscription controller manager signaled with: SIGQUIT")
			println("Signal: ", sig)
		}
	}()

	// Start the Cmd
	log.Info("Starting the Cmd.")
	if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
		log.Error(err, "unable to run the manager")
		os.Exit(1)
	}

}

var statusLive, statusReady common.StatusReady

func statusLiveHandler(manager *manager.Manager, log logr.Logger) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if manager != nil {
			if statusLive.SetReady() {
				log.Info("statusLiveHandler :: Status: READY")
			}
			w.WriteHeader(http.StatusOK)
		} else {
			statusLive.SetNotReady()
			log.Info("statusLiveHandler :: Status: NOT_READY")
			w.WriteHeader(http.StatusBadGateway)
		}
	})
}

func statusReadyHandler(manager *manager.Manager, log logr.Logger) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if manager != nil {
			if statusReady.SetReady() {
				log.Info("statusReadyHandler :: Status: READY")
			}
			w.WriteHeader(http.StatusOK)
		} else {
			statusReady.SetNotReady()
			log.Info("statusReadyHandler :: Status: NOT_READY")
			w.WriteHeader(http.StatusBadGateway)
		}
	})
}
<commit_msg>Add graceful shutdown to subscription controller (#3148)<commit_after>package main

import (
	"context"
	"fmt"
	"net/http"
	"os"
	"time"

	"github.com/go-logr/logr"
	pushv1alpha1 "github.com/kyma-project/kyma/components/event-bus/api/push/eventing.kyma-project.io/v1alpha1"
	"github.com/kyma-project/kyma/components/event-bus/internal/common"
	eav1alpha1 "github.com/kyma-project/kyma/components/event-bus/internal/ea/apis/applicationconnector.kyma-project.io/v1alpha1"
	"github.com/kyma-project/kyma/components/event-bus/internal/knative/subscription/controller/eventactivation"
	"github.com/kyma-project/kyma/components/event-bus/internal/knative/subscription/controller/subscription"
	"github.com/kyma-project/kyma/components/event-bus/internal/knative/subscription/opts"
	"sigs.k8s.io/controller-runtime/pkg/client/config"
	"sigs.k8s.io/controller-runtime/pkg/manager"
	logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
	"sigs.k8s.io/controller-runtime/pkg/runtime/signals"
)

func main() {
	sckOpts := opts.ParseFlags()

	logf.SetLogger(logf.ZapLogger(false))
	log := logf.Log.WithName("entrypoint")

	// Get a config to talk to the apiserver
	log.Info("setting up client for manager")
	cfg, err := config.GetConfig()
	if err != nil {
		log.Error(err, "unable to set up client config")
		os.Exit(1)
	}

	// Create a new Cmd to provide shared dependencies and start components
	log.Info("setting up manager")
	mgr, err := manager.New(cfg, manager.Options{})
	if err != nil {
		log.Error(err, "unable to set up overall controller manager")
		os.Exit(1)
	}

	log.Info("Registering Components.")

	// Setup Scheme for all resources
	log.Info("setting up scheme")
	if err := pushv1alpha1.AddToScheme(mgr.GetScheme()); err != nil {
		log.Error(err, "unable to add push APIs to scheme")
		os.Exit(1)
	}
	if err := eav1alpha1.AddToScheme(mgr.GetScheme()); err != nil {
		log.Error(err, "unable to add event activation APIs to scheme")
		os.Exit(1)
	}

	// Setup all Controllers
	log.Info("Setting up Subscription Controller")
	_, err = subscription.ProvideController(mgr, sckOpts)
	if err != nil {
		log.Error(err, "Unable to create Subscription controller")
		os.Exit(1)
	}

	log.Info("Setting up Event Activation Controller")
	_, err = eventactivation.ProvideController(mgr)
	if err != nil {
		log.Error(err, "Unable to create Event Activation controller")
		os.Exit(1)
	}

	// set up signals so we handle the first shutdown signal gracefully
	stopCh := signals.SetupSignalHandler()

	// Start the Manager
	log.Info("Starting the manager.")
	go func() {
		if err := mgr.Start(stopCh); err != nil {
			log.Error(err, "unable to run the manager")
			os.Exit(1)
		}
	}()

	// Set up health check handlers
	serveMux := http.NewServeMux()
	serveMux.Handle("/v1/status/live", statusLiveHandler(&mgr, log))
	serveMux.Handle("/v1/status/ready", statusReadyHandler(&mgr, log))
	server := http.Server{
		Addr:    fmt.Sprintf(":%d", sckOpts.Port),
		Handler: serveMux,
	}

	// Start HTTP server for health checks
	log.Info("HTTP server starting on", "port", sckOpts.Port)
	go func() {
		if err := server.ListenAndServe(); err != nil {
			log.Error(err, "HTTP server failed with error")
			os.Exit(1)
		}
	}()

	<-stopCh

	log.Info("Signal received, shutting down gracefully")
	// Close the http server gracefully
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	server.Shutdown(ctx)
}

var statusLive, statusReady common.StatusReady

func statusLiveHandler(manager *manager.Manager, log logr.Logger) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if manager != nil {
			if statusLive.SetReady() {
				log.Info("statusLiveHandler :: Status: READY")
			}
			w.WriteHeader(http.StatusOK)
		} else {
			statusLive.SetNotReady()
			log.Info("statusLiveHandler :: Status: NOT_READY")
			w.WriteHeader(http.StatusBadGateway)
		}
	})
}

func statusReadyHandler(manager *manager.Manager, log logr.Logger) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if manager != nil {
			if statusReady.SetReady() {
				log.Info("statusReadyHandler :: Status: READY")
			}
			w.WriteHeader(http.StatusOK)
		} else {
			statusReady.SetNotReady()
			log.Info("statusReadyHandler :: Status: NOT_READY")
			w.WriteHeader(http.StatusBadGateway)
		}
	})
}
<|endoftext|>


<commit_before>package aspect

import (
	"testing"
)

func TestSelect(t *testing.T) {
	// All three of these select statements should produce the same output
	s := Select(users.C["id"], users.C["name"])
	expectedSQL(
		t,
		s,
		`SELECT "users"."id", "users"."name" FROM "users"`,
		0,
	)

	// Add an ORDER BY
	expectedSQL(
		t,
		s.OrderBy(users.C["id"].Desc()),
		`SELECT "users"."id", "users"."name" FROM "users" ORDER BY "users"."id" DESC`,
		0,
	)

	// Build a GROUP BY statement with sorting using an aggregate
	expectedSQL(
		t,
		Select(views.C["user_id"], Count(views.C["timestamp"])).GroupBy(views.C["user_id"]).OrderBy(Count(views.C["timestamp"]).Desc()),
		`SELECT "views"."user_id", COUNT("views"."timestamp") FROM "views" GROUP BY "views"."user_id" ORDER BY COUNT("views"."timestamp") DESC`,
		0,
	)

	// Add a conditional
	expectedSQL(
		t,
		Select(users.C["name"]).Where(users.C["id"].Equals(1)),
		`SELECT "users"."name" FROM "users" WHERE "users"."id" = $1`,
		1,
	)
}
<commit_msg>Added tests for Limit and Offset methods of SelectStmt instances<commit_after>package aspect

import (
	"testing"
)

func TestSelect(t *testing.T) {
	// All three of these select statements should produce the same output
	s := Select(users.C["id"], users.C["name"])
	expectedSQL(
		t,
		s,
		`SELECT "users"."id", "users"."name" FROM "users"`,
		0,
	)

	// Add an ORDER BY
	expectedSQL(
		t,
		s.OrderBy(users.C["id"].Desc()),
		`SELECT "users"."id", "users"."name" FROM "users" ORDER BY "users"."id" DESC`,
		0,
	)

	// Build a GROUP BY statement with sorting using an aggregate
	expectedSQL(
		t,
		Select(views.C["user_id"], Count(views.C["timestamp"])).GroupBy(views.C["user_id"]).OrderBy(Count(views.C["timestamp"]).Desc()),
		`SELECT "views"."user_id", COUNT("views"."timestamp") FROM "views" GROUP BY "views"."user_id" ORDER BY COUNT("views"."timestamp") DESC`,
		0,
	)

	// Add a conditional
	expectedSQL(
		t,
		Select(users.C["name"]).Where(users.C["id"].Equals(1)),
		`SELECT "users"."name" FROM "users" WHERE "users"."id" = $1`,
		1,
	)

	// Test limit
	expectedSQL(
		t,
		Select(users.C["name"]).Limit(1),
		`SELECT "users"."name" FROM "users" LIMIT 1`,
		0,
	)

	// Test Offset
	expectedSQL(
		t,
		Select(users.C["name"]).Offset(1),
		`SELECT "users"."name" FROM "users" OFFSET 1`,
		0,
	)
}
<|endoftext|>


<commit_before>// Package botfaces defines the interfaces a bot can have, visibile to the graw
// engine. These interfaces allow graw to infer what events the bot cares about
// and can handle.
package botfaces

import (
	"github.com/turnage/redditproto"
	"time"
)

// Loader defines methods for bots that use external resources or need to do
// initialization.
type Loader interface {
	// SetUp is the first method ever called on the bot, and it will be
	// allowed to finish before other methods are called. Bots should
	// load resources here. If an error is returned, the engine will not
	// start, and the error will propagate up.
	SetUp() error
}

// Tearer defines methods for bots that need to tear things down after their run
// is finished.
type Tearer interface {
	// TearDown is the last method ever called on the bot, and all other
	// method calls will finish before this method is called. Bots should
	// unload resources here.
	TearDown()
}

// Failer defines methods bots can use to control how the Engine responds to
// failures.
type Failer interface {
	// Fail will be called when the engine encounters an error. The bot can
	// return true to instruct the engine to fail, or false to instruct the
	// engine to try again.
	//
	// This method will be called in the main engine loop; the bot may
	// choose to pause here or do other things to respond to the failure
	// (e.g. pause for three hours to respond to Reddit down time).
	Fail(err error) bool
}

// It is recommended, though not required, to implement all inbox handlers if
// one is implemented. All unread inbox items are fetched in updates (Reddit
// does not offer filtering by type (mentions, post replies, etc)).
//
// Ex. If Mentions are handled, but not Messages, any unread messages will be
// wasting your network data. graw will not mark an unhandled inbox item as
// read.
//
// It shouldn't be a concern if your bot cannot receive the events it does not
// handle. If it does not submit, it cannot receive post replies. If it does not
// comment, it cannot receive comment replies.

// PostHandler defines methods for bots that handle new posts in
// subreddits they monitor.
type PostHandler interface {
	// Post is called when a post is made in a monitored subreddit that the
	// bot has not seen yet. [Called as goroutine.]
	Post(post *redditproto.Link)
}

// MessageHandler defines methods for bots that handle new private messages to
// their inbox.
type MessageHandler interface {
	// Message is called when the bot receives a new private message to its
	// account. [Called as goroutine.]
	Message(msg *redditproto.Message)
}

// PostReplyHandler defines methods for bots that handle new top-level comments
// on their submissions.
type PostReplyHandler interface {
	// Reply is called when the bot receives a reply to one of its
	// submissions in its inbox. [Called as goroutine.]
	PostReply(reply *redditproto.Comment)
}

// CommentReplyHandler defines methods for bots that handle new comments made in
// reply to their own.
type CommentReplyHandler interface {
	// CommentReply is called when the bot receives a reply to one of its
	// comments in it its inbox. [Called as goroutine.]
	CommentReply(reply *redditproto.Comment)
}

// MentionHandler defines methods for bots that handle username mentions. These
// will only appear in the inbox if
//
//  1. The bot's account preferences are set to monitor username mentions.
//  2. The event type is not shadowed.
//
// Reddit will shadow a username mention under two other event types. If the
// bot's username is mentioned in a comment posted on its submission, the inbox
// item will be a post reply, not a mention. If the bot's username is mentioned
// in a comment posted in reply to one of the bot's comments, the inbox item
// will be a comment reply, not a mention. In both cases, this handler is
// unused.
type MentionHandler interface {
	// Mention is called when the bot receives a username mention in its
	// inbox. [Called as goroutine.]
	Mention(mention *redditproto.Comment)
}

// UserHandler defines methods for bots that handle activity by monitored users.
type UserHandler interface {
	// UserPost is called when a monitored user makes a post in a subreddit
	// the bot can view. [Called as goroutine.]
	UserPost(post *redditproto.Link)
	// UserComment is called when the monitored user makes a comment in a
	// subreddit the bot can view. [Called as goroutine.]
	UserComment(comment *redditproto.Comment)
}

// BlockTimer defines methods that allow bots to specify the interval to block
// between monitor updates.
type BlockTimer interface {
	// To comply with the reddit API rules, this should be >= 1*time.Second.
	// Default: 2*time.Second
	BlockTime() time.Duration
}
<commit_msg>Remove outdated comment.<commit_after>// Package botfaces defines the interfaces a bot can have, visibile to the graw
// engine. These interfaces allow graw to infer what events the bot cares about
// and can handle.
package botfaces

import (
	"github.com/turnage/redditproto"
	"time"
)

// Loader defines methods for bots that use external resources or need to do
// initialization.
type Loader interface {
	// SetUp is the first method ever called on the bot, and it will be
	// allowed to finish before other methods are called. Bots should
	// load resources here. If an error is returned, the engine will not
	// start, and the error will propagate up.
	SetUp() error
}

// Tearer defines methods for bots that need to tear things down after their run
// is finished.
type Tearer interface {
	// TearDown is the last method ever called on the bot, and all other
	// method calls will finish before this method is called. Bots should
	// unload resources here.
	TearDown()
}

// Failer defines methods bots can use to control how the Engine responds to
// failures.
type Failer interface {
	// Fail will be called when the engine encounters an error. The bot can
	// return true to instruct the engine to fail, or false to instruct the
	// engine to try again.
	//
	// This method will be called in the main engine loop; the bot may
	// choose to pause here or do other things to respond to the failure
	// (e.g. pause for three hours to respond to Reddit down time).
	Fail(err error) bool
}

// PostHandler defines methods for bots that handle new posts in
// subreddits they monitor.
type PostHandler interface {
	// Post is called when a post is made in a monitored subreddit that the
	// bot has not seen yet. [Called as goroutine.]
	Post(post *redditproto.Link)
}

// MessageHandler defines methods for bots that handle new private messages to
// their inbox.
type MessageHandler interface {
	// Message is called when the bot receives a new private message to its
	// account. [Called as goroutine.]
	Message(msg *redditproto.Message)
}

// PostReplyHandler defines methods for bots that handle new top-level comments
// on their submissions.
type PostReplyHandler interface {
	// Reply is called when the bot receives a reply to one of its
	// submissions in its inbox. [Called as goroutine.]
	PostReply(reply *redditproto.Comment)
}

// CommentReplyHandler defines methods for bots that handle new comments made in
// reply to their own.
type CommentReplyHandler interface {
	// CommentReply is called when the bot receives a reply to one of its
	// comments in it its inbox. [Called as goroutine.]
	CommentReply(reply *redditproto.Comment)
}

// MentionHandler defines methods for bots that handle username mentions. These
// will only appear in the inbox if
//
//  1. The bot's account preferences are set to monitor username mentions.
//  2. The event type is not shadowed.
//
// Reddit will shadow a username mention under two other event types. If the
// bot's username is mentioned in a comment posted on its submission, the inbox
// item will be a post reply, not a mention. If the bot's username is mentioned
// in a comment posted in reply to one of the bot's comments, the inbox item
// will be a comment reply, not a mention. In both cases, this handler is
// unused.
type MentionHandler interface {
	// Mention is called when the bot receives a username mention in its
	// inbox. [Called as goroutine.]
	Mention(mention *redditproto.Comment)
}

// UserHandler defines methods for bots that handle activity by monitored users.
type UserHandler interface {
	// UserPost is called when a monitored user makes a post in a subreddit
	// the bot can view. [Called as goroutine.]
	UserPost(post *redditproto.Link)
	// UserComment is called when the monitored user makes a comment in a
	// subreddit the bot can view. [Called as goroutine.]
	UserComment(comment *redditproto.Comment)
}

// BlockTimer defines methods that allow bots to specify the interval to block
// between monitor updates.
type BlockTimer interface {
	// To comply with the reddit API rules, this should be >= 1*time.Second.
	// Default: 2*time.Second
	BlockTime() time.Duration
}
<|endoftext|>


<commit_before>package tlc

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"path/filepath"
	"strings"

	"github.com/itchio/arkive/zip"

	"github.com/itchio/wharf/eos"
	"github.com/pkg/errors"
)

const (
	// ModeMask is or'd with files being diffed
	ModeMask = 0644

	// NullPath can be specified instead of a directory to yield an empty container
	NullPath = "/dev/null"
)

var (
	ErrUnrecognizedContainer = errors.New("Unrecognized container: should either be a directory, or a .zip archive")
)

// A FilterFunc allows ignoring certain files or directories when walking the filesystem
// When a directory is ignored by a FilterFunc, all its children are, too!
type FilterFunc func(fileInfo os.FileInfo) bool

// DefaultFilter is a passthrough that filters out no files at all
var DefaultFilter FilterFunc = func(fileInfo os.FileInfo) bool {
	return true
}

type WalkOpts struct {
	// Filter decides which files to exclude from the walk
	Filter FilterFunc

	// Dereference walks symlinks as if they were their targets
	Dereference bool
}

// WalkAny tries to retrieve container information on containerPath. It supports:
// the empty container (/dev/null), local directories, zip archives, or single files
func WalkAny(containerPath string, opts *WalkOpts) (*Container, error) {
	// empty container case
	if containerPath == NullPath {
		return &Container{}, nil
	}

	file, err := eos.Open(containerPath)
	if err != nil {
		return nil, errors.WithStack(err)
	}

	defer file.Close()

	stat, err := file.Stat()
	if err != nil {
		return nil, errors.WithStack(err)
	}

	if stat.IsDir() {
		// local directory case
		return WalkDir(containerPath, opts)
	}

	// zip archive case
	if strings.HasSuffix(strings.ToLower(stat.Name()), ".zip") {
		zr, err := zip.NewReader(file, stat.Size())
		if err != nil {
			return nil, errors.WithStack(err)
		}
		return WalkZip(zr, opts)
	}

	// single file case
	return WalkSingle(file)
}

// WalkSingle returns a container with a single file
func WalkSingle(file eos.File) (*Container, error) {
	stats, err := file.Stat()
	if err != nil {
		return nil, err
	}

	if !stats.Mode().IsRegular() {
		return nil, errors.Errorf("%s: not a regular file, can only WalkSingle regular files", stats.Name())
	}

	container := &Container{
		Files: []*File{
			&File{
				Mode:   uint32(stats.Mode()),
				Size:   int64(stats.Size()),
				Offset: 0,
				Path:   filepath.Base(stats.Name()),
			},
		},
		Size: stats.Size(),
	}
	return container, nil
}

// WalkDir retrieves information on all files, directories, and symlinks in a directory
func WalkDir(basePathIn string, opts *WalkOpts) (*Container, error) {
	filter := opts.Filter

	if filter == nil {
		filter = DefaultFilter
	}

	var Dirs []*Dir
	var Symlinks []*Symlink
	var Files []*File

	currentlyWalking := make(map[string]bool)

	TotalOffset := int64(0)

	var makeEntryCallback func(BasePath string, LocationPath string) filepath.WalkFunc

	makeEntryCallback = func(BasePath string, LocationPath string) filepath.WalkFunc {
		return func(FullPath string, fileInfo os.FileInfo, err error) error {
			// we shouldn't encounter any error crawling the repo
			if err != nil {
				if os.IsPermission(err) {
					// ...except permission errors, those are fine
					log.Printf("Permission error: %s\n", err.Error())
				} else {
					return errors.WithStack(err)
				}
			}

			Path, err := filepath.Rel(BasePath, FullPath)
			if err != nil {
				return errors.WithStack(err)
			}

			Path = filepath.Join(LocationPath, Path)

			Path = filepath.ToSlash(Path)
			if Path == "." {
				// Don't store a single folder named "."
				return nil
			}

			// os.Walk does not follow symlinks, so we must do it
			// manually if Dereference is set
			if opts.Dereference && fileInfo.Mode()&os.ModeSymlink > 0 {
				fileInfo, err = os.Stat(FullPath)
				if err != nil {
					return errors.WithStack(err)
				}

				if fileInfo.Mode().IsDir() {
					Dest, err := os.Readlink(FullPath)
					if err != nil {
						return errors.WithStack(err)
					}

					var JoinedDest string
					if filepath.IsAbs(Dest) {
						JoinedDest = Dest
					} else {
						JoinedDest = filepath.Join(filepath.Dir(FullPath), Dest)
					}

					CleanDest := filepath.Clean(JoinedDest)

					if currentlyWalking[CleanDest] {
						err := fmt.Errorf("symlinks recurse onto %s, cowardly refusing to walk infinite container", CleanDest)
						return errors.WithStack(err)
					}

					currentlyWalking[CleanDest] = true
					err = filepath.Walk(CleanDest, makeEntryCallback(CleanDest, Path))
					delete(currentlyWalking, CleanDest)
					if err != nil {
						return errors.WithStack(err)
					}
				}
			}

			// don't end up with files we (the patcher) can't modify
			Mode := fileInfo.Mode() | ModeMask

			if !filter(fileInfo) {
				if Mode.IsDir() {
					return filepath.SkipDir
				}
				return nil
			}

			if Mode.IsDir() {
				Dirs = append(Dirs, &Dir{Path: Path, Mode: uint32(Mode)})
			} else if Mode.IsRegular() {
				Size := fileInfo.Size()
				Offset := TotalOffset
				OffsetEnd := Offset + Size

				Files = append(Files, &File{Path: Path, Mode: uint32(Mode), Size: Size, Offset: Offset})
				TotalOffset = OffsetEnd
			} else if Mode&os.ModeSymlink > 0 {
				Dest, err := os.Readlink(FullPath)
				if err != nil {
					return errors.WithStack(err)
				}

				Dest = filepath.ToSlash(Dest)
				Symlinks = append(Symlinks, &Symlink{Path: Path, Mode: uint32(Mode), Dest: Dest})
			}

			return nil
		}
	}

	if basePathIn == NullPath {
		// empty container is fine - /dev/null is legal even on Win32 where it doesn't exist
	} else {
		basePathIn, err := filepath.Abs(basePathIn)
		if err != nil {
			return nil, errors.WithStack(err)
		}

		fi, err := os.Lstat(basePathIn)
		if err != nil {
			return nil, errors.WithStack(err)
		}

		if !fi.IsDir() {
			return nil, errors.Errorf("can't walk non-directory %s", basePathIn)
		}

		currentlyWalking[basePathIn] = true
		err = filepath.Walk(basePathIn, makeEntryCallback(basePathIn, "."))
		if err != nil {
			return nil, errors.WithStack(err)
		}
	}

	container := &Container{Size: TotalOffset, Dirs: Dirs, Symlinks: Symlinks, Files: Files}
	return container, nil
}

// WalkZip walks all file in a zip archive and returns a container
func WalkZip(zr *zip.Reader, opts *WalkOpts) (*Container, error) {
	filter := opts.Filter

	if filter == nil {
		// default filter is a passthrough
		filter = func(fileInfo os.FileInfo) bool {
			return true
		}
	}

	if opts.Dereference {
		return nil, errors.New("Dereference is not supporting when walking a zip")
	}

	var Dirs []*Dir
	var Symlinks []*Symlink
	var Files []*File

	dirMap := make(map[string]os.FileMode)

	TotalOffset := int64(0)

	for _, file := range zr.File {
		fileName := filepath.ToSlash(filepath.Clean(filepath.ToSlash(file.Name)))

		// don't trust zip files to have directory entries for
		// all directories. it's a miracle anything works.
		dir := path.Dir(fileName)
		if dir != "" && dir != "." && dirMap[dir] == 0 {
			dirMap[dir] = os.FileMode(0755)
		}

		info := file.FileInfo()
		mode := file.Mode() | ModeMask

		if info.IsDir() {
			dirMap[fileName] = mode
		} else if mode&os.ModeSymlink > 0 {
			var linkname []byte

			err := func() error {
				reader, err := file.Open()
				if err != nil {
					return errors.WithStack(err)
				}
				defer reader.Close()

				linkname, err = ioutil.ReadAll(reader)
				if err != nil {
					return errors.WithStack(err)
				}
				return nil
			}()

			if err != nil {
				return nil, errors.WithStack(err)
			}

			Symlinks = append(Symlinks, &Symlink{
				Path: fileName,
				Dest: string(linkname),
				Mode: uint32(mode),
			})
		} else {
			Size := int64(file.UncompressedSize64)

			Files = append(Files, &File{
				Path:   fileName,
				Mode:   uint32(mode),
				Size:   Size,
				Offset: TotalOffset,
			})

			TotalOffset += Size
		}
	}

	for dirPath, dirMode := range dirMap {
		Dirs = append(Dirs, &Dir{
			Path: dirPath,
			Mode: uint32(dirMode),
		})
	}

	container := &Container{
		Size:     TotalOffset,
		Dirs:     Dirs,
		Symlinks: Symlinks,
		Files:    Files,
	}
	return container, nil
}

// Stats return a human-readable summary of the contents of a container
func (container *Container) Stats() string {
	return fmt.Sprintf("%d files, %d dirs, %d symlinks",
		len(container.Files), len(container.Dirs), len(container.Symlinks))
}

// IsSingleFile returns true if the container contains
// exactly one files, and no directories or symlinks.
func (container *Container) IsSingleFile() bool {
	if len(container.Files) == 1 && len(container.Dirs) == 0 && len(container.Symlinks) == 0 {
		return true
	}
	return false
}
<commit_msg>Implement Formatter for container<commit_after>package tlc

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"path/filepath"
	"strings"

	"github.com/itchio/arkive/zip"
	"github.com/itchio/httpkit/progress"

	"github.com/itchio/wharf/eos"
	"github.com/pkg/errors"
)

const (
	// ModeMask is or'd with files being diffed
	ModeMask = 0644

	// NullPath can be specified instead of a directory to yield an empty container
	NullPath = "/dev/null"
)

var (
	ErrUnrecognizedContainer = errors.New("Unrecognized container: should either be a directory, or a .zip archive")
)

// A FilterFunc allows ignoring certain files or directories when walking the filesystem
// When a directory is ignored by a FilterFunc, all its children are, too!
type FilterFunc func(fileInfo os.FileInfo) bool

// DefaultFilter is a passthrough that filters out no files at all
var DefaultFilter FilterFunc = func(fileInfo os.FileInfo) bool {
	return true
}

type WalkOpts struct {
	// Filter decides which files to exclude from the walk
	Filter FilterFunc

	// Dereference walks symlinks as if they were their targets
	Dereference bool
}

// WalkAny tries to retrieve container information on containerPath. It supports:
// the empty container (/dev/null), local directories, zip archives, or single files
func WalkAny(containerPath string, opts *WalkOpts) (*Container, error) {
	// empty container case
	if containerPath == NullPath {
		return &Container{}, nil
	}

	file, err := eos.Open(containerPath)
	if err != nil {
		return nil, errors.WithStack(err)
	}

	defer file.Close()

	stat, err := file.Stat()
	if err != nil {
		return nil, errors.WithStack(err)
	}

	if stat.IsDir() {
		// local directory case
		return WalkDir(containerPath, opts)
	}

	// zip archive case
	if strings.HasSuffix(strings.ToLower(stat.Name()), ".zip") {
		zr, err := zip.NewReader(file, stat.Size())
		if err != nil {
			return nil, errors.WithStack(err)
		}
		return WalkZip(zr, opts)
	}

	// single file case
	return WalkSingle(file)
}

// WalkSingle returns a container with a single file
func WalkSingle(file eos.File) (*Container, error) {
	stats, err := file.Stat()
	if err != nil {
		return nil, err
	}

	if !stats.Mode().IsRegular() {
		return nil, errors.Errorf("%s: not a regular file, can only WalkSingle regular files", stats.Name())
	}

	container := &Container{
		Files: []*File{
			&File{
				Mode:   uint32(stats.Mode()),
				Size:   int64(stats.Size()),
				Offset: 0,
				Path:   filepath.Base(stats.Name()),
			},
		},
		Size: stats.Size(),
	}
	return container, nil
}

// WalkDir retrieves information on all files, directories, and symlinks in a directory
func WalkDir(basePathIn string, opts *WalkOpts) (*Container, error) {
	filter := opts.Filter

	if filter == nil {
		filter = DefaultFilter
	}

	var Dirs []*Dir
	var Symlinks []*Symlink
	var Files []*File

	currentlyWalking := make(map[string]bool)

	TotalOffset := int64(0)

	var makeEntryCallback func(BasePath string, LocationPath string) filepath.WalkFunc

	makeEntryCallback = func(BasePath string, LocationPath string) filepath.WalkFunc {
		return func(FullPath string, fileInfo os.FileInfo, err error) error {
			// we shouldn't encounter any error crawling the repo
			if err != nil {
				if os.IsPermission(err) {
					// ...except permission errors, those are fine
					log.Printf("Permission error: %s\n", err.Error())
				} else {
					return errors.WithStack(err)
				}
			}

			Path, err := filepath.Rel(BasePath, FullPath)
			if err != nil {
				return errors.WithStack(err)
			}

			Path = filepath.Join(LocationPath, Path)

			Path = filepath.ToSlash(Path)
			if Path == "." {
				// Don't store a single folder named "."
				return nil
			}

			// os.Walk does not follow symlinks, so we must do it
			// manually if Dereference is set
			if opts.Dereference && fileInfo.Mode()&os.ModeSymlink > 0 {
				fileInfo, err = os.Stat(FullPath)
				if err != nil {
					return errors.WithStack(err)
				}

				if fileInfo.Mode().IsDir() {
					Dest, err := os.Readlink(FullPath)
					if err != nil {
						return errors.WithStack(err)
					}

					var JoinedDest string
					if filepath.IsAbs(Dest) {
						JoinedDest = Dest
					} else {
						JoinedDest = filepath.Join(filepath.Dir(FullPath), Dest)
					}

					CleanDest := filepath.Clean(JoinedDest)

					if currentlyWalking[CleanDest] {
						err := fmt.Errorf("symlinks recurse onto %s, cowardly refusing to walk infinite container", CleanDest)
						return errors.WithStack(err)
					}

					currentlyWalking[CleanDest] = true
					err = filepath.Walk(CleanDest, makeEntryCallback(CleanDest, Path))
					delete(currentlyWalking, CleanDest)
					if err != nil {
						return errors.WithStack(err)
					}
				}
			}

			// don't end up with files we (the patcher) can't modify
			Mode := fileInfo.Mode() | ModeMask

			if !filter(fileInfo) {
				if Mode.IsDir() {
					return filepath.SkipDir
				}
				return nil
			}

			if Mode.IsDir() {
				Dirs = append(Dirs, &Dir{Path: Path, Mode: uint32(Mode)})
			} else if Mode.IsRegular() {
				Size := fileInfo.Size()
				Offset := TotalOffset
				OffsetEnd := Offset + Size

				Files = append(Files, &File{Path: Path, Mode: uint32(Mode), Size: Size, Offset: Offset})
				TotalOffset = OffsetEnd
			} else if Mode&os.ModeSymlink > 0 {
				Dest, err := os.Readlink(FullPath)
				if err != nil {
					return errors.WithStack(err)
				}

				Dest = filepath.ToSlash(Dest)
				Symlinks = append(Symlinks, &Symlink{Path: Path, Mode: uint32(Mode), Dest: Dest})
			}

			return nil
		}
	}

	if basePathIn == NullPath {
		// empty container is fine - /dev/null is legal even on Win32 where it doesn't exist
	} else {
		basePathIn, err := filepath.Abs(basePathIn)
		if err != nil {
			return nil, errors.WithStack(err)
		}

		fi, err := os.Lstat(basePathIn)
		if err != nil {
			return nil, errors.WithStack(err)
		}

		if !fi.IsDir() {
			return nil, errors.Errorf("can't walk non-directory %s", basePathIn)
		}

		currentlyWalking[basePathIn] = true
		err = filepath.Walk(basePathIn, makeEntryCallback(basePathIn, "."))
		if err != nil {
			return nil, errors.WithStack(err)
		}
	}

	container := &Container{Size: TotalOffset, Dirs: Dirs, Symlinks: Symlinks, Files: Files}
	return container, nil
}

// WalkZip walks all file in a zip archive and returns a container
func WalkZip(zr *zip.Reader, opts *WalkOpts) (*Container, error) {
	filter := opts.Filter

	if filter == nil {
		// default filter is a passthrough
		filter = func(fileInfo os.FileInfo) bool {
			return true
		}
	}

	if opts.Dereference {
		return nil, errors.New("Dereference is not supporting when walking a zip")
	}

	var Dirs []*Dir
	var Symlinks []*Symlink
	var Files []*File

	dirMap := make(map[string]os.FileMode)

	TotalOffset := int64(0)

	for _, file := range zr.File {
		fileName := filepath.ToSlash(filepath.Clean(filepath.ToSlash(file.Name)))

		// don't trust zip files to have directory entries for
		// all directories. it's a miracle anything works.
		dir := path.Dir(fileName)
		if dir != "" && dir != "." && dirMap[dir] == 0 {
			dirMap[dir] = os.FileMode(0755)
		}

		info := file.FileInfo()
		mode := file.Mode() | ModeMask

		if info.IsDir() {
			dirMap[fileName] = mode
		} else if mode&os.ModeSymlink > 0 {
			var linkname []byte

			err := func() error {
				reader, err := file.Open()
				if err != nil {
					return errors.WithStack(err)
				}
				defer reader.Close()

				linkname, err = ioutil.ReadAll(reader)
				if err != nil {
					return errors.WithStack(err)
				}
				return nil
			}()

			if err != nil {
				return nil, errors.WithStack(err)
			}

			Symlinks = append(Symlinks, &Symlink{
				Path: fileName,
				Dest: string(linkname),
				Mode: uint32(mode),
			})
		} else {
			Size := int64(file.UncompressedSize64)

			Files = append(Files, &File{
				Path:   fileName,
				Mode:   uint32(mode),
				Size:   Size,
				Offset: TotalOffset,
			})

			TotalOffset += Size
		}
	}

	for dirPath, dirMode := range dirMap {
		Dirs = append(Dirs, &Dir{
			Path: dirPath,
			Mode: uint32(dirMode),
		})
	}

	container := &Container{
		Size:     TotalOffset,
		Dirs:     Dirs,
		Symlinks: Symlinks,
		Files:    Files,
	}
	return container, nil
}

// Stats return a human-readable summary of the contents of a container
func (container *Container) Stats() string {
	return fmt.Sprintf("%d files, %d dirs, %d symlinks",
		len(container.Files), len(container.Dirs), len(container.Symlinks))
}

var _ fmt.Formatter = (*Container)(nil)

// Stats return a human-readable summary of the contents of a container
func (container *Container) Format(f fmt.State, c rune) {
	fmt.Fprintf(f, "%s (%s)",
		progress.FormatBytes(container.Size),
		container.Stats(),
	)
}

// IsSingleFile returns true if the container contains
// exactly one files, and no directories or symlinks.
func (container *Container) IsSingleFile() bool {
	if len(container.Files) == 1 && len(container.Dirs) == 0 && len(container.Symlinks) == 0 {
		return true
	}
	return false
}
<|endoftext|>


<commit_before>// Copyright 2017 The go-github 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 github

import (
	"context"
	"fmt"
	"net/http"
	"reflect"
	"testing"
	"time"
)

func TestRepositoriesService_GetCommunityHealthMetrics(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/repos/o/r/community/profile", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		testHeader(t, r, "Accept", mediaTypeRepositoryCommunityHealthMetricsPreview)
		fmt.Fprintf(w, `{
				"health_percentage": 100,
				"files": {
					"code_of_conduct": {
						"name": "Contributor Covenant",
						"key": "contributor_covenant",
						"url": null,
						"html_url": "https://github.com/octocat/Hello-World/blob/master/CODE_OF_CONDUCT.md"
					},
					"contributing": {
						"url": "https://api.github.com/repos/octocat/Hello-World/contents/CONTRIBUTING",
						"html_url": "https://github.com/octocat/Hello-World/blob/master/CONTRIBUTING"
					},
					"license": {
						"name": "MIT License",
						"key": "mit",
						"url": "https://api.github.com/licenses/mit",
						"html_url": "https://github.com/octocat/Hello-World/blob/master/LICENSE"
					},
					"readme": {
						"url": "https://api.github.com/repos/octocat/Hello-World/contents/README.md",
						"html_url": "https://github.com/octocat/Hello-World/blob/master/README.md"
					}
				},
				"updated_at": "2017-02-28T00:00:00Z"
			}`)
	})

	ctx := context.Background()
	got, _, err := client.Repositories.GetCommunityHealthMetrics(ctx, "o", "r")
	if err != nil {
		t.Errorf("Repositories.GetCommunityHealthMetrics returned error: %v", err)
	}

	updatedAt := time.Date(2017, time.February, 28, 0, 0, 0, 0, time.UTC)
	want := &CommunityHealthMetrics{
		HealthPercentage: Int(100),
		UpdatedAt:        &updatedAt,
		Files: &CommunityHealthFiles{
			CodeOfConduct: &Metric{
				Name:    String("Contributor Covenant"),
				Key:     String("contributor_covenant"),
				HTMLURL: String("https://github.com/octocat/Hello-World/blob/master/CODE_OF_CONDUCT.md"),
			},
			Contributing: &Metric{
				URL:     String("https://api.github.com/repos/octocat/Hello-World/contents/CONTRIBUTING"),
				HTMLURL: String("https://github.com/octocat/Hello-World/blob/master/CONTRIBUTING"),
			},
			License: &Metric{
				Name:    String("MIT License"),
				Key:     String("mit"),
				URL:     String("https://api.github.com/licenses/mit"),
				HTMLURL: String("https://github.com/octocat/Hello-World/blob/master/LICENSE"),
			},
			Readme: &Metric{
				URL:     String("https://api.github.com/repos/octocat/Hello-World/contents/README.md"),
				HTMLURL: String("https://github.com/octocat/Hello-World/blob/master/README.md"),
			},
		},
	}
	if !reflect.DeepEqual(got, want) {
		t.Errorf("Repositories.GetCommunityHealthMetrics:\ngot:\n%v\nwant:\n%v", Stringify(got), Stringify(want))
	}
}
<commit_msg>Improve repos_community_health.go coverage (#1704)<commit_after>// Copyright 2017 The go-github 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 github

import (
	"context"
	"fmt"
	"net/http"
	"reflect"
	"testing"
	"time"
)

func TestRepositoriesService_GetCommunityHealthMetrics(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/repos/o/r/community/profile", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		testHeader(t, r, "Accept", mediaTypeRepositoryCommunityHealthMetricsPreview)
		fmt.Fprintf(w, `{
				"health_percentage": 100,
				"files": {
					"code_of_conduct": {
						"name": "Contributor Covenant",
						"key": "contributor_covenant",
						"url": null,
						"html_url": "https://github.com/octocat/Hello-World/blob/master/CODE_OF_CONDUCT.md"
					},
					"contributing": {
						"url": "https://api.github.com/repos/octocat/Hello-World/contents/CONTRIBUTING",
						"html_url": "https://github.com/octocat/Hello-World/blob/master/CONTRIBUTING"
					},
					"license": {
						"name": "MIT License",
						"key": "mit",
						"url": "https://api.github.com/licenses/mit",
						"html_url": "https://github.com/octocat/Hello-World/blob/master/LICENSE"
					},
					"readme": {
						"url": "https://api.github.com/repos/octocat/Hello-World/contents/README.md",
						"html_url": "https://github.com/octocat/Hello-World/blob/master/README.md"
					}
				},
				"updated_at": "2017-02-28T00:00:00Z"
			}`)
	})

	ctx := context.Background()
	got, _, err := client.Repositories.GetCommunityHealthMetrics(ctx, "o", "r")
	if err != nil {
		t.Errorf("Repositories.GetCommunityHealthMetrics returned error: %v", err)
	}

	updatedAt := time.Date(2017, time.February, 28, 0, 0, 0, 0, time.UTC)
	want := &CommunityHealthMetrics{
		HealthPercentage: Int(100),
		UpdatedAt:        &updatedAt,
		Files: &CommunityHealthFiles{
			CodeOfConduct: &Metric{
				Name:    String("Contributor Covenant"),
				Key:     String("contributor_covenant"),
				HTMLURL: String("https://github.com/octocat/Hello-World/blob/master/CODE_OF_CONDUCT.md"),
			},
			Contributing: &Metric{
				URL:     String("https://api.github.com/repos/octocat/Hello-World/contents/CONTRIBUTING"),
				HTMLURL: String("https://github.com/octocat/Hello-World/blob/master/CONTRIBUTING"),
			},
			License: &Metric{
				Name:    String("MIT License"),
				Key:     String("mit"),
				URL:     String("https://api.github.com/licenses/mit"),
				HTMLURL: String("https://github.com/octocat/Hello-World/blob/master/LICENSE"),
			},
			Readme: &Metric{
				URL:     String("https://api.github.com/repos/octocat/Hello-World/contents/README.md"),
				HTMLURL: String("https://github.com/octocat/Hello-World/blob/master/README.md"),
			},
		},
	}
	if !reflect.DeepEqual(got, want) {
		t.Errorf("Repositories.GetCommunityHealthMetrics:\ngot:\n%v\nwant:\n%v", Stringify(got), Stringify(want))
	}

	const methodName = "GetCommunityHealthMetrics"
	testBadOptions(t, methodName, func() (err error) {
		_, _, err = client.Repositories.GetCommunityHealthMetrics(ctx, "\n", "\n")
		return err
	})

	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		got, resp, err := client.Repositories.GetCommunityHealthMetrics(ctx, "o", "r")
		if got != nil {
			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
		}
		return resp, err
	})
}
<|endoftext|>


<commit_before>package worker

// Job represents the job to be run
type Job struct {
	Payload interface{}
}

// The task interface to handle the job.
type Task interface {
	Handle(Job)
}

// Worker represents the worker that executes the job
type Worker struct {
	workerPool chan chan Job
	jobChannel chan Job
	quit       chan bool
	handler    interface{}
}

// NewWorker creates a new worker.
//
// The worker registers its job channel into workPool to get the job,
// then handle it by handler, either which implements the interface Task,
// or whose type is func(Job).
func NewWorker(workerPool chan chan Job, handler interface{}) *Worker {
	return &Worker{
		workerPool: workerPool,
		jobChannel: make(chan Job),
		quit:       make(chan bool),
		handler:    handler,
	}
}

// Start method starts the run loop for the worker, listening for a quit channel in
// case we need to stop it
func (w *Worker) Start() {
	go func() {
		for {
			// register the current worker into the worker queue.
			w.workerPool <- w.jobChannel

			select {
			case job := <-w.jobChannel:
				// we have received a work request.
				w.handle(job)
			case <-w.quit:
				// we have received a signal to stop
				return
			}
		}
	}()
}

func (w *Worker) handle(job Job) {
	recovered := true

	defer func() {
		if recovered {
			recover()
		}
	}()

	if h, ok := w.handler.(Task); ok {
		h.Handle(job)
	} else if h, ok := w.handler.(func(Job)); ok {
		h(job)
	} else {
		recovered = false
		panic("The handler type is wrong")
	}
}

// Stop signals the worker to stop listening for work requests.
func (w *Worker) Stop() {
	go func() {
		w.quit <- true
	}()
}
<commit_msg>Add the package comment<commit_after>// A worker pool with the dispatcher.
package worker

// Job represents the job to be run
type Job struct {
	Payload interface{}
}

// The task interface to handle the job.
type Task interface {
	Handle(Job)
}

// Worker represents the worker that executes the job
type Worker struct {
	workerPool chan chan Job
	jobChannel chan Job
	quit       chan bool
	handler    interface{}
}

// NewWorker creates a new worker.
//
// The worker registers its job channel into workPool to get the job,
// then handle it by handler, either which implements the interface Task,
// or whose type is func(Job).
func NewWorker(workerPool chan chan Job, handler interface{}) *Worker {
	return &Worker{
		workerPool: workerPool,
		jobChannel: make(chan Job),
		quit:       make(chan bool),
		handler:    handler,
	}
}

// Start method starts the run loop for the worker, listening for a quit channel in
// case we need to stop it
func (w *Worker) Start() {
	go func() {
		for {
			// register the current worker into the worker queue.
			w.workerPool <- w.jobChannel

			select {
			case job := <-w.jobChannel:
				// we have received a work request.
				w.handle(job)
			case <-w.quit:
				// we have received a signal to stop
				return
			}
		}
	}()
}

func (w *Worker) handle(job Job) {
	recovered := true

	defer func() {
		if recovered {
			recover()
		}
	}()

	if h, ok := w.handler.(Task); ok {
		h.Handle(job)
	} else if h, ok := w.handler.(func(Job)); ok {
		h(job)
	} else {
		recovered = false
		panic("The handler type is wrong")
	}
}

// Stop signals the worker to stop listening for work requests.
func (w *Worker) Stop() {
	go func() {
		w.quit <- true
	}()
}
<|endoftext|>


<commit_before>package server

import (
	"errors"
	"net/http"

	"github.com/labstack/echo"
	"github.com/labstack/echo-contrib/session"
	log "github.com/sirupsen/logrus"
	"github.com/spf13/viper"
	"github.com/ubccr/goipa"
)

func (h *Handler) tryAuth(uid, password string) (string, error) {
	if len(password) == 0 {
		return "", errors.New("Please provide a password")
	}

	client := ipa.NewDefaultClient()

	err := client.Login(uid, password)
	if err != nil {
		log.WithFields(log.Fields{
			"uid":              uid,
			"ipa_client_error": err,
		}).Error("Failed login attempt")
		return "", errors.New("Invalid login")
	}

	// Ping to get sessionID for later use
	_, err = client.Ping()
	if err != nil {
		return "", errors.New("Error contacting FreeIPA")
	}

	return client.SessionID(), nil
}

func (h *Handler) LoginPost(c echo.Context) error {
	message := ""
	sess, _ := session.Get(CookieKeySession, c)

	uid := c.FormValue("uid")
	password := c.FormValue("password")

	sid, err := h.tryAuth(uid, password)
	if err == nil {
		sess.Values[CookieKeyUser] = uid
		sess.Values[CookieKeySID] = sid
		sess.Values[CookieKeyAuthenticated] = true

		location := Path("/")
		wyaf := sess.Values[CookieKeyWYAF]
		if _, ok := wyaf.(string); ok {
			location = wyaf.(string)
		}
		delete(sess.Values, CookieKeyWYAF)

		sess.Save(c.Request(), c.Response())

		return c.Redirect(http.StatusFound, location)
	} else {
		message = err.Error()
	}

	vars := map[string]interface{}{
		"csrf":    c.Get("csrf").(string),
		"globus":  viper.GetBool("globus_signup"),
		"message": message}

	return c.Render(http.StatusOK, "login.html", vars)
}

func (h *Handler) LoginGet(c echo.Context) error {
	vars := map[string]interface{}{
		"csrf":   c.Get("csrf").(string),
		"globus": viper.GetBool("globus_signup"),
	}

	return c.Render(http.StatusOK, "login.html", vars)
}

func (h *Handler) Logout(c echo.Context) error {
	logout(c)
	return c.Redirect(http.StatusFound, Path("/auth/login"))
}

func logout(c echo.Context) {
	sess, _ := session.Get(CookieKeySession, c)
	delete(sess.Values, CookieKeySID)
	delete(sess.Values, CookieKeyUser)
	delete(sess.Values, CookieKeyAuthenticated)
	delete(sess.Values, CookieKeyWYAF)
	delete(sess.Values, CookieKeyGlobus)
	delete(sess.Values, CookieKeyGlobusUsername)
	sess.Options.MaxAge = -1

	sess.Save(c.Request(), c.Response())
}
<commit_msg>gokrb5 doesn't support OTP kerberos logins. Use RemoteLogin for now.<commit_after>package server

import (
	"errors"
	"net/http"

	"github.com/labstack/echo"
	"github.com/labstack/echo-contrib/session"
	log "github.com/sirupsen/logrus"
	"github.com/spf13/viper"
	"github.com/ubccr/goipa"
)

func (h *Handler) tryAuth(uid, password string) (string, error) {
	if len(password) == 0 {
		return "", errors.New("Please provide a password")
	}

	client := ipa.NewDefaultClient()

	err := client.RemoteLogin(uid, password)
	if err != nil {
		log.WithFields(log.Fields{
			"uid":              uid,
			"ipa_client_error": err,
		}).Error("Failed login attempt")
		return "", errors.New("Invalid login")
	}

	// Ping to get sessionID for later use
	_, err = client.Ping()
	if err != nil {
		return "", errors.New("Error contacting FreeIPA")
	}

	return client.SessionID(), nil
}

func (h *Handler) LoginPost(c echo.Context) error {
	message := ""
	sess, _ := session.Get(CookieKeySession, c)

	uid := c.FormValue("uid")
	password := c.FormValue("password")

	sid, err := h.tryAuth(uid, password)
	if err == nil {
		sess.Values[CookieKeyUser] = uid
		sess.Values[CookieKeySID] = sid
		sess.Values[CookieKeyAuthenticated] = true

		location := Path("/")
		wyaf := sess.Values[CookieKeyWYAF]
		if _, ok := wyaf.(string); ok {
			location = wyaf.(string)
		}
		delete(sess.Values, CookieKeyWYAF)

		sess.Save(c.Request(), c.Response())

		return c.Redirect(http.StatusFound, location)
	} else {
		message = err.Error()
	}

	vars := map[string]interface{}{
		"csrf":    c.Get("csrf").(string),
		"globus":  viper.GetBool("globus_signup"),
		"message": message}

	return c.Render(http.StatusOK, "login.html", vars)
}

func (h *Handler) LoginGet(c echo.Context) error {
	vars := map[string]interface{}{
		"csrf":   c.Get("csrf").(string),
		"globus": viper.GetBool("globus_signup"),
	}

	return c.Render(http.StatusOK, "login.html", vars)
}

func (h *Handler) Logout(c echo.Context) error {
	logout(c)
	return c.Redirect(http.StatusFound, Path("/auth/login"))
}

func logout(c echo.Context) {
	sess, _ := session.Get(CookieKeySession, c)
	delete(sess.Values, CookieKeySID)
	delete(sess.Values, CookieKeyUser)
	delete(sess.Values, CookieKeyAuthenticated)
	delete(sess.Values, CookieKeyWYAF)
	delete(sess.Values, CookieKeyGlobus)
	delete(sess.Values, CookieKeyGlobusUsername)
	sess.Options.MaxAge = -1

	sess.Save(c.Request(), c.Response())
}
<|endoftext|>


<commit_before>package models

type PinRequest struct {
	MessageId int64  `json:"messageId,string"`
	GroupName string `json:"groupName"`
	AccountId int64  `json:"accountId,string"`
}

func NewPinRequest() *PinRequest {
	return &PinRequest{
		GroupName: Channel_KODING_NAME,
	}
}
<commit_msg>Social: create a new struct for pinned channel events<commit_after>package models

type PinRequest struct {
	MessageId int64  `json:"messageId,string"`
	GroupName string `json:"groupName"`
	AccountId int64  `json:"accountId,string"`
}

func NewPinRequest() *PinRequest {
	return &PinRequest{
		GroupName: Channel_KODING_NAME,
	}
}

type PinnedChannelListUpdatedEvent struct {
	Channel Channel        `json:"channel"`
	Message ChannelMessage `json:"message"`
	Reply   ChannelMessage `json:"reply"`
}
<|endoftext|>


<commit_before>// Copyright 2015 The Vanadium 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 util

import (
	"fmt"

	"v.io/v23/vdl"
	"v.io/v23/vom"
)

type structSplitTarget struct {
	tt *vdl.Type
	fields []*vom.RawBytes
	vdl.Target
}

func (targ *structSplitTarget) StartFields(tt *vdl.Type) (vdl.FieldsTarget, error) {
	targ.tt = tt
	targ.fields = make([]*vom.RawBytes, tt.NumField())
	return &structSplitFieldsTarget{targ}, nil
}

func (targ *structSplitTarget) FinishFields(x vdl.FieldsTarget) error {
	return nil
}

func (targ *structSplitTarget) Fields() []*vom.RawBytes {
	return targ.fields
}

type structSplitFieldsTarget struct {
	targ *structSplitTarget
}

func (ft *structSplitFieldsTarget) StartField(name string) (key, field vdl.Target, _ error) {
	_, index := ft.targ.tt.FieldByName(name)
	ft.targ.fields[index] = &vom.RawBytes{}
	return nil, vom.RawBytesTarget(ft.targ.fields[index]), nil
}

func (ft *structSplitFieldsTarget) FinishField(key, field vdl.Target) error {
	return nil
}

func StructSplitTarget() *structSplitTarget {
	return &structSplitTarget{}
}

func JoinRawBytesAsStruct(targ vdl.Target, structType *vdl.Type, fields []*vom.RawBytes) error {
	st, err := targ.StartFields(structType)
	if err != nil {
		return err
	}
	if structType.NumField() != len(fields) {
		return fmt.Errorf("received %d fields, but %v has %d fields", len(fields), structType, structType.NumField())
	}
	for i := 0; i < structType.NumField(); i++ {
		f := structType.Field(i)
		k, t, err := st.StartField(f.Name)
		if err != nil {
			return err
		}
		if err := fields[i].ToTarget(t); err != nil {
			return err
		}
		if err := st.FinishField(k, t); err != nil {
			return err
		}
	}
	return targ.FinishFields(st)
}<commit_msg>mojo.v23proxy: Replace RawBytesTarget hacks with vdl.Targeter<commit_after>// Copyright 2015 The Vanadium 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 util

import (
	"fmt"

	"v.io/v23/vdl"
	"v.io/v23/vom"
)

type structSplitTarget struct {
	tt     *vdl.Type
	fields []*vom.RawBytes
	vdl.Target
}

func (targ *structSplitTarget) StartFields(tt *vdl.Type) (vdl.FieldsTarget, error) {
	targ.tt = tt
	targ.fields = make([]*vom.RawBytes, tt.NumField())
	return &structSplitFieldsTarget{targ}, nil
}

func (targ *structSplitTarget) FinishFields(x vdl.FieldsTarget) error {
	return nil
}

func (targ *structSplitTarget) Fields() []*vom.RawBytes {
	return targ.fields
}

type structSplitFieldsTarget struct {
	targ *structSplitTarget
}

func (ft *structSplitFieldsTarget) StartField(name string) (key, field vdl.Target, _ error) {
	_, index := ft.targ.tt.FieldByName(name)
	rb := new(vom.RawBytes)
	ft.targ.fields[index] = rb
	return nil, rb.MakeVDLTarget(), nil
}

func (ft *structSplitFieldsTarget) FinishField(key, field vdl.Target) error {
	return nil
}

func StructSplitTarget() *structSplitTarget {
	return &structSplitTarget{}
}

func JoinRawBytesAsStruct(targ vdl.Target, structType *vdl.Type, fields []*vom.RawBytes) error {
	st, err := targ.StartFields(structType)
	if err != nil {
		return err
	}
	if structType.NumField() != len(fields) {
		return fmt.Errorf("received %d fields, but %v has %d fields", len(fields), structType, structType.NumField())
	}
	for i := 0; i < structType.NumField(); i++ {
		f := structType.Field(i)
		k, t, err := st.StartField(f.Name)
		if err != nil {
			return err
		}
		if err := fields[i].FillVDLTarget(t); err != nil {
			return err
		}
		if err := st.FinishField(k, t); err != nil {
			return err
		}
	}
	return targ.FinishFields(st)
}
<|endoftext|>