<commit_before>package models

import (
	"time"

	"gopkg.in/mgo.v2/bson"
)

// StackTemplateConfig represents jStackTemplate.config field.
type StackTemplateConfig struct {
	RequiredData      map[string][]string `bson:"requiredData"`
	RequiredProviders []string            `bson:"requiredProviders"`
	Verified          bool                `bson:"verified"`
}

// StackTemplate is a document from jStackTemplates collection
type StackTemplate struct {
	Id          bson.ObjectId `bson:"_id" json:"-"`
	AccessLevel string        `bson:"accessLevel"`

	Template struct {
		Content    string `bson:"content"`
		RawContent string `bson:"rawContent"`
		Sum        string `bson:"sum"`
		Details    bson.M `bson:"details"`
	} `bson:"template"`

	Config      *StackTemplateConfig `bson:"config"`
	Credentials map[string][]string  `bson:"credentials"`
	Description string               `bson:"description"`
	Group       string               `bson:"group"`
	Machines    []bson.M             `bson:"machines"`
	Meta        bson.M               `bson:"meta"`
	OriginID    bson.ObjectId        `bson:"originId"`
	Title       string               `bson:"title"`
}

func NewStackTemplate(provider, identifier string) *StackTemplate {
	now := time.Now()

	return &StackTemplate{
		Id:          bson.NewObjectId(),
		AccessLevel: "group",
		Config: &StackTemplateConfig{
			RequiredData: map[string][]string{
				"user":  {"username"},
				"group": {"slug"},
			},
			RequiredProviders: []string{
				"koding",
				provider,
			},
			Verified: true,
		},
		Credentials: map[string][]string{
			provider: {identifier},
		},
		Description: "##### Readme text for this stack template\n\nYou can write" +
			" down a readme text for new users.\nThis text will be shown when they " +
			"want to use this stack.\nYou can use markdown with the readme content.\n\n",
		Meta: bson.M{
			"createdAt":  now,
			"modifiedAt": now,
			"tags":       nil,
			"views":      nil,
			"votes":      nil,
			"likes":      0,
		},
	}

}
<commit_msg>db/mongo: use private as default access level<commit_after>package models

import (
	"time"

	"gopkg.in/mgo.v2/bson"
)

// StackTemplateConfig represents jStackTemplate.config field.
type StackTemplateConfig struct {
	RequiredData      map[string][]string `bson:"requiredData"`
	RequiredProviders []string            `bson:"requiredProviders"`
	Verified          bool                `bson:"verified"`
}

// StackTemplate is a document from jStackTemplates collection
type StackTemplate struct {
	Id          bson.ObjectId `bson:"_id" json:"-"`
	AccessLevel string        `bson:"accessLevel"`

	Template struct {
		Content    string `bson:"content"`
		RawContent string `bson:"rawContent"`
		Sum        string `bson:"sum"`
		Details    bson.M `bson:"details"`
	} `bson:"template"`

	Config      *StackTemplateConfig `bson:"config"`
	Credentials map[string][]string  `bson:"credentials"`
	Description string               `bson:"description"`
	Group       string               `bson:"group"`
	Machines    []bson.M             `bson:"machines"`
	Meta        bson.M               `bson:"meta"`
	OriginID    bson.ObjectId        `bson:"originId"`
	Title       string               `bson:"title"`
}

func NewStackTemplate(provider, identifier string) *StackTemplate {
	now := time.Now()

	return &StackTemplate{
		Id:          bson.NewObjectId(),
		AccessLevel: "private",
		Config: &StackTemplateConfig{
			RequiredData: map[string][]string{
				"user":  {"username"},
				"group": {"slug"},
			},
			RequiredProviders: []string{
				"koding",
				provider,
			},
			Verified: true,
		},
		Credentials: map[string][]string{
			provider: {identifier},
		},
		Description: "##### Readme text for this stack template\n\nYou can write" +
			" down a readme text for new users.\nThis text will be shown when they " +
			"want to use this stack.\nYou can use markdown with the readme content.\n\n",
		Meta: bson.M{
			"createdAt":  now,
			"modifiedAt": now,
			"tags":       nil,
			"views":      nil,
			"votes":      nil,
			"likes":      0,
		},
	}

}
<|endoftext|>


<commit_before>package al

import (
	"math/rand"
	"testing"
	"time"

	. "github.com/sdboyer/gocheck"
	. "github.com/sdboyer/gogl"
)

// TODO reimplement with specs
//func SetUpBenchmarksFromBuilder(b GraphBuilder) bool {
//Suite(&GraphBenchSuite{b: b})

//return true
//}

//var _ = SetUpBenchmarksFromBuilder(BMBD)

type GraphBenchSuite struct {
	//b       GraphBuilder
	g10     Graph
	g100    Graph
	g1000   Graph
	g10000  Graph
	g100000 Graph
}

// An edge type specifically for benchmarking that encompasses all edge types.
type benchEdge struct {
	U Vertex
	V Vertex
	W float64
	L string
	P interface{}
}

func (e benchEdge) Source() Vertex {
	return e.U
}

func (e benchEdge) Target() Vertex {
	return e.V
}

func (e benchEdge) Both() (Vertex, Vertex) {
	return e.U, e.V
}

func (e benchEdge) Weight() float64 {
	return e.W
}

func (e benchEdge) Label() string {
	return e.L
}

func (e benchEdge) Data() interface{} {
	return e.P
}

func bernoulliDistributionGenerator(vertexCount uint, edgeProbability int, src rand.Source) GraphSource {
	if edgeProbability > 100 || edgeProbability < 1 {
		panic("Must designate an edge probability between 1 and 100")
	}

	if src == nil {
		src = rand.NewSource(time.Now().UnixNano())
	}

	r := rand.New(src)

	list := make([][]benchEdge, vertexCount, vertexCount)

	size := 0
	vc := int(vertexCount)
	for u := 0; u < vc; u++ {
		list[u] = make([]benchEdge, vertexCount, vertexCount)
		for v := 0; v < vc; v++ {
			// without this conditional, this loop would create a complete graph
			if v != u && // no loops
				r.Intn(100) <= edgeProbability { // create edge iff probability says so
				list[u][v] = benchEdge{U: u, V: v}
				size++
			}
		}
	}

	return &benchGraph{targetOrder: vertexCount, directed: true, list: list, size: size}
}

// A type of graph intended to serve as a controlled source of graph data for benchmarking.
type benchGraph struct {
	targetOrder   uint
	targetDensity float64
	maxDegree     uint
	minDegree     uint
	directed      bool
	list          [][]benchEdge
	size          int
}

func (g *benchGraph) EachVertex(f VertexStep) {
	for v, _ := range g.list {
		if f(v) {
			return
		}
	}
}

func (g *benchGraph) EachEdge(f EdgeStep) {
	for _, adj := range g.list {
		for _, e := range adj {
			if f(e) {
				return
			}
		}
	}
}

func (g *benchGraph) Size() int {
	return g.size
}

func (g *benchGraph) Order() int {
	return len(g.list)
}

// back to reality

func (s *GraphBenchSuite) SetUpSuite(c *C) {
	//src := rand.NewSource(time.Now().UnixNano())
	//s.g10 = s.b.Using(bernoulliDistributionGenerator(10, 50, src)).Graph()
	//s.g100 = s.b.Using(bernoulliDistributionGenerator(100, 50, src)).Graph()
	//s.g1000 = s.b.Using(bernoulliDistributionGenerator(1000, 50, src)).Graph()
	//s.g10000 = s.b.Using(bernoulliDistributionGenerator(10000, 50, src)).Graph()
	//	s.g100000 = s.b.Using(bernoulliDistributionGenerator(100000, 50, src)).Graph()
}

func (s *GraphBenchSuite) BenchmarkHasVertex10(c *C) {
	benchHasVertex(s.g10, c)
}

func (s *GraphBenchSuite) BenchmarkHasVertex100(c *C) {
	benchHasVertex(s.g100, c)
}

func (s *GraphBenchSuite) BenchmarkHasVertex1000(c *C) {
	benchHasVertex(s.g1000, c)
}

//func (s *GraphBenchSuite) BenchmarkHasVertex10000(c *C) {
//benchHasVertex(s.g10000, c)
//}

//func (s *GraphBenchSuite) BenchmarkHasVertex100000(c *C) {
//benchHasVertex(s.g100000, c)
//}

func benchHasVertex(g Graph, c *C) {
	for i := 0; i < c.N; i++ {
		g.HasVertex(50)
	}
}

var bgraph = Spec().Directed().Using(bernoulliDistributionGenerator(1000, 50, nil)).Create(G)

func BenchmarkHasVertex(b *testing.B) {
	for i := 0; i < b.N; i++ {
		bgraph.HasVertex(50)
	}
}

func BenchmarkEachVertex(b *testing.B) {
	for i := 0; i < b.N; i++ {
		bgraph.EachVertex(func(v Vertex) (terminate bool) {
			return
		})
	}
}

func BenchmarkEachEdge(b *testing.B) {
	for i := 0; i < b.N; i++ {
		bgraph.EachEdge(func(e Edge) (terminate bool) {
			return
		})
	}
}
<commit_msg>Shut the stupid defunct bench test up temporarily<commit_after>package al

import (
	"math/rand"
	"testing"
	"time"

	. "github.com/sdboyer/gocheck"
	. "github.com/sdboyer/gogl"
)

// TODO reimplement with specs
//func SetUpBenchmarksFromBuilder(b GraphBuilder) bool {
//Suite(&GraphBenchSuite{b: b})

//return true
//}

//var _ = SetUpBenchmarksFromBuilder(BMBD)

type GraphBenchSuite struct {
	//b       GraphBuilder
	g10     Graph
	g100    Graph
	g1000   Graph
	g10000  Graph
	g100000 Graph
}

// An edge type specifically for benchmarking that encompasses all edge types.
type benchEdge struct {
	U Vertex
	V Vertex
	W float64
	L string
	P interface{}
}

func (e benchEdge) Source() Vertex {
	return e.U
}

func (e benchEdge) Target() Vertex {
	return e.V
}

func (e benchEdge) Both() (Vertex, Vertex) {
	return e.U, e.V
}

func (e benchEdge) Weight() float64 {
	return e.W
}

func (e benchEdge) Label() string {
	return e.L
}

func (e benchEdge) Data() interface{} {
	return e.P
}

func bernoulliDistributionGenerator(vertexCount uint, edgeProbability int, src rand.Source) GraphSource {
	if edgeProbability > 100 || edgeProbability < 1 {
		panic("Must designate an edge probability between 1 and 100")
	}

	if src == nil {
		src = rand.NewSource(time.Now().UnixNano())
	}

	r := rand.New(src)

	list := make([][]benchEdge, vertexCount, vertexCount)

	size := 0
	vc := int(vertexCount)
	for u := 0; u < vc; u++ {
		list[u] = make([]benchEdge, vertexCount, vertexCount)
		for v := 0; v < vc; v++ {
			// without this conditional, this loop would create a complete graph
			if v != u && // no loops
				r.Intn(100) <= edgeProbability { // create edge iff probability says so
				list[u][v] = benchEdge{U: u, V: v}
				size++
			}
		}
	}

	return &benchGraph{targetOrder: vertexCount, directed: true, list: list, size: size}
}

// A type of graph intended to serve as a controlled source of graph data for benchmarking.
type benchGraph struct {
	targetOrder   uint
	targetDensity float64
	maxDegree     uint
	minDegree     uint
	directed      bool
	list          [][]benchEdge
	size          int
}

func (g *benchGraph) EachVertex(f VertexStep) {
	for v, _ := range g.list {
		if f(v) {
			return
		}
	}
}

func (g *benchGraph) EachEdge(f EdgeStep) {
	for _, adj := range g.list {
		for _, e := range adj {
			if f(e) {
				return
			}
		}
	}
}

func (g *benchGraph) Size() int {
	return g.size
}

func (g *benchGraph) Order() int {
	return len(g.list)
}

// back to reality

func (s *GraphBenchSuite) SetUpSuite(c *C) {
	//src := rand.NewSource(time.Now().UnixNano())
	//s.g10 = s.b.Using(bernoulliDistributionGenerator(10, 50, src)).Graph()
	//s.g100 = s.b.Using(bernoulliDistributionGenerator(100, 50, src)).Graph()
	//s.g1000 = s.b.Using(bernoulliDistributionGenerator(1000, 50, src)).Graph()
	//s.g10000 = s.b.Using(bernoulliDistributionGenerator(10000, 50, src)).Graph()
	//	s.g100000 = s.b.Using(bernoulliDistributionGenerator(100000, 50, src)).Graph()
}

func (s *GraphBenchSuite) BenchmarkHasVertex10(c *C) {
	benchHasVertex(s.g10, c)
}

func (s *GraphBenchSuite) BenchmarkHasVertex100(c *C) {
	benchHasVertex(s.g100, c)
}

func (s *GraphBenchSuite) BenchmarkHasVertex1000(c *C) {
	benchHasVertex(s.g1000, c)
}

//func (s *GraphBenchSuite) BenchmarkHasVertex10000(c *C) {
//benchHasVertex(s.g10000, c)
//}

//func (s *GraphBenchSuite) BenchmarkHasVertex100000(c *C) {
//benchHasVertex(s.g100000, c)
//}

func benchHasVertex(g Graph, c *C) {
	for i := 0; i < c.N; i++ {
		g.HasVertex(50)
	}
}

var bgraph = Spec().Using(bernoulliDistributionGenerator(1000, 50, nil)).Create(G)

func BenchmarkHasVertex(b *testing.B) {
	for i := 0; i < b.N; i++ {
		bgraph.HasVertex(50)
	}
}

func BenchmarkEachVertex(b *testing.B) {
	for i := 0; i < b.N; i++ {
		bgraph.EachVertex(func(v Vertex) (terminate bool) {
			return
		})
	}
}

func BenchmarkEachEdge(b *testing.B) {
	for i := 0; i < b.N; i++ {
		bgraph.EachEdge(func(e Edge) (terminate bool) {
			return
		})
	}
}
<|endoftext|>


<commit_before>package main

import "testing"

func TestCount(t *testing.T) {
	cases := []struct {
		in       string
		expected int
	}{
		{"(", 1},
		{"()", 0},
		{"(((", 3},
		{"(()(()(", 3},
		{"))(((((", 3},
		{"())", -1},
		{"))(", -1},
		{")))", -3},
		{")())())", -3},
	}
	for _, c := range cases {
		result := Count(c.in)
		if result != c.expected {
			t.Errorf("Count(%q) == %d, expected %d", c.in, result, c.expected)
		}
	}
}

func TestEntryPoint(t *testing.T) {
	cases := []struct {
		input    string
		expected int
	}{
		{"", 0},
		{")", 1},
		{"()())", 5},
	}
	for _, c := range cases {
		basement := -1
		result := FindEntryPoint(c.input, basement)
		if result != c.expected {
			t.Errorf("Floor(%d) reached at character %d, not %d", basement, result, c.expected)
		}
	}
}
<commit_msg>handling both return values from FindEntryPoint<commit_after>package main

import "testing"

func TestCount(t *testing.T) {
	cases := []struct {
		in       string
		expected int
	}{
		{"(", 1},
		{"()", 0},
		{"(((", 3},
		{"(()(()(", 3},
		{"))(((((", 3},
		{"())", -1},
		{"))(", -1},
		{")))", -3},
		{")())())", -3},
	}
	for _, c := range cases {
		result := Count(c.in)
		if result != c.expected {
			t.Errorf("Count(%q) == %d, expected %d", c.in, result, c.expected)
		}
	}
}

func TestEntryPoint(t *testing.T) {
	cases := []struct {
		input    string
		expected int
	}{
		{"", 0},
		{")", 1},
		{"()())", 5},
	}
	for _, c := range cases {
		basement := -1
		result, _ := FindEntryPoint(c.input, basement)
		if result != c.expected {
			t.Errorf("Floor(%d) reached at character %d, not %d", basement, result, c.expected)
		}
	}
}
<|endoftext|>


<commit_before>package db

import (
  . "seeme/models"

	"errors"
)

func GetConnectionsMap(user string) (map[string]bool, error) {
  return GetQueryResultsMap("SELECT connection FROM connections WHERE username = ?", user)
}

func GetNetworkList(user string) ([]User, error) {
  return []User{}, nil
}

func InsertNewConnection(username string, connection string) (error) {
	db := GetDatabaseInstance()
	_, err := db.Exec("INSERT INTO connections VALUES (?, ?, 'pending')", username, connection)
	return err
}

func UpdateConnectionStatus(username string, connection string) (error) {
	db := GetDatabaseInstance()
	_, err := db.Exec("UPDATE connections SET status = 'connected' WHERE username = ? AND connection = ?",
												connection, username)
	return err
}

func DeleteConnection(username string, connection string) (int64, error) {
  primaryUser, connectUser, err := getUserRelationship(username, connection)
  if err != nil {
    return 0, errors.New("Connection Search Error!")
  }
  return PostDeleteQuery("DELETE FROM connections WHERE username = ? AND connection = ?",
                              primaryUser, connectUser)
}

func getUserRelationship(username string, connection string) (string, string, error) {
  userMap, err := GetConnectionsMap(connection)
  if err != nil {
    return username, connection, err
  }
  if userMap[username] {
    primaryUser := connection
    connectUser := username
    return primaryUser, connectUser, nil
  }

  return username, connection, nil
}
<commit_msg>added code in GetNetworkList to return allusers from GetQueryUserList<commit_after>package db

import (
  . "seeme/models"

	"errors"
)

func GetConnectionsMap(user string) (map[string]bool, error) {
  return GetQueryResultsMap("SELECT connection FROM connections WHERE username = ?", user)
}

func GetNetworkList(user string) ([]User, error) {
  return GetQueryUserList("SELECT * FROM users WHERE discoverable = 1 AND !(network_id = 'NULL')")
}

func InsertNewConnection(username string, connection string) (error) {
	db := GetDatabaseInstance()
	_, err := db.Exec("INSERT INTO connections VALUES (?, ?, 'pending')", username, connection)
	return err
}

func UpdateConnectionStatus(username string, connection string) (error) {
	db := GetDatabaseInstance()
	_, err := db.Exec("UPDATE connections SET status = 'connected' WHERE username = ? AND connection = ?",
												connection, username)
	return err
}

func DeleteConnection(username string, connection string) (int64, error) {
  primaryUser, connectUser, err := getUserRelationship(username, connection)
  if err != nil {
    return 0, errors.New("Connection Search Error!")
  }
  return PostDeleteQuery("DELETE FROM connections WHERE username = ? AND connection = ?",
                              primaryUser, connectUser)
}

func getUserRelationship(username string, connection string) (string, string, error) {
  userMap, err := GetConnectionsMap(connection)
  if err != nil {
    return username, connection, err
  }
  if userMap[username] {
    primaryUser := connection
    connectUser := username
    return primaryUser, connectUser, nil
  }

  return username, connection, nil
}
<|endoftext|>


<commit_before>package flake

import (
	"encoding/binary"
	"math/big"
)

// overtflakeID is a wrapper around the bytes generated for an overt-flake identifer
// 	- it implementst the OvertFlakeID interface
type overtFlakeID struct {
	idBytes []byte
}

// NewOvertFlakeID creates an instance of overtFlakeID which implements OvertFlakeID
func NewOvertFlakeID(id []byte) OvertFlakeID {
	return &overtFlakeID{
		idBytes: id,
	}
}

// Timestamp is when the ID was generated, and is the # of milliseconds since
// the generator Epoch
func (id *overtFlakeID) Timestamp() uint64 {
	return id.Upper() >> 16
}

// Interval represents the Nth value created during a time interval
// (0 if the 1st interval generated)
func (id *overtFlakeID) Interval() uint16 {
	return uint16(id.Upper() & 0xFFFF)
}

// HardwareID is the HardwareID assigned by the generator
func (id *overtFlakeID) HardwareID() HardwareID {
	return id.idBytes[8:14]
}

// ProcessID is the processID assigned by the generator
func (id *overtFlakeID) ProcessID() uint16 {
	return uint16(id.Lower() & 0xFFFF)
}

// MachineID is the uint64 representation of HardwareID and ProcessID and is == Lower()
func (id *overtFlakeID) MachineID() uint64 {
	return id.Lower()
}

// Upper is the upper (most-signficant) bytes of the id represented as a uint64
func (id *overtFlakeID) Upper() uint64 {
	return binary.BigEndian.Uint64(id.idBytes[0:8])
}

// Lower is the lower (least-signficant) bytes of the id represented as a uint64
func (id *overtFlakeID) Lower() uint64 {
	return binary.BigEndian.Uint64(id.idBytes[8:16])
}

// Bytes is the []byte representation of the ID
func (id *overtFlakeID) Bytes() []byte {
	return id.idBytes
}

// ToBigInt converts the ID to a *big.Int
func (id *overtFlakeID) ToBigInt() *big.Int {
	i := big.NewInt(0)
	i.SetBytes(id.idBytes)
	return i
}

// String returns the big.Int string representation of the ID
func (id *overtFlakeID) String() string {
	return id.ToBigInt().String()
}
<commit_msg>Interval => SequenceID<commit_after>package flake

import (
	"encoding/binary"
	"math/big"
)

// overtflakeID is a wrapper around the bytes generated for an overt-flake identifer
// 	- it implementst the OvertFlakeID interface
type overtFlakeID struct {
	idBytes []byte
}

// NewOvertFlakeID creates an instance of overtFlakeID which implements OvertFlakeID
func NewOvertFlakeID(id []byte) OvertFlakeID {
	return &overtFlakeID{
		idBytes: id,
	}
}

// Timestamp is when the ID was generated, and is the # of milliseconds since
// the generator Epoch
func (id *overtFlakeID) Timestamp() uint64 {
	return id.Upper() >> 16
}

// SequenceID represents the Nth value created during a time interval
// (0 if the 1st interval generated)
func (id *overtFlakeID) SequenceID() uint16 {
	return uint16(id.Upper() & 0xFFFF)
}

// HardwareID is the HardwareID assigned by the generator
func (id *overtFlakeID) HardwareID() HardwareID {
	return id.idBytes[8:14]
}

// ProcessID is the processID assigned by the generator
func (id *overtFlakeID) ProcessID() uint16 {
	return uint16(id.Lower() & 0xFFFF)
}

// MachineID is the uint64 representation of HardwareID and ProcessID and is == Lower()
func (id *overtFlakeID) MachineID() uint64 {
	return id.Lower()
}

// Upper is the upper (most-signficant) bytes of the id represented as a uint64
func (id *overtFlakeID) Upper() uint64 {
	return binary.BigEndian.Uint64(id.idBytes[0:8])
}

// Lower is the lower (least-signficant) bytes of the id represented as a uint64
func (id *overtFlakeID) Lower() uint64 {
	return binary.BigEndian.Uint64(id.idBytes[8:16])
}

// Bytes is the []byte representation of the ID
func (id *overtFlakeID) Bytes() []byte {
	return id.idBytes
}

// ToBigInt converts the ID to a *big.Int
func (id *overtFlakeID) ToBigInt() *big.Int {
	i := big.NewInt(0)
	i.SetBytes(id.idBytes)
	return i
}

// String returns the big.Int string representation of the ID
func (id *overtFlakeID) String() string {
	return id.ToBigInt().String()
}
<|endoftext|>


<commit_before>package checks

import (
	"testing"
)

func TestFileChecker(t *testing.T) {
	if err := FileChecker("/tmp").Check(); err == nil {
		t.Errorf("/tmp was expected as exists")
	}

	if err := FileChecker("NoSuchFileFromMoon").Check(); err != nil {
		t.Errorf("NoSuchFileFromMoon was expected as not exists, error:%v", err)
	}
}
<commit_msg>Test: add test for HTTPChecker<commit_after>package checks

import (
	"testing"
)

func TestFileChecker(t *testing.T) {
	if err := FileChecker("/tmp").Check(); err == nil {
		t.Errorf("/tmp was expected as exists")
	}

	if err := FileChecker("NoSuchFileFromMoon").Check(); err != nil {
		t.Errorf("NoSuchFileFromMoon was expected as not exists, error:%v", err)
	}
}

func TestHTTPChecker(t *testing.T) {
	if err := HTTPChecker("https://www.google.cybertron").Check(); err == nil {
		t.Errorf("Google on Cybertron was expected as not exists")
	}

	if err := HTTPChecker("https://www.google.pt").Check(); err != nil {
		t.Errorf("Google at Portugal was expected as exists, error:%v", err)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2018 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

const (
	attestationAuthorityCRD = `apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
    name: attestationauthorities.kritis.grafeas.io
    labels:
        %s: ""
spec:
    group: kritis.grafeas.io
    version: v1beta1
    scope: Namespaced
    names:
        plural: attestationauthorities
        singular: attestationauthority
        kind: AttestationAuthority`

	imageSecurityPolicyCRD = `apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
    name: imagesecuritypolicies.kritis.grafeas.io
    labels:
        %s: ""
spec:
    group: kritis.grafeas.io
    version: v1beta1
    names:
        kind: ImageSecurityPolicy
        plural: imagesecuritypolicies
        scope: Namespaced`

	kritisConfigCRD = `apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: kritisconfigs.kritis.grafeas.io
  labels:
      %s: ""
spec:
  group: kritis.grafeas.io
  version: v1beta1
  names:
    kind: KritisConfig
    plural: kritisconfigs
    singular: kritisconfig
    scope: Cluster`
)
<commit_msg>Fix "scope" position of CRD manifests in helm preinstall hook<commit_after>/*
Copyright 2018 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

const (
	attestationAuthorityCRD = `apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
    name: attestationauthorities.kritis.grafeas.io
    labels:
        %s: ""
spec:
    group: kritis.grafeas.io
    version: v1beta1
    scope: Namespaced
    names:
        plural: attestationauthorities
        singular: attestationauthority
        kind: AttestationAuthority`

	imageSecurityPolicyCRD = `apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
    name: imagesecuritypolicies.kritis.grafeas.io
    labels:
        %s: ""
spec:
    group: kritis.grafeas.io
    version: v1beta1
    scope: Namespaced
    names:
        kind: ImageSecurityPolicy
        plural: imagesecuritypolicies`

	kritisConfigCRD = `apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: kritisconfigs.kritis.grafeas.io
  labels:
      %s: ""
spec:
  group: kritis.grafeas.io
  version: v1beta1
  scope: Cluster
  names:
    kind: KritisConfig
    plural: kritisconfigs
    singular: kritisconfig`
)
<|endoftext|>


<commit_before>package builder

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"sort"
	"strings"
	"time"

	"github.com/Cloud-Foundations/Dominator/lib/filter"
	"github.com/Cloud-Foundations/Dominator/lib/format"
	"github.com/Cloud-Foundations/Dominator/lib/html"
	libjson "github.com/Cloud-Foundations/Dominator/lib/json"
)

const codeStyle = `background-color: #eee; border: 1px solid #999; display: block; float: left;`

func writeFilter(writer io.Writer, prefix string, filt *filter.Filter) {
	if filt != nil && len(filt.FilterLines) > 0 {
		fmt.Fprintln(writer, prefix, "Filter lines:
")
		fmt.Fprintf(writer, "
\n", codeStyle)
		libjson.WriteWithIndent(writer, "    ", filt.FilterLines)
		fmt.Fprintln(writer, "

")
	}
}

func (stream *bootstrapStream) WriteHtml(writer io.Writer) {
	fmt.Fprintf(writer, "Bootstrap command: %s
\n",
		strings.Join(stream.BootstrapCommand, " "))
	writeFilter(writer, "", stream.Filter)
	packager := stream.builder.packagerTypes[stream.PackagerType]
	packager.WriteHtml(writer)
	writeFilter(writer, "Image ", stream.imageFilter)
	if stream.imageTriggers != nil {
		fmt.Fprintln(writer, "Image triggers:
")
		fmt.Fprintf(writer, "
\n", codeStyle)
		libjson.WriteWithIndent(writer, "    ", stream.imageTriggers.Triggers)
		fmt.Fprintln(writer, "

")
	}
}

func (b *Builder) getHtmlWriter(streamName string) html.HtmlWriter {
	if stream := b.getBootstrapStream(streamName); stream != nil {
		return stream
	}
	if stream := b.getNormalStream(streamName); stream != nil {
		return stream
	}
	// Ensure a nil interface is returned, not a stream with value == nil.
	return nil
}

func (b *Builder) showImageStream(writer io.Writer, streamName string) {
	stream := b.getHtmlWriter(streamName)
	if stream == nil {
		fmt.Fprintf(writer, "Stream: %s does not exist!\n", streamName)
		return
	}
	fmt.Fprintf(writer, "
Information for stream: %s
\n", streamName)
	stream.WriteHtml(writer)
}

func (b *Builder) showImageStreams(writer io.Writer) {
	streamNames := b.listAllStreamNames()
	sort.Strings(streamNames)
	fmt.Fprintln(writer, `<table border="1">`)
	fmt.Fprintln(writer, "
")
	fmt.Fprintln(writer, "    Image Stream	")
	fmt.Fprintln(writer, "    ManifestUrl	")
	fmt.Fprintln(writer, "    ManifestDirectory	")
	fmt.Fprintln(writer, "
")
	for _, streamName := range streamNames {
		fmt.Fprintf(writer, "
\n")
		fmt.Fprintf(writer,
			"    %s	\n",
			streamName, streamName)
		if imageStream := b.getNormalStream(streamName); imageStream == nil {
			fmt.Fprintln(writer, "    	")
			fmt.Fprintln(writer, "    	")
		} else {
			fmt.Fprintf(writer, "    %s	\n", imageStream.ManifestUrl)
			fmt.Fprintf(writer, "    %s	\n",
				imageStream.ManifestDirectory)
		}
		fmt.Fprintf(writer, "
\n")
	}
	fmt.Fprintln(writer, "

")
}

func (b *Builder) writeHtml(writer io.Writer) {
	fmt.Fprintf(writer,
		"Number of image streams: %d
\n",
		b.getNumNormalStreams())
	currentBuilds := make([]string, 0)
	goodBuilds := make(map[string]buildResultType)
	failedBuilds := make(map[string]buildResultType)
	b.buildResultsLock.RLock()
	for name := range b.currentBuildLogs {
		currentBuilds = append(currentBuilds, name)
	}
	for name, result := range b.lastBuildResults {
		if result.error == nil {
			goodBuilds[name] = result
		} else {
			failedBuilds[name] = result
		}
	}
	b.buildResultsLock.RUnlock()
	currentTime := time.Now()
	if len(currentBuilds) > 0 {
		fmt.Fprintln(writer, "Current image builds:
")
		fmt.Fprintln(writer, `<table border="1">`)
		fmt.Fprintln(writer, "
")
		fmt.Fprintln(writer, "    Image Stream	")
		fmt.Fprintln(writer, "    Build log	")
		fmt.Fprintln(writer, "
")
		for _, streamName := range currentBuilds {
			fmt.Fprintf(writer, "
\n")
			fmt.Fprintf(writer, "    %s	\n", streamName)
			fmt.Fprintf(writer,
				"    log	\n",
				streamName)
			fmt.Fprintf(writer, "
\n")
		}
		fmt.Fprintln(writer, "

")
	}
	if len(failedBuilds) > 0 {
		streamNames := make([]string, 0, len(failedBuilds))
		for streamName := range failedBuilds {
			streamNames = append(streamNames, streamName)
		}
		sort.Strings(streamNames)
		fmt.Fprintln(writer, "Failed image builds:
")
		fmt.Fprintln(writer, `<table border="1">`)
		fmt.Fprintln(writer, "
")
		fmt.Fprintln(writer, "    Image Stream	")
		fmt.Fprintln(writer, "    Error	")
		fmt.Fprintln(writer, "    Build log	")
		fmt.Fprintln(writer, "    Last attempt	")
		fmt.Fprintln(writer, "
")
		for _, streamName := range streamNames {
			result := failedBuilds[streamName]
			fmt.Fprintf(writer, "
\n")
			fmt.Fprintf(writer, "    %s	\n", streamName)
			fmt.Fprintf(writer, "    %s	\n", result.error)
			fmt.Fprintf(writer,
				"    log	\n",
				streamName)
			fmt.Fprintf(writer, "    %s ago	\n",
				format.Duration(currentTime.Sub(result.finishTime)))
			fmt.Fprintf(writer, "
\n")
		}
		fmt.Fprintln(writer, "

")
	}
	if len(goodBuilds) > 0 {
		streamNames := make([]string, 0, len(goodBuilds))
		for streamName := range goodBuilds {
			streamNames = append(streamNames, streamName)
		}
		sort.Strings(streamNames)
		fmt.Fprintln(writer, "Successful image builds:
")
		fmt.Fprintln(writer, `<table border="1">`)
		fmt.Fprintln(writer, "
")
		fmt.Fprintln(writer, "    Image Stream	")
		fmt.Fprintln(writer, "    Name	")
		fmt.Fprintln(writer, "    Build log	")
		fmt.Fprintln(writer, "    Duration	")
		fmt.Fprintln(writer, "    Age	")
		fmt.Fprintln(writer, "
")
		for _, streamName := range streamNames {
			result := goodBuilds[streamName]
			fmt.Fprintf(writer, "
\n")
			fmt.Fprintf(writer, "    %s	\n", streamName)
			fmt.Fprintf(writer,
				"    %s	\n",
				b.imageServerAddress, result.imageName, result.imageName)
			fmt.Fprintf(writer,
				"    log	\n",
				streamName)
			fmt.Fprintf(writer, "    %s	\n",
				format.Duration(result.finishTime.Sub(result.startTime)))
			fmt.Fprintf(writer, "    %s	\n",
				format.Duration(currentTime.Sub(result.finishTime)))
			fmt.Fprintf(writer, "
\n")
		}
		fmt.Fprintln(writer, "

")
	}
}

func (stream *imageStreamType) WriteHtml(writer io.Writer) {
	if len(stream.BuilderGroups) > 0 {
		fmt.Fprintf(writer, "BuilderGroups: %s
\n",
			strings.Join(stream.BuilderGroups, ", "))
	}
	fmt.Fprintf(writer, "Manifest URL: %s
\n",
		stream.ManifestUrl)
	fmt.Fprintf(writer, "Manifest Directory: %s
\n",
		stream.ManifestDirectory)
	buildLog := new(bytes.Buffer)
	manifestDirectory, gitInfo, err := stream.getManifest(stream.builder,
		stream.name, "", nil, buildLog)
	if err != nil {
		fmt.Fprintf(writer, "%s
\n", err)
		return
	}
	defer os.RemoveAll(manifestDirectory)
	if gitInfo != nil {
		fmt.Fprintf(writer,
			"Latest commit on branch: %s: %ss
\n",
			gitInfo.branch, gitInfo.commitId)
	}
	manifestFilename := path.Join(manifestDirectory, "manifest")
	manifestBytes, err := ioutil.ReadFile(manifestFilename)
	if err != nil {
		fmt.Fprintf(writer, "%s
\n", err)
		return
	}
	var manifest manifestConfigType
	if err := json.Unmarshal(manifestBytes, &manifest); err != nil {
		fmt.Fprintf(writer, "%s
\n", err)
		return
	}
	sourceImageName := os.Expand(manifest.SourceImage,
		func(name string) string {
			return stream.getenv()[name]
		})
	if stream.builder.getHtmlWriter(sourceImageName) == nil {
		fmt.Fprintf(writer, "SourceImage: %s
\n",
			sourceImageName)
	} else {
		fmt.Fprintf(writer,
			"SourceImage: %s
\n",
			sourceImageName, sourceImageName)
	}
	fmt.Fprintln(writer, "Contents of manifest file:
")
	fmt.Fprintf(writer, "
\n", codeStyle)
	writer.Write(manifestBytes)
	fmt.Fprintln(writer, "

")
	packagesFile, err := os.Open(path.Join(manifestDirectory, "package-list"))
	if err == nil {
		defer packagesFile.Close()
		fmt.Fprintln(writer, "Contents of package-list file:
")
		fmt.Fprintf(writer, "
\n", codeStyle)
		io.Copy(writer, packagesFile)
		fmt.Fprintln(writer, "

")
	} else if !os.IsNotExist(err) {
		fmt.Fprintf(writer, "%s
\n", err)
		return
	}
	if size, err := getTreeSize(manifestDirectory); err != nil {
		fmt.Fprintf(writer, "%s
\n", err)
		return
	} else {
		fmt.Fprintf(writer, "Manifest tree size: %s
\n",
			format.FormatBytes(size))
	}
	fmt.Fprintln(writer, "
")
	fmt.Fprintln(writer, "Logging output:")
	fmt.Fprintln(writer, "
")
	io.Copy(writer, buildLog)
	fmt.Fprintln(writer, "
")
	fmt.Fprintln(writer, "")
}

func (packager *packagerType) WriteHtml(writer io.Writer) {
	fmt.Fprintf(writer, "Clean command: %s
\n",
		strings.Join(packager.CleanCommand, " "))
	fmt.Fprintf(writer, "Install command: %s
\n",
		strings.Join(packager.InstallCommand, " "))
	fmt.Fprintf(writer, "List command: %s
\n",
		strings.Join(packager.ListCommand.ArgList, " "))
	if packager.ListCommand.SizeMultiplier > 1 {
		fmt.Fprintf(writer, "List command size multiplier: %d
\n",
			packager.ListCommand.SizeMultiplier)
	}
	fmt.Fprintf(writer, "Remove command: %s
\n",
		strings.Join(packager.RemoveCommand, " "))
	fmt.Fprintf(writer, "Update command: %s
\n",
		strings.Join(packager.UpdateCommand, " "))
	fmt.Fprintf(writer, "Upgrade command: %s
\n",
		strings.Join(packager.UpgradeCommand, " "))
	if len(packager.Verbatim) > 0 {
		fmt.Fprintln(writer, "Verbatim lines:
")
		fmt.Fprintf(writer, "
\n", codeStyle)
		libjson.WriteWithIndent(writer, "    ", packager.Verbatim)
		fmt.Fprintln(writer, "

")
	}
	fmt.Fprintln(writer, "Package installer script:
")
	fmt.Fprintf(writer, "
\n", codeStyle)
	packager.writePackageInstallerContents(writer)
	fmt.Fprintln(writer, "

")
}
<commit_msg>imaginator: use lib/html.TableWriter to beautify tables.<commit_after>package builder

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"sort"
	"strings"
	"time"

	"github.com/Cloud-Foundations/Dominator/lib/filter"
	"github.com/Cloud-Foundations/Dominator/lib/format"
	"github.com/Cloud-Foundations/Dominator/lib/html"
	libjson "github.com/Cloud-Foundations/Dominator/lib/json"
)

const codeStyle = `background-color: #eee; border: 1px solid #999; display: block; float: left;`

func writeFilter(writer io.Writer, prefix string, filt *filter.Filter) {
	if filt != nil && len(filt.FilterLines) > 0 {
		fmt.Fprintln(writer, prefix, "Filter lines:
")
		fmt.Fprintf(writer, "
\n", codeStyle)
		libjson.WriteWithIndent(writer, "    ", filt.FilterLines)
		fmt.Fprintln(writer, "

")
	}
}

func (stream *bootstrapStream) WriteHtml(writer io.Writer) {
	fmt.Fprintf(writer, "Bootstrap command: %s
\n",
		strings.Join(stream.BootstrapCommand, " "))
	writeFilter(writer, "", stream.Filter)
	packager := stream.builder.packagerTypes[stream.PackagerType]
	packager.WriteHtml(writer)
	writeFilter(writer, "Image ", stream.imageFilter)
	if stream.imageTriggers != nil {
		fmt.Fprintln(writer, "Image triggers:
")
		fmt.Fprintf(writer, "
\n", codeStyle)
		libjson.WriteWithIndent(writer, "    ", stream.imageTriggers.Triggers)
		fmt.Fprintln(writer, "

")
	}
}

func (b *Builder) getHtmlWriter(streamName string) html.HtmlWriter {
	if stream := b.getBootstrapStream(streamName); stream != nil {
		return stream
	}
	if stream := b.getNormalStream(streamName); stream != nil {
		return stream
	}
	// Ensure a nil interface is returned, not a stream with value == nil.
	return nil
}

func (b *Builder) showImageStream(writer io.Writer, streamName string) {
	stream := b.getHtmlWriter(streamName)
	if stream == nil {
		fmt.Fprintf(writer, "Stream: %s does not exist!\n", streamName)
		return
	}
	fmt.Fprintf(writer, "
Information for stream: %s
\n", streamName)
	stream.WriteHtml(writer)
}

func (b *Builder) showImageStreams(writer io.Writer) {
	streamNames := b.listAllStreamNames()
	sort.Strings(streamNames)
	fmt.Fprintln(writer, `<table border="1">`)
	tw, _ := html.NewTableWriter(writer, true,
		"Image Stream", "ManifestUrl", "ManifestDirectory")
	for _, streamName := range streamNames {
		var manifestUrl, manifestDirectory string
		if imageStream := b.getNormalStream(streamName); imageStream != nil {
			manifestUrl = imageStream.ManifestUrl
			manifestDirectory = imageStream.ManifestDirectory
		}
		tw.WriteRow("", "",
			fmt.Sprintf("%s",
				streamName, streamName), manifestUrl, manifestDirectory)
	}
	fmt.Fprintln(writer, "
")
}

func (b *Builder) writeHtml(writer io.Writer) {
	fmt.Fprintf(writer,
		"Number of image streams: %d
\n",
		b.getNumNormalStreams())
	currentBuilds := make([]string, 0)
	goodBuilds := make(map[string]buildResultType)
	failedBuilds := make(map[string]buildResultType)
	b.buildResultsLock.RLock()
	for name := range b.currentBuildLogs {
		currentBuilds = append(currentBuilds, name)
	}
	for name, result := range b.lastBuildResults {
		if result.error == nil {
			goodBuilds[name] = result
		} else {
			failedBuilds[name] = result
		}
	}
	b.buildResultsLock.RUnlock()
	currentTime := time.Now()
	if len(currentBuilds) > 0 {
		fmt.Fprintln(writer, "Current image builds:
")
		fmt.Fprintln(writer, `<table border="1">`)
		tw, _ := html.NewTableWriter(writer, true, "Image Stream", "Build log")
		for _, streamName := range currentBuilds {
			tw.WriteRow("", "",
				streamName,
				fmt.Sprintf("log",
					streamName),
			)
		}
		fmt.Fprintln(writer, "

")
	}
	if len(failedBuilds) > 0 {
		streamNames := make([]string, 0, len(failedBuilds))
		for streamName := range failedBuilds {
			streamNames = append(streamNames, streamName)
		}
		sort.Strings(streamNames)
		fmt.Fprintln(writer, "Failed image builds:
")
		fmt.Fprintln(writer, `<table border="1">`)
		tw, _ := html.NewTableWriter(writer, true,
			"Image Stream", "Error", "Build log", "Last attempt")
		for _, streamName := range streamNames {
			result := failedBuilds[streamName]
			tw.WriteRow("", "",
				streamName,
				result.error.Error(),
				fmt.Sprintf("log",
					streamName),
				fmt.Sprintf("%s ago",
					format.Duration(currentTime.Sub(result.finishTime))),
			)
		}
		fmt.Fprintln(writer, "

")
	}
	if len(goodBuilds) > 0 {
		streamNames := make([]string, 0, len(goodBuilds))
		for streamName := range goodBuilds {
			streamNames = append(streamNames, streamName)
		}
		sort.Strings(streamNames)
		fmt.Fprintln(writer, "Successful image builds:
")
		fmt.Fprintln(writer, `<table border="1">`)
		tw, _ := html.NewTableWriter(writer, true, "Image Stream", "Name",
			"Build log", "Duration", "Age")
		for _, streamName := range streamNames {
			result := goodBuilds[streamName]
			tw.WriteRow("", "",
				streamName,
				fmt.Sprintf("%s",
					b.imageServerAddress, result.imageName, result.imageName),
				fmt.Sprintf("log",
					streamName),
				format.Duration(result.finishTime.Sub(result.startTime)),
				fmt.Sprintf("%s ago",
					format.Duration(currentTime.Sub(result.finishTime))),
			)
		}
		fmt.Fprintln(writer, "

")
	}
}

func (stream *imageStreamType) WriteHtml(writer io.Writer) {
	if len(stream.BuilderGroups) > 0 {
		fmt.Fprintf(writer, "BuilderGroups: %s
\n",
			strings.Join(stream.BuilderGroups, ", "))
	}
	fmt.Fprintf(writer, "Manifest URL: %s
\n",
		stream.ManifestUrl)
	fmt.Fprintf(writer, "Manifest Directory: %s
\n",
		stream.ManifestDirectory)
	buildLog := new(bytes.Buffer)
	manifestDirectory, gitInfo, err := stream.getManifest(stream.builder,
		stream.name, "", nil, buildLog)
	if err != nil {
		fmt.Fprintf(writer, "%s
\n", err)
		return
	}
	defer os.RemoveAll(manifestDirectory)
	if gitInfo != nil {
		fmt.Fprintf(writer,
			"Latest commit on branch: %s: %ss
\n",
			gitInfo.branch, gitInfo.commitId)
	}
	manifestFilename := path.Join(manifestDirectory, "manifest")
	manifestBytes, err := ioutil.ReadFile(manifestFilename)
	if err != nil {
		fmt.Fprintf(writer, "%s
\n", err)
		return
	}
	var manifest manifestConfigType
	if err := json.Unmarshal(manifestBytes, &manifest); err != nil {
		fmt.Fprintf(writer, "%s
\n", err)
		return
	}
	sourceImageName := os.Expand(manifest.SourceImage,
		func(name string) string {
			return stream.getenv()[name]
		})
	if stream.builder.getHtmlWriter(sourceImageName) == nil {
		fmt.Fprintf(writer, "SourceImage: %s
\n",
			sourceImageName)
	} else {
		fmt.Fprintf(writer,
			"SourceImage: %s
\n",
			sourceImageName, sourceImageName)
	}
	fmt.Fprintln(writer, "Contents of manifest file:
")
	fmt.Fprintf(writer, "
\n", codeStyle)
	writer.Write(manifestBytes)
	fmt.Fprintln(writer, "

")
	packagesFile, err := os.Open(path.Join(manifestDirectory, "package-list"))
	if err == nil {
		defer packagesFile.Close()
		fmt.Fprintln(writer, "Contents of package-list file:
")
		fmt.Fprintf(writer, "
\n", codeStyle)
		io.Copy(writer, packagesFile)
		fmt.Fprintln(writer, "

")
	} else if !os.IsNotExist(err) {
		fmt.Fprintf(writer, "%s
\n", err)
		return
	}
	if size, err := getTreeSize(manifestDirectory); err != nil {
		fmt.Fprintf(writer, "%s
\n", err)
		return
	} else {
		fmt.Fprintf(writer, "Manifest tree size: %s
\n",
			format.FormatBytes(size))
	}
	fmt.Fprintln(writer, "
")
	fmt.Fprintln(writer, "Logging output:")
	fmt.Fprintln(writer, "
")
	io.Copy(writer, buildLog)
	fmt.Fprintln(writer, "
")
	fmt.Fprintln(writer, "")
}

func (packager *packagerType) WriteHtml(writer io.Writer) {
	fmt.Fprintf(writer, "Clean command: %s
\n",
		strings.Join(packager.CleanCommand, " "))
	fmt.Fprintf(writer, "Install command: %s
\n",
		strings.Join(packager.InstallCommand, " "))
	fmt.Fprintf(writer, "List command: %s
\n",
		strings.Join(packager.ListCommand.ArgList, " "))
	if packager.ListCommand.SizeMultiplier > 1 {
		fmt.Fprintf(writer, "List command size multiplier: %d
\n",
			packager.ListCommand.SizeMultiplier)
	}
	fmt.Fprintf(writer, "Remove command: %s
\n",
		strings.Join(packager.RemoveCommand, " "))
	fmt.Fprintf(writer, "Update command: %s
\n",
		strings.Join(packager.UpdateCommand, " "))
	fmt.Fprintf(writer, "Upgrade command: %s
\n",
		strings.Join(packager.UpgradeCommand, " "))
	if len(packager.Verbatim) > 0 {
		fmt.Fprintln(writer, "Verbatim lines:
")
		fmt.Fprintf(writer, "
\n", codeStyle)
		libjson.WriteWithIndent(writer, "    ", packager.Verbatim)
		fmt.Fprintln(writer, "

")
	}
	fmt.Fprintln(writer, "Package installer script:
")
	fmt.Fprintf(writer, "
\n", codeStyle)
	packager.writePackageInstallerContents(writer)
	fmt.Fprintln(writer, "

")
}
<|endoftext|>


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

// Package ioutil implements some I/O utility functions.
package ioutil

import (
	"bytes"
	"io"
	"os"
	"sort"
)

// readAll reads from r until an error or EOF and returns the data it read
// from the internal buffer allocated with a specified capacity.
func readAll(r io.Reader, capacity int64) (b []byte, err error) {
	buf := bytes.NewBuffer(make([]byte, 0, capacity))
	// If the buffer overflows, we will get bytes.ErrTooLarge.
	// Return that as an error. Any other panic remains.
	defer func() {
		e := recover()
		if e == nil {
			return
		}
		if panicErr, ok := e.(error); ok && panicErr == bytes.ErrTooLarge {
			err = panicErr
		} else {
			panic(e)
		}
	}()
	_, err = buf.ReadFrom(r)
	return buf.Bytes(), err
}

// ReadAll reads from r until an error or EOF and returns the data it read.
func ReadAll(r io.Reader) ([]byte, error) {
	return readAll(r, bytes.MinRead)
}

// ReadFile reads the file named by filename and returns the contents.
func ReadFile(filename string) ([]byte, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	// It's a good but not certain bet that FileInfo will tell us exactly how much to
	// read, so let's try it but be prepared for the answer to be wrong.
	fi, err := f.Stat()
	var n int64
	if size := fi.Size(); err == nil && size < 2e9 { // Don't preallocate a huge buffer, just in case.
		n = size
	}
	// As initial capacity for readAll, use n + a little extra in case Size is zero,
	// and to avoid another allocation after Read has filled the buffer.  The readAll
	// call will read into its allocated internal buffer cheaply.  If the size was
	// wrong, we'll either waste some space off the end or reallocate as needed, but
	// in the overwhelmingly common case we'll get it just right.
	return readAll(f, n+bytes.MinRead)
}

// WriteFile writes data to a file named by filename.
// If the file does not exist, WriteFile creates it with permissions perm;
// otherwise WriteFile truncates it before writing.
func WriteFile(filename string, data []byte, perm os.FileMode) error {
	f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
	if err != nil {
		return err
	}
	n, err := f.Write(data)
	f.Close()
	if err == nil && n < len(data) {
		err = io.ErrShortWrite
	}
	return err
}

// byName implements sort.Interface.
type byName []os.FileInfo

func (f byName) Len() int           { return len(f) }
func (f byName) Less(i, j int) bool { return f[i].Name() < f[j].Name() }
func (f byName) Swap(i, j int)      { f[i], f[j] = f[j], f[i] }

// ReadDir reads the directory named by dirname and returns
// a list of sorted directory entries.
func ReadDir(dirname string) ([]os.FileInfo, error) {
	f, err := os.Open(dirname)
	if err != nil {
		return nil, err
	}
	list, err := f.Readdir(-1)
	f.Close()
	if err != nil {
		return nil, err
	}
	sort.Sort(byName(list))
	return list, nil
}

type nopCloser struct {
	io.Reader
}

func (nopCloser) Close() error { return nil }

// NopCloser returns a ReadCloser with a no-op Close method wrapping
// the provided Reader r.
func NopCloser(r io.Reader) io.ReadCloser {
	return nopCloser{r}
}

type devNull int

// devNull implements ReaderFrom as an optimization so io.Copy to
// ioutil.Discard can avoid doing unnecessary work.
var _ io.ReaderFrom = devNull(0)

func (devNull) Write(p []byte) (int, error) {
	return len(p), nil
}

var blackHole = make([]byte, 8192)

func (devNull) ReadFrom(r io.Reader) (n int64, err error) {
	readSize := 0
	for {
		readSize, err = r.Read(blackHole)
		n += int64(readSize)
		if err != nil {
			if err == io.EOF {
				return n, nil
			}
			return
		}
	}
	panic("unreachable")
}

// Discard is an io.Writer on which all Write calls succeed
// without doing anything.
var Discard io.Writer = devNull(0)
<commit_msg>io/ioutil: document EOF behavior in ReadFile and ReadAll<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package ioutil implements some I/O utility functions.
package ioutil

import (
	"bytes"
	"io"
	"os"
	"sort"
)

// readAll reads from r until an error or EOF and returns the data it read
// from the internal buffer allocated with a specified capacity.
func readAll(r io.Reader, capacity int64) (b []byte, err error) {
	buf := bytes.NewBuffer(make([]byte, 0, capacity))
	// If the buffer overflows, we will get bytes.ErrTooLarge.
	// Return that as an error. Any other panic remains.
	defer func() {
		e := recover()
		if e == nil {
			return
		}
		if panicErr, ok := e.(error); ok && panicErr == bytes.ErrTooLarge {
			err = panicErr
		} else {
			panic(e)
		}
	}()
	_, err = buf.ReadFrom(r)
	return buf.Bytes(), err
}

// ReadAll reads from r until an error or EOF and returns the data it read.
// A successful call returns err == nil, not err == EOF. Because ReadAll is
// defined to read from src until EOF, it does not treat an EOF from Read
// as an error to be reported.
func ReadAll(r io.Reader) ([]byte, error) {
	return readAll(r, bytes.MinRead)
}

// ReadFile reads the file named by filename and returns the contents.
// A successful call returns err == nil, not err == EOF. Because ReadFile
// reads the whole file, it does not treat an EOF from Read as an error
// to be reported.
func ReadFile(filename string) ([]byte, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	// It's a good but not certain bet that FileInfo will tell us exactly how much to
	// read, so let's try it but be prepared for the answer to be wrong.
	fi, err := f.Stat()
	var n int64
	if size := fi.Size(); err == nil && size < 2e9 { // Don't preallocate a huge buffer, just in case.
		n = size
	}
	// As initial capacity for readAll, use n + a little extra in case Size is zero,
	// and to avoid another allocation after Read has filled the buffer.  The readAll
	// call will read into its allocated internal buffer cheaply.  If the size was
	// wrong, we'll either waste some space off the end or reallocate as needed, but
	// in the overwhelmingly common case we'll get it just right.
	return readAll(f, n+bytes.MinRead)
}

// WriteFile writes data to a file named by filename.
// If the file does not exist, WriteFile creates it with permissions perm;
// otherwise WriteFile truncates it before writing.
func WriteFile(filename string, data []byte, perm os.FileMode) error {
	f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
	if err != nil {
		return err
	}
	n, err := f.Write(data)
	f.Close()
	if err == nil && n < len(data) {
		err = io.ErrShortWrite
	}
	return err
}

// byName implements sort.Interface.
type byName []os.FileInfo

func (f byName) Len() int           { return len(f) }
func (f byName) Less(i, j int) bool { return f[i].Name() < f[j].Name() }
func (f byName) Swap(i, j int)      { f[i], f[j] = f[j], f[i] }

// ReadDir reads the directory named by dirname and returns
// a list of sorted directory entries.
func ReadDir(dirname string) ([]os.FileInfo, error) {
	f, err := os.Open(dirname)
	if err != nil {
		return nil, err
	}
	list, err := f.Readdir(-1)
	f.Close()
	if err != nil {
		return nil, err
	}
	sort.Sort(byName(list))
	return list, nil
}

type nopCloser struct {
	io.Reader
}

func (nopCloser) Close() error { return nil }

// NopCloser returns a ReadCloser with a no-op Close method wrapping
// the provided Reader r.
func NopCloser(r io.Reader) io.ReadCloser {
	return nopCloser{r}
}

type devNull int

// devNull implements ReaderFrom as an optimization so io.Copy to
// ioutil.Discard can avoid doing unnecessary work.
var _ io.ReaderFrom = devNull(0)

func (devNull) Write(p []byte) (int, error) {
	return len(p), nil
}

var blackHole = make([]byte, 8192)

func (devNull) ReadFrom(r io.Reader) (n int64, err error) {
	readSize := 0
	for {
		readSize, err = r.Read(blackHole)
		n += int64(readSize)
		if err != nil {
			if err == io.EOF {
				return n, nil
			}
			return
		}
	}
	panic("unreachable")
}

// Discard is an io.Writer on which all Write calls succeed
// without doing anything.
var Discard io.Writer = devNull(0)
<|endoftext|>


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

package http_test

import (
	"fmt"
	"io/ioutil"
	. "net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"testing"
)

const (
	testFile       = "testdata/file"
	testFileLength = 11
)

var ServeFileRangeTests = []struct {
	start, end int
	r          string
	code       int
}{
	{0, testFileLength, "", StatusOK},
	{0, 5, "0-4", StatusPartialContent},
	{2, testFileLength, "2-", StatusPartialContent},
	{testFileLength - 5, testFileLength, "-5", StatusPartialContent},
	{3, 8, "3-7", StatusPartialContent},
	{0, 0, "20-", StatusRequestedRangeNotSatisfiable},
}

func TestServeFile(t *testing.T) {
	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
		ServeFile(w, r, "testdata/file")
	}))
	defer ts.Close()

	var err error

	file, err := ioutil.ReadFile(testFile)
	if err != nil {
		t.Fatal("reading file:", err)
	}

	// set up the Request (re-used for all tests)
	var req Request
	req.Header = make(Header)
	if req.URL, err = url.Parse(ts.URL); err != nil {
		t.Fatal("ParseURL:", err)
	}
	req.Method = "GET"

	// straight GET
	_, body := getBody(t, req)
	if !equal(body, file) {
		t.Fatalf("body mismatch: got %q, want %q", body, file)
	}

	// Range tests
	for _, rt := range ServeFileRangeTests {
		req.Header.Set("Range", "bytes="+rt.r)
		if rt.r == "" {
			req.Header["Range"] = nil
		}
		r, body := getBody(t, req)
		if r.StatusCode != rt.code {
			t.Errorf("range=%q: StatusCode=%d, want %d", rt.r, r.StatusCode, rt.code)
		}
		if rt.code == StatusRequestedRangeNotSatisfiable {
			continue
		}
		h := fmt.Sprintf("bytes %d-%d/%d", rt.start, rt.end-1, testFileLength)
		if rt.r == "" {
			h = ""
		}
		cr := r.Header.Get("Content-Range")
		if cr != h {
			t.Errorf("header mismatch: range=%q: got %q, want %q", rt.r, cr, h)
		}
		if !equal(body, file[rt.start:rt.end]) {
			t.Errorf("body mismatch: range=%q: got %q, want %q", rt.r, body, file[rt.start:rt.end])
		}
	}
}

var fsRedirectTestData = []struct {
	original, redirect string
}{
	{"/test/index.html", "/test/"},
	{"/test/testdata", "/test/testdata/"},
	{"/test/testdata/file/", "/test/testdata/file"},
}

func TestFSRedirect(t *testing.T) {
	ts := httptest.NewServer(StripPrefix("/test", FileServer(Dir("."))))
	defer ts.Close()

	for _, data := range fsRedirectTestData {
		res, err := Get(ts.URL + data.original)
		if err != nil {
			t.Fatal(err)
		}
		res.Body.Close()
		if g, e := res.Request.URL.Path, data.redirect; g != e {
			t.Errorf("redirect from %s: got %s, want %s", data.original, g, e)
		}
	}
}

type testFileSystem struct {
	open func(name string) (File, error)
}

func (fs *testFileSystem) Open(name string) (File, error) {
	return fs.open(name)
}

func TestFileServerCleans(t *testing.T) {
	ch := make(chan string, 1)
	fs := FileServer(&testFileSystem{func(name string) (File, error) {
		ch <- name
		return nil, os.ENOENT
	}})
	tests := []struct {
		reqPath, openArg string
	}{
		{"/foo.txt", "/foo.txt"},
		{"//foo.txt", "/foo.txt"},
		{"/../foo.txt", "/foo.txt"},
	}
	req, _ := NewRequest("GET", "http://example.com", nil)
	for n, test := range tests {
		rec := httptest.NewRecorder()
		req.URL.Path = test.reqPath
		fs.ServeHTTP(rec, req)
		if got := <-ch; got != test.openArg {
			t.Errorf("test %d: got %q, want %q", n, got, test.openArg)
		}
	}
}

func TestFileServerImplicitLeadingSlash(t *testing.T) {
	tempDir, err := ioutil.TempDir("", "")
	if err != nil {
		t.Fatalf("TempDir: %v", err)
	}
	defer os.RemoveAll(tempDir)
	if err := ioutil.WriteFile(filepath.Join(tempDir, "foo.txt"), []byte("Hello world"), 0644); err != nil {
		t.Fatalf("WriteFile: %v", err)
	}
	ts := httptest.NewServer(StripPrefix("/bar/", FileServer(Dir(tempDir))))
	defer ts.Close()
	get := func(suffix string) string {
		res, err := Get(ts.URL + suffix)
		if err != nil {
			t.Fatalf("Get %s: %v", suffix, err)
		}
		b, err := ioutil.ReadAll(res.Body)
		if err != nil {
			t.Fatalf("ReadAll %s: %v", suffix, err)
		}
		return string(b)
	}
	if s := get("/bar/"); !strings.Contains(s, ">foo.txt<") {
		t.Logf("expected a directory listing with foo.txt, got %q", s)
	}
	if s := get("/bar/foo.txt"); s != "Hello world" {
		t.Logf("expected %q, got %q", "Hello world", s)
	}
}

func TestDirJoin(t *testing.T) {
	wfi, err := os.Stat("/etc/hosts")
	if err != nil {
		t.Logf("skipping test; no /etc/hosts file")
		return
	}
	test := func(d Dir, name string) {
		f, err := d.Open(name)
		if err != nil {
			t.Fatalf("open of %s: %v", name, err)
		}
		defer f.Close()
		gfi, err := f.Stat()
		if err != nil {
			t.Fatalf("stat of %s: %v", name, err)
		}
		if !gfi.(*os.FileStat).SameFile(wfi.(*os.FileStat)) {
			t.Errorf("%s got different file", name)
		}
	}
	test(Dir("/etc/"), "/hosts")
	test(Dir("/etc/"), "hosts")
	test(Dir("/etc/"), "../../../../hosts")
	test(Dir("/etc"), "/hosts")
	test(Dir("/etc"), "hosts")
	test(Dir("/etc"), "../../../../hosts")

	// Not really directories, but since we use this trick in
	// ServeFile, test it:
	test(Dir("/etc/hosts"), "")
	test(Dir("/etc/hosts"), "/")
	test(Dir("/etc/hosts"), "../")
}

func TestEmptyDirOpenCWD(t *testing.T) {
	test := func(d Dir) {
		name := "fs_test.go"
		f, err := d.Open(name)
		if err != nil {
			t.Fatalf("open of %s: %v", name, err)
		}
		defer f.Close()
	}
	test(Dir(""))
	test(Dir("."))
	test(Dir("./"))
}

func TestServeFileContentType(t *testing.T) {
	const ctype = "icecream/chocolate"
	override := false
	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
		if override {
			w.Header().Set("Content-Type", ctype)
		}
		ServeFile(w, r, "testdata/file")
	}))
	defer ts.Close()
	get := func(want string) {
		resp, err := Get(ts.URL)
		if err != nil {
			t.Fatal(err)
		}
		if h := resp.Header.Get("Content-Type"); h != want {
			t.Errorf("Content-Type mismatch: got %q, want %q", h, want)
		}
	}
	get("text/plain; charset=utf-8")
	override = true
	get(ctype)
}

func TestServeFileMimeType(t *testing.T) {
	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
		ServeFile(w, r, "testdata/style.css")
	}))
	defer ts.Close()
	resp, err := Get(ts.URL)
	if err != nil {
		t.Fatal(err)
	}
	want := "text/css; charset=utf-8"
	if h := resp.Header.Get("Content-Type"); h != want {
		t.Errorf("Content-Type mismatch: got %q, want %q", h, want)
	}
}

func TestServeFileFromCWD(t *testing.T) {
	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
		ServeFile(w, r, "fs_test.go")
	}))
	defer ts.Close()
	r, err := Get(ts.URL)
	if err != nil {
		t.Fatal(err)
	}
	if r.StatusCode != 200 {
		t.Fatalf("expected 200 OK, got %s", r.Status)
	}
}

func TestServeFileWithContentEncoding(t *testing.T) {
	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
		w.Header().Set("Content-Encoding", "foo")
		ServeFile(w, r, "testdata/file")
	}))
	defer ts.Close()
	resp, err := Get(ts.URL)
	if err != nil {
		t.Fatal(err)
	}
	if g, e := resp.ContentLength, int64(-1); g != e {
		t.Errorf("Content-Length mismatch: got %d, want %d", g, e)
	}
}

func TestServeIndexHtml(t *testing.T) {
	const want = "index.html says hello\n"
	ts := httptest.NewServer(FileServer(Dir(".")))
	defer ts.Close()

	for _, path := range []string{"/testdata/", "/testdata/index.html"} {
		res, err := Get(ts.URL + path)
		if err != nil {
			t.Fatal(err)
		}
		defer res.Body.Close()
		b, err := ioutil.ReadAll(res.Body)
		if err != nil {
			t.Fatal("reading Body:", err)
		}
		if s := string(b); s != want {
			t.Errorf("for path %q got %q, want %q", path, s, want)
		}
	}
}

func getBody(t *testing.T, req Request) (*Response, []byte) {
	r, err := DefaultClient.Do(&req)
	if err != nil {
		t.Fatal(req.URL.String(), "send:", err)
	}
	b, err := ioutil.ReadAll(r.Body)
	if err != nil {
		t.Fatal("reading Body:", err)
	}
	return r, b
}

func equal(a, b []byte) bool {
	if len(a) != len(b) {
		return false
	}
	for i := range a {
		if a[i] != b[i] {
			return false
		}
	}
	return true
}
<commit_msg>net/http: fix data race in test Fixes issue 2712.<commit_after>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package http_test

import (
	"fmt"
	"io/ioutil"
	. "net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"testing"
)

const (
	testFile       = "testdata/file"
	testFileLength = 11
)

var ServeFileRangeTests = []struct {
	start, end int
	r          string
	code       int
}{
	{0, testFileLength, "", StatusOK},
	{0, 5, "0-4", StatusPartialContent},
	{2, testFileLength, "2-", StatusPartialContent},
	{testFileLength - 5, testFileLength, "-5", StatusPartialContent},
	{3, 8, "3-7", StatusPartialContent},
	{0, 0, "20-", StatusRequestedRangeNotSatisfiable},
}

func TestServeFile(t *testing.T) {
	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
		ServeFile(w, r, "testdata/file")
	}))
	defer ts.Close()

	var err error

	file, err := ioutil.ReadFile(testFile)
	if err != nil {
		t.Fatal("reading file:", err)
	}

	// set up the Request (re-used for all tests)
	var req Request
	req.Header = make(Header)
	if req.URL, err = url.Parse(ts.URL); err != nil {
		t.Fatal("ParseURL:", err)
	}
	req.Method = "GET"

	// straight GET
	_, body := getBody(t, req)
	if !equal(body, file) {
		t.Fatalf("body mismatch: got %q, want %q", body, file)
	}

	// Range tests
	for _, rt := range ServeFileRangeTests {
		req.Header.Set("Range", "bytes="+rt.r)
		if rt.r == "" {
			req.Header["Range"] = nil
		}
		r, body := getBody(t, req)
		if r.StatusCode != rt.code {
			t.Errorf("range=%q: StatusCode=%d, want %d", rt.r, r.StatusCode, rt.code)
		}
		if rt.code == StatusRequestedRangeNotSatisfiable {
			continue
		}
		h := fmt.Sprintf("bytes %d-%d/%d", rt.start, rt.end-1, testFileLength)
		if rt.r == "" {
			h = ""
		}
		cr := r.Header.Get("Content-Range")
		if cr != h {
			t.Errorf("header mismatch: range=%q: got %q, want %q", rt.r, cr, h)
		}
		if !equal(body, file[rt.start:rt.end]) {
			t.Errorf("body mismatch: range=%q: got %q, want %q", rt.r, body, file[rt.start:rt.end])
		}
	}
}

var fsRedirectTestData = []struct {
	original, redirect string
}{
	{"/test/index.html", "/test/"},
	{"/test/testdata", "/test/testdata/"},
	{"/test/testdata/file/", "/test/testdata/file"},
}

func TestFSRedirect(t *testing.T) {
	ts := httptest.NewServer(StripPrefix("/test", FileServer(Dir("."))))
	defer ts.Close()

	for _, data := range fsRedirectTestData {
		res, err := Get(ts.URL + data.original)
		if err != nil {
			t.Fatal(err)
		}
		res.Body.Close()
		if g, e := res.Request.URL.Path, data.redirect; g != e {
			t.Errorf("redirect from %s: got %s, want %s", data.original, g, e)
		}
	}
}

type testFileSystem struct {
	open func(name string) (File, error)
}

func (fs *testFileSystem) Open(name string) (File, error) {
	return fs.open(name)
}

func TestFileServerCleans(t *testing.T) {
	ch := make(chan string, 1)
	fs := FileServer(&testFileSystem{func(name string) (File, error) {
		ch <- name
		return nil, os.ENOENT
	}})
	tests := []struct {
		reqPath, openArg string
	}{
		{"/foo.txt", "/foo.txt"},
		{"//foo.txt", "/foo.txt"},
		{"/../foo.txt", "/foo.txt"},
	}
	req, _ := NewRequest("GET", "http://example.com", nil)
	for n, test := range tests {
		rec := httptest.NewRecorder()
		req.URL.Path = test.reqPath
		fs.ServeHTTP(rec, req)
		if got := <-ch; got != test.openArg {
			t.Errorf("test %d: got %q, want %q", n, got, test.openArg)
		}
	}
}

func TestFileServerImplicitLeadingSlash(t *testing.T) {
	tempDir, err := ioutil.TempDir("", "")
	if err != nil {
		t.Fatalf("TempDir: %v", err)
	}
	defer os.RemoveAll(tempDir)
	if err := ioutil.WriteFile(filepath.Join(tempDir, "foo.txt"), []byte("Hello world"), 0644); err != nil {
		t.Fatalf("WriteFile: %v", err)
	}
	ts := httptest.NewServer(StripPrefix("/bar/", FileServer(Dir(tempDir))))
	defer ts.Close()
	get := func(suffix string) string {
		res, err := Get(ts.URL + suffix)
		if err != nil {
			t.Fatalf("Get %s: %v", suffix, err)
		}
		b, err := ioutil.ReadAll(res.Body)
		if err != nil {
			t.Fatalf("ReadAll %s: %v", suffix, err)
		}
		return string(b)
	}
	if s := get("/bar/"); !strings.Contains(s, ">foo.txt<") {
		t.Logf("expected a directory listing with foo.txt, got %q", s)
	}
	if s := get("/bar/foo.txt"); s != "Hello world" {
		t.Logf("expected %q, got %q", "Hello world", s)
	}
}

func TestDirJoin(t *testing.T) {
	wfi, err := os.Stat("/etc/hosts")
	if err != nil {
		t.Logf("skipping test; no /etc/hosts file")
		return
	}
	test := func(d Dir, name string) {
		f, err := d.Open(name)
		if err != nil {
			t.Fatalf("open of %s: %v", name, err)
		}
		defer f.Close()
		gfi, err := f.Stat()
		if err != nil {
			t.Fatalf("stat of %s: %v", name, err)
		}
		if !gfi.(*os.FileStat).SameFile(wfi.(*os.FileStat)) {
			t.Errorf("%s got different file", name)
		}
	}
	test(Dir("/etc/"), "/hosts")
	test(Dir("/etc/"), "hosts")
	test(Dir("/etc/"), "../../../../hosts")
	test(Dir("/etc"), "/hosts")
	test(Dir("/etc"), "hosts")
	test(Dir("/etc"), "../../../../hosts")

	// Not really directories, but since we use this trick in
	// ServeFile, test it:
	test(Dir("/etc/hosts"), "")
	test(Dir("/etc/hosts"), "/")
	test(Dir("/etc/hosts"), "../")
}

func TestEmptyDirOpenCWD(t *testing.T) {
	test := func(d Dir) {
		name := "fs_test.go"
		f, err := d.Open(name)
		if err != nil {
			t.Fatalf("open of %s: %v", name, err)
		}
		defer f.Close()
	}
	test(Dir(""))
	test(Dir("."))
	test(Dir("./"))
}

func TestServeFileContentType(t *testing.T) {
	const ctype = "icecream/chocolate"
	override := make(chan bool, 1)
	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
		if <-override {
			w.Header().Set("Content-Type", ctype)
		}
		ServeFile(w, r, "testdata/file")
	}))
	defer ts.Close()
	get := func(want string) {
		resp, err := Get(ts.URL)
		if err != nil {
			t.Fatal(err)
		}
		if h := resp.Header.Get("Content-Type"); h != want {
			t.Errorf("Content-Type mismatch: got %q, want %q", h, want)
		}
	}
	override <- false
	get("text/plain; charset=utf-8")
	override <- true
	get(ctype)
}

func TestServeFileMimeType(t *testing.T) {
	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
		ServeFile(w, r, "testdata/style.css")
	}))
	defer ts.Close()
	resp, err := Get(ts.URL)
	if err != nil {
		t.Fatal(err)
	}
	want := "text/css; charset=utf-8"
	if h := resp.Header.Get("Content-Type"); h != want {
		t.Errorf("Content-Type mismatch: got %q, want %q", h, want)
	}
}

func TestServeFileFromCWD(t *testing.T) {
	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
		ServeFile(w, r, "fs_test.go")
	}))
	defer ts.Close()
	r, err := Get(ts.URL)
	if err != nil {
		t.Fatal(err)
	}
	if r.StatusCode != 200 {
		t.Fatalf("expected 200 OK, got %s", r.Status)
	}
}

func TestServeFileWithContentEncoding(t *testing.T) {
	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
		w.Header().Set("Content-Encoding", "foo")
		ServeFile(w, r, "testdata/file")
	}))
	defer ts.Close()
	resp, err := Get(ts.URL)
	if err != nil {
		t.Fatal(err)
	}
	if g, e := resp.ContentLength, int64(-1); g != e {
		t.Errorf("Content-Length mismatch: got %d, want %d", g, e)
	}
}

func TestServeIndexHtml(t *testing.T) {
	const want = "index.html says hello\n"
	ts := httptest.NewServer(FileServer(Dir(".")))
	defer ts.Close()

	for _, path := range []string{"/testdata/", "/testdata/index.html"} {
		res, err := Get(ts.URL + path)
		if err != nil {
			t.Fatal(err)
		}
		defer res.Body.Close()
		b, err := ioutil.ReadAll(res.Body)
		if err != nil {
			t.Fatal("reading Body:", err)
		}
		if s := string(b); s != want {
			t.Errorf("for path %q got %q, want %q", path, s, want)
		}
	}
}

func getBody(t *testing.T, req Request) (*Response, []byte) {
	r, err := DefaultClient.Do(&req)
	if err != nil {
		t.Fatal(req.URL.String(), "send:", err)
	}
	b, err := ioutil.ReadAll(r.Body)
	if err != nil {
		t.Fatal("reading Body:", err)
	}
	return r, b
}

func equal(a, b []byte) bool {
	if len(a) != len(b) {
		return false
	}
	for i := range a {
		if a[i] != b[i] {
			return false
		}
	}
	return true
}
<|endoftext|>


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

package integration

import (
	"fmt"
	"net/http"
	"os"
	"os/user"
	"path/filepath"
	"testing"
	"time"

	"code.gitea.io/gitea/integrations/internal/utils"
)

// The HTTP port listened by the Gitea server.
const ServerHTTPPort = "3001"

const _RetryLimit = 10

func makeSimpleSettings(user, workdir, port string) map[string][]string {
	return map[string][]string{
		"db_type":        {"SQLite3"},
		"db_host":        {"localhost"},
		"db_path":        {workdir + "data/gitea.db"},
		"app_name":       {"Gitea: Git with a cup of tea"},
		"repo_root_path": {workdir + "repositories"},
		"run_user":       {user},
		"domain":         {"localhost"},
		"ssh_port":       {"22"},
		"http_port":      {port},
		"app_url":        {"http://localhost:" + port},
		"log_root_path":  {workdir + "log"},
	}
}

func install(t *utils.T) error {
	var r *http.Response
	var err error

	for i := 1; i <= _RetryLimit; i++ {

		r, err = http.Get("http://:" + ServerHTTPPort + "/")
		if err == nil {
			fmt.Fprintln(os.Stderr)
			break
		}

		// Give the server some amount of time to warm up.
		time.Sleep(100 * time.Millisecond)
		fmt.Fprint(os.Stderr, ".")
	}

	if err != nil {
		return err
	}

	defer r.Body.Close()

	_user, err := user.Current()
	if err != nil {
		return err
	}

	path, err := filepath.Abs(t.Config.WorkDir)
	if err != nil {
		return err
	}

	settings := makeSimpleSettings(_user.Username, path, ServerHTTPPort)
	r, err = http.PostForm("http://:"+ServerHTTPPort+"/install", settings)
	if err != nil {
		return err
	}
	defer r.Body.Close()

	if r.StatusCode != http.StatusOK {
		return fmt.Errorf("'/install': %s", r.Status)
	}
	return nil
}

func TestInstall(t *testing.T) {
	conf := utils.Config{
		Program: "../gitea",
		WorkDir: "",
		Args:    []string{"web", "--port", ServerHTTPPort},
		LogFile: os.Stderr,
	}

	if err := utils.New(t, &conf).RunTest(install); err != nil {
		t.Fatal(err)
	}
}
<commit_msg>Fix stray directories generated by integration tests (#1134)<commit_after>// Copyright 2017 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package integration

import (
	"fmt"
	"net/http"
	"os"
	"os/user"
	"testing"
	"time"

	"code.gitea.io/gitea/integrations/internal/utils"
)

// The HTTP port listened by the Gitea server.
const ServerHTTPPort = "3001"

const _RetryLimit = 10

func makeSimpleSettings(user, port string) map[string][]string {
	return map[string][]string{
		"db_type":        {"SQLite3"},
		"db_host":        {"localhost"},
		"db_path":        {"data/gitea.db"},
		"app_name":       {"Gitea: Git with a cup of tea"},
		"repo_root_path": {"repositories"},
		"run_user":       {user},
		"domain":         {"localhost"},
		"ssh_port":       {"22"},
		"http_port":      {port},
		"app_url":        {"http://localhost:" + port},
		"log_root_path":  {"log"},
	}
}

func install(t *utils.T) error {
	var r *http.Response
	var err error

	for i := 1; i <= _RetryLimit; i++ {

		r, err = http.Get("http://:" + ServerHTTPPort + "/")
		if err == nil {
			fmt.Fprintln(os.Stderr)
			break
		}

		// Give the server some amount of time to warm up.
		time.Sleep(100 * time.Millisecond)
		fmt.Fprint(os.Stderr, ".")
	}

	if err != nil {
		return err
	}

	defer r.Body.Close()

	_user, err := user.Current()
	if err != nil {
		return err
	}

	settings := makeSimpleSettings(_user.Username, ServerHTTPPort)
	r, err = http.PostForm("http://:"+ServerHTTPPort+"/install", settings)
	if err != nil {
		return err
	}
	defer r.Body.Close()

	if r.StatusCode != http.StatusOK {
		return fmt.Errorf("'/install': %s", r.Status)
	}
	return nil
}

func TestInstall(t *testing.T) {
	conf := utils.Config{
		Program: "../gitea",
		WorkDir: "",
		Args:    []string{"web", "--port", ServerHTTPPort},
		LogFile: os.Stderr,
	}

	if err := utils.New(t, &conf).RunTest(install); err != nil {
		t.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package database

import (
	"gopkg.in/inconshreveable/log15.v2"
)

var dbUpdates = []dbUpdate{
	{version: 1, run: dbUpdateFromV0},
}

type dbUpdate struct {
	version int
	run     func(previousVersion int, version int, db *DB) error
}

func (u *dbUpdate) apply(currentVersion int, db *DB, logger log15.Logger) error {
	logger.Info("Updating DB schema", log15.Ctx{"current": currentVersion, "update": u.version})

	err := u.run(currentVersion, u.version, db)
	if err != nil {
		return err
	}

	_, err = db.Exec("INSERT INTO schema (version, updated_at) VALUES (?, strftime(\"%s\"));", u.version)
	if err != nil {
		return err
	}

	return nil
}

func dbUpdateFromV0(currentVersion int, version int, db *DB) error {
	_, err := db.Exec("ALTER TABLE team ADD COLUMN tags VARCHAR;")
	return err
}
<commit_msg>askgod-server: Fix Schema updates<commit_after>package database

import (
	"time"

	"gopkg.in/inconshreveable/log15.v2"
)

var dbUpdates = []dbUpdate{
	{version: 1, run: dbUpdateFromV0},
}

type dbUpdate struct {
	version int
	run     func(previousVersion int, version int, db *DB) error
}

func (u *dbUpdate) apply(currentVersion int, db *DB, logger log15.Logger) error {
	logger.Info("Updating DB schema", log15.Ctx{"current": currentVersion, "update": u.version})

	err := u.run(currentVersion, u.version, db)
	if err != nil {
		return err
	}

	_, err = db.Exec("INSERT INTO schema (version, updated_at) VALUES ($1, $2);", u.version, time.Now())
	if err != nil {
		return err
	}

	return nil
}

func dbUpdateFromV0(currentVersion int, version int, db *DB) error {
	_, err := db.Exec("ALTER TABLE team ADD COLUMN tags VARCHAR;")
	return err
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package marshaled

import (
	"fmt"
	"io"
	"log"
	"sort"
	"strings"
	"sync"
	"time"

	"github.com/uber-go/gwr/source"
)

// NOTE: This approach is perhaps overfit to the json module's marshalling
// mindset.  A better interface (for performance) would work by passing a
// writer to the specific encoder, rather than a []byte-returning Marshal
// function.  This would be possible perhaps using something like
// io.MultiWriter.

// DataSource wraps a format-agnostic data source and provides one or
// more formats for it.
//
// DataSource implements:
// - DataSource to satisfy DataSources and low level protocols
// - ItemDataSource so that higher level protocols may add their own framing
// - GenericDataWatcher inwardly to the wrapped GenericDataSource
type DataSource struct {
	// TODO: better to have alternate implementations for each combination
	// rather than one with these nil checks
	source      source.GenericDataSource
	getSource   source.GetableDataSource
	watchSource source.WatchableDataSource
	watiSource  source.WatchInitableDataSource
	actiSource  source.ActivateWatchableDataSource

	formats     map[string]source.GenericDataFormat
	formatNames []string
	maxItems    int
	maxBatches  int
	maxWait     time.Duration

	procs     sync.WaitGroup
	watchLock sync.Mutex
	watchers  map[string]*marshaledWatcher
	active    bool
	itemChan  chan interface{}
	itemsChan chan []interface{}
}

func stringIt(item interface{}) ([]byte, error) {
	var s string
	if ss, ok := item.(fmt.Stringer); ok {
		s = ss.String()
	} else {
		s = fmt.Sprintf("%+v", item)
	}
	return []byte(s), nil
}

// NewDataSource creates a DataSource for a given format-agnostic data source
// and a map of marshalers
func NewDataSource(
	src source.GenericDataSource,
	formats map[string]source.GenericDataFormat,
) *DataSource {
	if formats == nil {
		formats = make(map[string]source.GenericDataFormat)
	}

	// source-defined formats
	if fmtsrc, ok := src.(source.GenericDataSourceFormats); ok {
		fmts := fmtsrc.Formats()
		for name, fmt := range fmts {
			formats[name] = fmt
		}
	}

	// standard json protocol
	if formats["json"] == nil {
		formats["json"] = LDJSONMarshal
	}

	// convenience templated text protocol
	if formats["text"] == nil {
		if txtsrc, ok := src.(source.TextTemplatedSource); ok {
			if tt := txtsrc.TextTemplate(); tt != nil {
				formats["text"] = NewTemplatedMarshal(tt)
			}
		}
	}

	// default to just string-ing it
	if formats["text"] == nil {
		formats["text"] = source.GenericDataFormatFunc(stringIt)
	}

	ds := &DataSource{
		source:   src,
		formats:  formats,
		watchers: make(map[string]*marshaledWatcher, len(formats)),
		// TODO: tunable
		maxItems:   100,
		maxBatches: 100,
		maxWait:    100 * time.Microsecond,
	}
	ds.getSource, _ = src.(source.GetableDataSource)
	ds.watchSource, _ = src.(source.WatchableDataSource)
	ds.watiSource, _ = src.(source.WatchInitableDataSource)
	ds.actiSource, _ = src.(source.ActivateWatchableDataSource)
	for name, format := range formats {
		ds.formatNames = append(ds.formatNames, name)
		ds.watchers[name] = newMarshaledWatcher(ds, format)
	}
	sort.Strings(ds.formatNames)

	if ds.watchSource != nil {
		ds.watchSource.SetWatcher(ds)
	}

	return ds
}

// Active returns true if there are any active watchers, false otherwise.  If
// Active returns false, so will any calls to HandleItem and HandleItems.
func (mds *DataSource) Active() bool {
	mds.watchLock.Lock()
	r := mds.active && mds.itemChan != nil && mds.itemsChan != nil
	mds.watchLock.Unlock()
	return r
}

// Name passes through the GenericDataSource.Name()
func (mds *DataSource) Name() string {
	return mds.source.Name()
}

// Formats returns the list of supported format names.
func (mds *DataSource) Formats() []string {
	return mds.formatNames
}

// Attrs returns arbitrary description information about the data source.
func (mds *DataSource) Attrs() map[string]interface{} {
	// TODO: support per-format Attrs?
	// TODO: any support for per-source Attrs?
	return nil
}

// Get marshals data source's Get data to the writer
func (mds *DataSource) Get(formatName string, w io.Writer) error {
	if mds.getSource == nil {
		return source.ErrNotGetable
	}
	format, ok := mds.formats[strings.ToLower(formatName)]
	if !ok {
		return source.ErrUnsupportedFormat
	}
	data := mds.getSource.Get()
	buf, err := format.MarshalGet(data)
	if err != nil {
		log.Printf("get marshaling error %v", err)
		return err
	}
	_, err = w.Write(buf)
	return err
}

// Watch marshals any data source GetInit data to the writer, and then
// retains a reference to the writer so that any future agnostic data source
// Watch(emit)'ed data gets marshaled to it as well
func (mds *DataSource) Watch(formatName string, w io.Writer) error {
	if mds.watchSource == nil {
		return source.ErrNotWatchable
	}

	mds.watchLock.Lock()
	acted := !mds.active
	err := func() error {
		defer mds.watchLock.Unlock()
		watcher, ok := mds.watchers[strings.ToLower(formatName)]
		if !ok {
			return source.ErrUnsupportedFormat
		}
		if err := watcher.init(w); err != nil {
			return err
		}
		if err := mds.startWatching(); err != nil {
			return err
		}
		return nil
	}()

	if err == nil && acted && mds.actiSource != nil {
		mds.actiSource.Activate()
	}
	return err
}

// WatchItems marshals any data source GetInit data as a single item to the
// ItemWatcher's HandleItem method.  The watcher is then retained and future
// items are marshaled to its HandleItem method.
func (mds *DataSource) WatchItems(formatName string, iw source.ItemWatcher) error {
	if mds.watchSource == nil {
		return source.ErrNotWatchable
	}

	mds.watchLock.Lock()
	acted := !mds.active
	err := func() error {
		defer mds.watchLock.Unlock()
		watcher, ok := mds.watchers[strings.ToLower(formatName)]
		if !ok {
			return source.ErrUnsupportedFormat
		}
		if err := watcher.initItems(iw); err != nil {
			return err
		}
		if err := mds.startWatching(); err != nil {
			return err
		}
		return nil
	}()

	if err == nil && acted && mds.actiSource != nil {
		mds.actiSource.Activate()
	}
	return err
}

// startWatching flips the active bit, creates new item channels, and starts a
// processing go routine; it assumes that the watchLock is being held by the
// caller.
func (mds *DataSource) startWatching() error {
	// TODO: we could optimize the only-one-format-being-watched case
	if mds.active {
		return nil
	}
	mds.active = true
	mds.itemChan = make(chan interface{}, mds.maxItems)
	mds.itemsChan = make(chan []interface{}, mds.maxBatches)
	mds.procs.Add(1)
	go mds.processItemChan(mds.itemChan, mds.itemsChan)
	return nil
}

// Drain closes the item channels, and waits for the item processor to finish.
// After drain, any remaining watchers are closed, and the source goes
// inactive.
func (mds *DataSource) Drain() {
	mds.watchLock.Lock()
	any := false
	if mds.itemChan != nil {
		close(mds.itemChan)
		any = true
		mds.itemChan = nil
	}
	if mds.itemsChan != nil {
		close(mds.itemsChan)
		any = true
		mds.itemsChan = nil
	}
	if any {
		mds.watchLock.Unlock()
		mds.procs.Wait()
		mds.watchLock.Lock()
	}
	stop := mds.active
	if stop {
		mds.active = false
	}
	mds.watchLock.Unlock()

	if stop {
		for _, watcher := range mds.watchers {
			watcher.Close()
		}
	}
}

func (mds *DataSource) processItemChan(itemChan chan interface{}, itemsChan chan []interface{}) {
	defer mds.procs.Done()

	stop := false

loop:
	for {
		mds.watchLock.Lock()
		active := mds.active
		watchers := mds.watchers
		mds.watchLock.Unlock()
		if !active {
			break loop
		}
		select {
		case item, ok := <-itemChan:
			if !ok {
				itemChan = nil
				continue loop
			}
			any := false
			for _, watcher := range watchers {
				if watcher.emit(item) {
					any = true
				}
			}
			if !any {
				stop = true
				break loop
			}

		case items, ok := <-itemsChan:
			if !ok {
				itemsChan = nil
				continue loop
			}
			any := false
			for _, watcher := range watchers {
				if watcher.emitBatch(items) {
					any = true
				}
			}
			if !any {
				stop = true
				break loop
			}

		default:
			if itemChan == nil && itemsChan == nil {
				break loop
			}
		}
	}

	mds.watchLock.Lock()
	if mds.itemChan == itemChan {
		mds.itemChan = nil
	}
	if mds.itemsChan == itemsChan {
		mds.itemsChan = nil
	}
	if stop {
		mds.active = false
	}
	mds.watchLock.Unlock()

	if stop {
		for _, watcher := range mds.watchers {
			watcher.Close()
		}
	}
}

// HandleItem implements GenericDataWatcher.HandleItem by passing the item to
// all current marshaledWatchers.
func (mds *DataSource) HandleItem(item interface{}) bool {
	if !mds.Active() {
		return false
	}
	select {
	case mds.itemChan <- item:
		return true
	case <-time.After(mds.maxWait):
		mds.watchLock.Lock()
		if !mds.active {
			mds.watchLock.Unlock()
			return false
		}
		mds.active = false
		mds.watchLock.Unlock()
		for _, watcher := range mds.watchers {
			watcher.Close()
		}
		return false
	}
}

// HandleItems implements GenericDataWatcher.HandleItems by passing the batch
// to all current marshaledWatchers.
func (mds *DataSource) HandleItems(items []interface{}) bool {
	if !mds.Active() {
		return false
	}
	select {
	case mds.itemsChan <- items:
		return true
	case <-time.After(mds.maxWait):
		mds.watchLock.Lock()
		if !mds.active {
			mds.watchLock.Unlock()
			return false
		}
		mds.active = false
		mds.watchLock.Unlock()
		for _, watcher := range mds.watchers {
			watcher.Close()
		}
		return false
	}
}
<commit_msg>use RWMutex in DataSource (#26)<commit_after>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package marshaled

import (
	"fmt"
	"io"
	"log"
	"sort"
	"strings"
	"sync"
	"time"

	"github.com/uber-go/gwr/source"
)

// NOTE: This approach is perhaps overfit to the json module's marshalling
// mindset.  A better interface (for performance) would work by passing a
// writer to the specific encoder, rather than a []byte-returning Marshal
// function.  This would be possible perhaps using something like
// io.MultiWriter.

// DataSource wraps a format-agnostic data source and provides one or
// more formats for it.
//
// DataSource implements:
// - DataSource to satisfy DataSources and low level protocols
// - ItemDataSource so that higher level protocols may add their own framing
// - GenericDataWatcher inwardly to the wrapped GenericDataSource
type DataSource struct {
	// TODO: better to have alternate implementations for each combination
	// rather than one with these nil checks
	source      source.GenericDataSource
	getSource   source.GetableDataSource
	watchSource source.WatchableDataSource
	watiSource  source.WatchInitableDataSource
	actiSource  source.ActivateWatchableDataSource

	formats     map[string]source.GenericDataFormat
	formatNames []string
	maxItems    int
	maxBatches  int
	maxWait     time.Duration

	procs     sync.WaitGroup
	watchLock sync.RWMutex
	watchers  map[string]*marshaledWatcher
	active    bool
	itemChan  chan interface{}
	itemsChan chan []interface{}
}

func stringIt(item interface{}) ([]byte, error) {
	var s string
	if ss, ok := item.(fmt.Stringer); ok {
		s = ss.String()
	} else {
		s = fmt.Sprintf("%+v", item)
	}
	return []byte(s), nil
}

// NewDataSource creates a DataSource for a given format-agnostic data source
// and a map of marshalers
func NewDataSource(
	src source.GenericDataSource,
	formats map[string]source.GenericDataFormat,
) *DataSource {
	if formats == nil {
		formats = make(map[string]source.GenericDataFormat)
	}

	// source-defined formats
	if fmtsrc, ok := src.(source.GenericDataSourceFormats); ok {
		fmts := fmtsrc.Formats()
		for name, fmt := range fmts {
			formats[name] = fmt
		}
	}

	// standard json protocol
	if formats["json"] == nil {
		formats["json"] = LDJSONMarshal
	}

	// convenience templated text protocol
	if formats["text"] == nil {
		if txtsrc, ok := src.(source.TextTemplatedSource); ok {
			if tt := txtsrc.TextTemplate(); tt != nil {
				formats["text"] = NewTemplatedMarshal(tt)
			}
		}
	}

	// default to just string-ing it
	if formats["text"] == nil {
		formats["text"] = source.GenericDataFormatFunc(stringIt)
	}

	ds := &DataSource{
		source:   src,
		formats:  formats,
		watchers: make(map[string]*marshaledWatcher, len(formats)),
		// TODO: tunable
		maxItems:   100,
		maxBatches: 100,
		maxWait:    100 * time.Microsecond,
	}
	ds.getSource, _ = src.(source.GetableDataSource)
	ds.watchSource, _ = src.(source.WatchableDataSource)
	ds.watiSource, _ = src.(source.WatchInitableDataSource)
	ds.actiSource, _ = src.(source.ActivateWatchableDataSource)
	for name, format := range formats {
		ds.formatNames = append(ds.formatNames, name)
		ds.watchers[name] = newMarshaledWatcher(ds, format)
	}
	sort.Strings(ds.formatNames)

	if ds.watchSource != nil {
		ds.watchSource.SetWatcher(ds)
	}

	return ds
}

// Active returns true if there are any active watchers, false otherwise.  If
// Active returns false, so will any calls to HandleItem and HandleItems.
func (mds *DataSource) Active() bool {
	mds.watchLock.RLock()
	r := mds.active && mds.itemChan != nil && mds.itemsChan != nil
	mds.watchLock.RUnlock()
	return r
}

// Name passes through the GenericDataSource.Name()
func (mds *DataSource) Name() string {
	return mds.source.Name()
}

// Formats returns the list of supported format names.
func (mds *DataSource) Formats() []string {
	return mds.formatNames
}

// Attrs returns arbitrary description information about the data source.
func (mds *DataSource) Attrs() map[string]interface{} {
	// TODO: support per-format Attrs?
	// TODO: any support for per-source Attrs?
	return nil
}

// Get marshals data source's Get data to the writer
func (mds *DataSource) Get(formatName string, w io.Writer) error {
	if mds.getSource == nil {
		return source.ErrNotGetable
	}
	format, ok := mds.formats[strings.ToLower(formatName)]
	if !ok {
		return source.ErrUnsupportedFormat
	}
	data := mds.getSource.Get()
	buf, err := format.MarshalGet(data)
	if err != nil {
		log.Printf("get marshaling error %v", err)
		return err
	}
	_, err = w.Write(buf)
	return err
}

// Watch marshals any data source GetInit data to the writer, and then
// retains a reference to the writer so that any future agnostic data source
// Watch(emit)'ed data gets marshaled to it as well
func (mds *DataSource) Watch(formatName string, w io.Writer) error {
	if mds.watchSource == nil {
		return source.ErrNotWatchable
	}

	mds.watchLock.Lock()
	acted := !mds.active
	err := func() error {
		defer mds.watchLock.Unlock()
		watcher, ok := mds.watchers[strings.ToLower(formatName)]
		if !ok {
			return source.ErrUnsupportedFormat
		}
		if err := watcher.init(w); err != nil {
			return err
		}
		if err := mds.startWatching(); err != nil {
			return err
		}
		return nil
	}()

	if err == nil && acted && mds.actiSource != nil {
		mds.actiSource.Activate()
	}
	return err
}

// WatchItems marshals any data source GetInit data as a single item to the
// ItemWatcher's HandleItem method.  The watcher is then retained and future
// items are marshaled to its HandleItem method.
func (mds *DataSource) WatchItems(formatName string, iw source.ItemWatcher) error {
	if mds.watchSource == nil {
		return source.ErrNotWatchable
	}

	mds.watchLock.Lock()
	acted := !mds.active
	err := func() error {
		defer mds.watchLock.Unlock()
		watcher, ok := mds.watchers[strings.ToLower(formatName)]
		if !ok {
			return source.ErrUnsupportedFormat
		}
		if err := watcher.initItems(iw); err != nil {
			return err
		}
		if err := mds.startWatching(); err != nil {
			return err
		}
		return nil
	}()

	if err == nil && acted && mds.actiSource != nil {
		mds.actiSource.Activate()
	}
	return err
}

// startWatching flips the active bit, creates new item channels, and starts a
// processing go routine; it assumes that the watchLock is being held by the
// caller.
func (mds *DataSource) startWatching() error {
	// TODO: we could optimize the only-one-format-being-watched case
	if mds.active {
		return nil
	}
	mds.active = true
	mds.itemChan = make(chan interface{}, mds.maxItems)
	mds.itemsChan = make(chan []interface{}, mds.maxBatches)
	mds.procs.Add(1)
	go mds.processItemChan(mds.itemChan, mds.itemsChan)
	return nil
}

// Drain closes the item channels, and waits for the item processor to finish.
// After drain, any remaining watchers are closed, and the source goes
// inactive.
func (mds *DataSource) Drain() {
	mds.watchLock.Lock()
	any := false
	if mds.itemChan != nil {
		close(mds.itemChan)
		any = true
		mds.itemChan = nil
	}
	if mds.itemsChan != nil {
		close(mds.itemsChan)
		any = true
		mds.itemsChan = nil
	}
	if any {
		mds.watchLock.Unlock()
		mds.procs.Wait()
		mds.watchLock.Lock()
	}
	stop := mds.active
	if stop {
		mds.active = false
	}
	mds.watchLock.Unlock()

	if stop {
		for _, watcher := range mds.watchers {
			watcher.Close()
		}
	}
}

func (mds *DataSource) processItemChan(itemChan chan interface{}, itemsChan chan []interface{}) {
	defer mds.procs.Done()

	stop := false

loop:
	for {
		mds.watchLock.RLock()
		active := mds.active
		watchers := mds.watchers
		mds.watchLock.RUnlock()
		if !active {
			break loop
		}
		select {
		case item, ok := <-itemChan:
			if !ok {
				itemChan = nil
				continue loop
			}
			any := false
			for _, watcher := range watchers {
				if watcher.emit(item) {
					any = true
				}
			}
			if !any {
				stop = true
				break loop
			}

		case items, ok := <-itemsChan:
			if !ok {
				itemsChan = nil
				continue loop
			}
			any := false
			for _, watcher := range watchers {
				if watcher.emitBatch(items) {
					any = true
				}
			}
			if !any {
				stop = true
				break loop
			}

		default:
			if itemChan == nil && itemsChan == nil {
				break loop
			}
		}
	}

	mds.watchLock.Lock()
	if mds.itemChan == itemChan {
		mds.itemChan = nil
	}
	if mds.itemsChan == itemsChan {
		mds.itemsChan = nil
	}
	if stop {
		mds.active = false
	}
	mds.watchLock.Unlock()

	if stop {
		for _, watcher := range mds.watchers {
			watcher.Close()
		}
	}
}

// HandleItem implements GenericDataWatcher.HandleItem by passing the item to
// all current marshaledWatchers.
func (mds *DataSource) HandleItem(item interface{}) bool {
	if !mds.Active() {
		return false
	}
	select {
	case mds.itemChan <- item:
		return true
	case <-time.After(mds.maxWait):
		mds.watchLock.Lock()
		if !mds.active {
			mds.watchLock.Unlock()
			return false
		}
		mds.active = false
		mds.watchLock.Unlock()
		for _, watcher := range mds.watchers {
			watcher.Close()
		}
		return false
	}
}

// HandleItems implements GenericDataWatcher.HandleItems by passing the batch
// to all current marshaledWatchers.
func (mds *DataSource) HandleItems(items []interface{}) bool {
	if !mds.Active() {
		return false
	}
	select {
	case mds.itemsChan <- items:
		return true
	case <-time.After(mds.maxWait):
		mds.watchLock.Lock()
		if !mds.active {
			mds.watchLock.Unlock()
			return false
		}
		mds.active = false
		mds.watchLock.Unlock()
		for _, watcher := range mds.watchers {
			watcher.Close()
		}
		return false
	}
}
<|endoftext|>