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

package fakestorage

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

	"cloud.google.com/go/storage"
	"github.com/fsouza/fake-gcs-server/internal/backend"
	"github.com/gorilla/mux"
	"google.golang.org/api/option"
)

// Server is the fake server.
//
// It provides a fake implementation of the Google Cloud Storage API.
type Server struct {
	backend   backend.Storage
	uploads   map[string]Object
	transport *http.Transport
	ts        *httptest.Server
	mux       *mux.Router
	mtx       sync.RWMutex
}

// NewServer creates a new instance of the server, pre-loaded with the given
// objects.
func NewServer(objects []Object) *Server {
	s, _ := NewServerWithOptions(Options{
		InitialObjects: objects,
	})
	return s
}

// NewServerWithHostPort creates a new server that listens on a custom host and port
func NewServerWithHostPort(objects []Object, host string, port uint16) (*Server, error) {
	return NewServerWithOptions(Options{
		InitialObjects: objects,
		Host:           host,
		Port:           port,
	})
}

// Options are used to configure the server on creation
type Options struct {
	InitialObjects []Object
	Host           string
	Port           uint16
	StorageRoot    string
}

// NewServerWithOptions creates a new server with custom options
func NewServerWithOptions(options Options) (*Server, error) {
	s, err := newUnstartedServer(options.InitialObjects, options.StorageRoot)
	if err != nil {
		return nil, err
	}
	var addr string
	if options.Port != 0 {
		addr = fmt.Sprintf("%s:%d", options.Host, options.Port)
		l, err := net.Listen("tcp", addr)
		if err != nil {
			return nil, err
		}
		s.ts.Listener.Close()
		s.ts.Listener = l
		s.ts.StartTLS()
		s.setTransportToAddr(addr)
	} else {
		s.setTransportToAddr(s.ts.Listener.Addr().String())
		s.ts.StartTLS()
	}
	return s, nil
}

func newUnstartedServer(objects []Object, storageRoot string) (*Server, error) {
	backendObjects := toBackendObjects(objects)
	var backendStorage backend.Storage
	var err error
	if storageRoot != "" {
		backendStorage, err = backend.NewStorageFS(backendObjects, storageRoot)
	} else {
		backendStorage = backend.NewStorageMemory(backendObjects)
	}
	if err != nil {
		return nil, err
	}
	s := Server{
		backend: backendStorage,
		uploads: make(map[string]Object),
	}
	s.buildMuxer()
	s.ts = httptest.NewUnstartedServer(s.mux)
	return &s, nil
}

func (s *Server) setTransportToAddr(addr string) {
	tlsConfig := tls.Config{InsecureSkipVerify: true}
	s.transport = &http.Transport{
		TLSClientConfig: &tlsConfig,
		DialTLS: func(string, string) (net.Conn, error) {
			return tls.Dial("tcp", addr, &tlsConfig)
		},
	}
}

func (s *Server) buildMuxer() {
	s.mux = mux.NewRouter()
	s.mux.Host("storage.googleapis.com").Path("/{bucketName}/{objectName:.+}").Methods("GET").HandlerFunc(s.downloadObject)
	r := s.mux.PathPrefix("/storage/v1").Subrouter()
	r.Path("/b").Methods("GET").HandlerFunc(s.listBuckets)
	r.Path("/b/{bucketName}").Methods("GET").HandlerFunc(s.getBucket)
	r.Path("/b/{bucketName}/o").Methods("GET").HandlerFunc(s.listObjects)
	r.Path("/b/{bucketName}/o").Methods("POST").HandlerFunc(s.insertObject)
	r.Path("/b/{bucketName}/o/{objectName:.+}").Methods("GET").HandlerFunc(s.getObject)
	r.Path("/b/{bucketName}/o/{objectName:.+}").Methods("DELETE").HandlerFunc(s.deleteObject)
	r.Path("/b/{sourceBucket}/o/{sourceObject:.+}/rewriteTo/b/{destinationBucket}/o/{destinationObject:.+}").HandlerFunc(s.rewriteObject)
	s.mux.Path("/upload/storage/v1/b/{bucketName}/o").Methods("POST").HandlerFunc(s.insertObject)
	s.mux.Path("/upload/resumable/{uploadId}").Methods("PUT", "POST").HandlerFunc(s.uploadFileContent)
}

// Stop stops the server, closing all connections.
func (s *Server) Stop() {
	s.transport.CloseIdleConnections()
	s.ts.Close()
}

// URL returns the server URL.
func (s *Server) URL() string {
	return s.ts.URL
}

// Client returns a GCS client configured to talk to the server.
func (s *Server) Client() *storage.Client {
	opt := option.WithHTTPClient(&http.Client{Transport: s.transport})
	client, _ := storage.NewClient(context.Background(), opt)
	return client
}
<commit_msg>fakestorage: add a method to get an HTTP client<commit_after>// Copyright 2017 Francisco Souza. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package fakestorage

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

	"cloud.google.com/go/storage"
	"github.com/fsouza/fake-gcs-server/internal/backend"
	"github.com/gorilla/mux"
	"google.golang.org/api/option"
)

// Server is the fake server.
//
// It provides a fake implementation of the Google Cloud Storage API.
type Server struct {
	backend   backend.Storage
	uploads   map[string]Object
	transport *http.Transport
	ts        *httptest.Server
	mux       *mux.Router
	mtx       sync.RWMutex
}

// NewServer creates a new instance of the server, pre-loaded with the given
// objects.
func NewServer(objects []Object) *Server {
	s, _ := NewServerWithOptions(Options{
		InitialObjects: objects,
	})
	return s
}

// NewServerWithHostPort creates a new server that listens on a custom host and port
func NewServerWithHostPort(objects []Object, host string, port uint16) (*Server, error) {
	return NewServerWithOptions(Options{
		InitialObjects: objects,
		Host:           host,
		Port:           port,
	})
}

// Options are used to configure the server on creation
type Options struct {
	InitialObjects []Object
	Host           string
	Port           uint16
	StorageRoot    string
}

// NewServerWithOptions creates a new server with custom options
func NewServerWithOptions(options Options) (*Server, error) {
	s, err := newUnstartedServer(options.InitialObjects, options.StorageRoot)
	if err != nil {
		return nil, err
	}
	var addr string
	if options.Port != 0 {
		addr = fmt.Sprintf("%s:%d", options.Host, options.Port)
		l, err := net.Listen("tcp", addr)
		if err != nil {
			return nil, err
		}
		s.ts.Listener.Close()
		s.ts.Listener = l
		s.ts.StartTLS()
		s.setTransportToAddr(addr)
	} else {
		s.setTransportToAddr(s.ts.Listener.Addr().String())
		s.ts.StartTLS()
	}
	return s, nil
}

func newUnstartedServer(objects []Object, storageRoot string) (*Server, error) {
	backendObjects := toBackendObjects(objects)
	var backendStorage backend.Storage
	var err error
	if storageRoot != "" {
		backendStorage, err = backend.NewStorageFS(backendObjects, storageRoot)
	} else {
		backendStorage = backend.NewStorageMemory(backendObjects)
	}
	if err != nil {
		return nil, err
	}
	s := Server{
		backend: backendStorage,
		uploads: make(map[string]Object),
	}
	s.buildMuxer()
	s.ts = httptest.NewUnstartedServer(s.mux)
	return &s, nil
}

func (s *Server) setTransportToAddr(addr string) {
	tlsConfig := tls.Config{InsecureSkipVerify: true}
	s.transport = &http.Transport{
		TLSClientConfig: &tlsConfig,
		DialTLS: func(string, string) (net.Conn, error) {
			return tls.Dial("tcp", addr, &tlsConfig)
		},
	}
}

func (s *Server) buildMuxer() {
	s.mux = mux.NewRouter()
	s.mux.Host("storage.googleapis.com").Path("/{bucketName}/{objectName:.+}").Methods("GET").HandlerFunc(s.downloadObject)
	r := s.mux.PathPrefix("/storage/v1").Subrouter()
	r.Path("/b").Methods("GET").HandlerFunc(s.listBuckets)
	r.Path("/b/{bucketName}").Methods("GET").HandlerFunc(s.getBucket)
	r.Path("/b/{bucketName}/o").Methods("GET").HandlerFunc(s.listObjects)
	r.Path("/b/{bucketName}/o").Methods("POST").HandlerFunc(s.insertObject)
	r.Path("/b/{bucketName}/o/{objectName:.+}").Methods("GET").HandlerFunc(s.getObject)
	r.Path("/b/{bucketName}/o/{objectName:.+}").Methods("DELETE").HandlerFunc(s.deleteObject)
	r.Path("/b/{sourceBucket}/o/{sourceObject:.+}/rewriteTo/b/{destinationBucket}/o/{destinationObject:.+}").HandlerFunc(s.rewriteObject)
	s.mux.Path("/upload/storage/v1/b/{bucketName}/o").Methods("POST").HandlerFunc(s.insertObject)
	s.mux.Path("/upload/resumable/{uploadId}").Methods("PUT", "POST").HandlerFunc(s.uploadFileContent)
}

// Stop stops the server, closing all connections.
func (s *Server) Stop() {
	s.transport.CloseIdleConnections()
	s.ts.Close()
}

// URL returns the server URL.
func (s *Server) URL() string {
	return s.ts.URL
}

// HTTPClient returns an HTTP client configured to talk to the server.
func (s *Server) HTTPClient() *http.Client {
	return &http.Client{Transport: s.transport}
}

// Client returns a GCS client configured to talk to the server.
func (s *Server) Client() *storage.Client {
	opt := option.WithHTTPClient(s.HTTPClient())
	client, _ := storage.NewClient(context.Background(), opt)
	return client
}
<|endoftext|>


<commit_before>package convert

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"strings"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestCIDR(t *testing.T) {
	checkHeader(
		t,
		cidrHeader,
		[]string{"network"},
	)

	v4net := "1.1.1.0/24"
	checkLine(
		t,
		cidrLine,
		v4net,
		[]string{v4net},
	)

	v6net := "2001:db8:85a3:42::/64"
	checkLine(
		t,
		cidrLine,
		v6net,
		[]string{v6net},
	)
}

func TestRange(t *testing.T) {
	checkHeader(
		t,
		rangeHeader,
		[]string{"network_start_ip", "network_last_ip"},
	)

	checkLine(
		t,
		rangeLine,
		"1.1.1.0/24",
		[]string{"1.1.1.0", "1.1.1.255"},
	)

	checkLine(
		t,
		rangeLine,
		"2001:0db8:85a3:0042::/64",
		[]string{"2001:db8:85a3:42::", "2001:db8:85a3:42:ffff:ffff:ffff:ffff"},
	)
}

func TestIntRange(t *testing.T) {
	checkHeader(
		t,
		intRangeHeader,
		[]string{"network_start_integer", "network_last_integer"},
	)

	checkLine(
		t,
		intRangeLine,
		"1.1.1.0/24",
		[]string{"16843008", "16843263"},
	)

	checkLine(
		t,
		intRangeLine,
		"2001:0db8:85a3:0042::/64",
		[]string{
			"42540766452641155289225172512357220352",
			"42540766452641155307671916586066771967",
		},
	)
}

func TestHexRange(t *testing.T) {
	checkHeader(
		t,
		hexRangeHeader,
		[]string{"network_start_hex", "network_last_hex"},
	)

	checkLine(
		t,
		hexRangeLine,
		"1.1.1.0/24",
		[]string{"1010100", "10101ff"},
	)

	checkLine(
		t,
		hexRangeLine,
		"2001:0db8:85a3:0042::/64",
		[]string{
			"20010db885a300420000000000000000",
			"20010db885a30042ffffffffffffffff",
		},
	)
}

func checkHeader(
	t *testing.T,
	makeHeader headerFunc,
	expected []string) {
	suffix := []string{"city", "country"}
	assert.Equal(
		t,
		append(expected, suffix...),
		makeHeader(suffix),
	)
}

func checkLine(
	t *testing.T,
	makeLine lineFunc,
	network string,
	expected []string) {
	p, err := makePrefix(network)
	if err != nil {
		t.Fatal(err)
	}

	suffix := []string{"1", "2"}
	assert.Equal(
		t,
		append(expected, suffix...),
		makeLine(p, suffix),
	)
}

func TestCIDROutput(t *testing.T) {
	checkOutput(
		t,
		"CIDR only",
		true,
		false,
		false,
		false,
		[]interface{}{
			"network",
			"1.0.0.0/24",
			"4.69.140.16/29",
			"5.61.192.0/21",
			"2001:4220::/32",
			"2402:d000::/32",
			"2406:4000::/32",
		},
	)
}

func TestRangeOutput(t *testing.T) {
	checkOutput(
		t,
		"range only",
		false,
		true,
		false,
		false,
		[]interface{}{
			"network_start_ip,network_last_ip",
			"1.0.0.0,1.0.0.255",
			"4.69.140.16,4.69.140.23",
			"5.61.192.0,5.61.199.255",
			"2001:4220::,2001:4220:ffff:ffff:ffff:ffff:ffff:ffff",
			"2402:d000::,2402:d000:ffff:ffff:ffff:ffff:ffff:ffff",
			"2406:4000::,2406:4000:ffff:ffff:ffff:ffff:ffff:ffff",
		},
	)
}

func TestIntRangeOutput(t *testing.T) {
	checkOutput(
		t,
		"integer range only",
		false,
		false,
		true,
		false,
		[]interface{}{
			"network_start_integer,network_last_integer",
			"16777216,16777471",
			"71666704,71666711",
			"87932928,87934975",
			"42541829336310884227257139937291534336,42541829415539046741521477530835484671",
			"47866811183171600627242296191018336256,47866811262399763141506633784562286591",
			"47884659703622814097215369772150030336,47884659782850976611479707365693980671",
		},
	)
}

func TestHexRangeOutput(t *testing.T) {
	checkOutput(
		t,
		"hex range only",
		false,
		false,
		false,
		true,
		[]interface{}{
			"network_start_hex,network_last_hex",
			"1000000,10000ff",
			"4458c10,4458c17",
			"53dc000,53dc7ff",
			"20014220000000000000000000000000,20014220ffffffffffffffffffffffff",
			"2402d000000000000000000000000000,2402d000ffffffffffffffffffffffff",
			"24064000000000000000000000000000,24064000ffffffffffffffffffffffff",
		},
	)
}

func TestAllOutput(t *testing.T) {
	checkOutput(
		t,
		"all output options",
		true,
		true,
		true,
		true,
		[]interface{}{
			// nolint: lll
			"network,network_start_ip,network_last_ip,network_start_integer,network_last_integer,network_start_hex,network_last_hex",
			"1.0.0.0/24,1.0.0.0,1.0.0.255,16777216,16777471,1000000,10000ff",
			"4.69.140.16/29,4.69.140.16,4.69.140.23,71666704,71666711,4458c10,4458c17",
			"5.61.192.0/21,5.61.192.0,5.61.199.255,87932928,87934975,53dc000,53dc7ff",
			// nolint: lll
			"2001:4220::/32,2001:4220::,2001:4220:ffff:ffff:ffff:ffff:ffff:ffff,42541829336310884227257139937291534336,42541829415539046741521477530835484671,20014220000000000000000000000000,20014220ffffffffffffffffffffffff",
			// nolint: lll
			"2402:d000::/32,2402:d000::,2402:d000:ffff:ffff:ffff:ffff:ffff:ffff,47866811183171600627242296191018336256,47866811262399763141506633784562286591,2402d000000000000000000000000000,2402d000ffffffffffffffffffffffff",
			// nolint: lll
			"2406:4000::/32,2406:4000::,2406:4000:ffff:ffff:ffff:ffff:ffff:ffff,47884659703622814097215369772150030336,47884659782850976611479707365693980671,24064000000000000000000000000000,24064000ffffffffffffffffffffffff",
		},
	)
}

func checkOutput(
	t *testing.T,
	name string,
	cidr bool,
	ipRange bool,
	intRange bool,
	hexRange bool,
	expected []interface{},
) {
	// nolint: lll
	input := `network,geoname_id,registered_country_geoname_id,represented_country_geoname_id,is_anonymous_proxy,is_satellite_provider
1.0.0.0/24,2077456,2077456,,0,0
4.69.140.16/29,6252001,6252001,,0,0
5.61.192.0/21,2635167,2635167,,0,0
2001:4220::/32,357994,357994,,0,0
2402:d000::/32,1227603,1227603,,0,0
2406:4000::/32,1835841,1835841,,0,0
`
	var outbuf bytes.Buffer

	err := Convert(strings.NewReader(input), &outbuf, cidr, ipRange, intRange, hexRange)
	if err != nil {
		t.Fatal(err)
	}

	// This is a regexp as Go 1.4 does not quote empty fields while earlier
	// versions do
	// nolint: lll
	outTMPL := `%s,geoname_id,registered_country_geoname_id,represented_country_geoname_id,is_anonymous_proxy,is_satellite_provider
%s,2077456,2077456,(?:"")?,0,0
%s,6252001,6252001,(?:"")?,0,0
%s,2635167,2635167,(?:"")?,0,0
%s,357994,357994,(?:"")?,0,0
%s,1227603,1227603,(?:"")?,0,0
%s,1835841,1835841,(?:"")?,0,0
`

	assert.Regexp(
		t,
		fmt.Sprintf(outTMPL, expected...),
		outbuf.String(),
		name,
	)
}

func TestFileWriting(t *testing.T) {
	input := `network,something
1.0.0.0/24,"some more"
`

	// nolint: lll
	expected := `network,network_start_ip,network_last_ip,network_start_integer,network_last_integer,network_start_hex,network_last_hex,something
1.0.0.0/24,1.0.0.0,1.0.0.255,16777216,16777471,1000000,10000ff,some more
`

	inFile, err := ioutil.TempFile("", "input")
	if err != nil {
		t.Fatal(err)
	}
	defer inFile.Close() // nolint: gosec

	outFile, err := ioutil.TempFile("", "output")
	if err != nil {
		t.Fatal(err)
	}
	defer outFile.Close() // nolint: gosec

	_, err = inFile.WriteString(input)
	require.NoError(t, err)

	err = ConvertFile(inFile.Name(), outFile.Name(), true, true, true, true)
	if err != nil {
		t.Fatal(err)
	}

	buf := bytes.NewBuffer(nil)
	_, err = io.Copy(buf, outFile)
	require.NoError(t, err)

	assert.Equal(t, expected, buf.String())
}
<commit_msg>Fix lints<commit_after>package convert

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"strings"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestCIDR(t *testing.T) {
	checkHeader(
		t,
		cidrHeader,
		[]string{"network"},
	)

	v4net := "1.1.1.0/24"
	checkLine(
		t,
		cidrLine,
		v4net,
		[]string{v4net},
	)

	v6net := "2001:db8:85a3:42::/64"
	checkLine(
		t,
		cidrLine,
		v6net,
		[]string{v6net},
	)
}

func TestRange(t *testing.T) {
	checkHeader(
		t,
		rangeHeader,
		[]string{"network_start_ip", "network_last_ip"},
	)

	checkLine(
		t,
		rangeLine,
		"1.1.1.0/24",
		[]string{"1.1.1.0", "1.1.1.255"},
	)

	checkLine(
		t,
		rangeLine,
		"2001:0db8:85a3:0042::/64",
		[]string{"2001:db8:85a3:42::", "2001:db8:85a3:42:ffff:ffff:ffff:ffff"},
	)
}

func TestIntRange(t *testing.T) {
	checkHeader(
		t,
		intRangeHeader,
		[]string{"network_start_integer", "network_last_integer"},
	)

	checkLine(
		t,
		intRangeLine,
		"1.1.1.0/24",
		[]string{"16843008", "16843263"},
	)

	checkLine(
		t,
		intRangeLine,
		"2001:0db8:85a3:0042::/64",
		[]string{
			"42540766452641155289225172512357220352",
			"42540766452641155307671916586066771967",
		},
	)
}

func TestHexRange(t *testing.T) {
	checkHeader(
		t,
		hexRangeHeader,
		[]string{"network_start_hex", "network_last_hex"},
	)

	checkLine(
		t,
		hexRangeLine,
		"1.1.1.0/24",
		[]string{"1010100", "10101ff"},
	)

	checkLine(
		t,
		hexRangeLine,
		"2001:0db8:85a3:0042::/64",
		[]string{
			"20010db885a300420000000000000000",
			"20010db885a30042ffffffffffffffff",
		},
	)
}

func checkHeader(
	t *testing.T,
	makeHeader headerFunc,
	expected []string,
) {
	suffix := []string{"city", "country"}
	assert.Equal(
		t,
		append(expected, suffix...),
		makeHeader(suffix),
	)
}

func checkLine(
	t *testing.T,
	makeLine lineFunc,
	network string,
	expected []string,
) {
	p, err := makePrefix(network)
	if err != nil {
		t.Fatal(err)
	}

	suffix := []string{"1", "2"}
	assert.Equal(
		t,
		append(expected, suffix...),
		makeLine(p, suffix),
	)
}

func TestCIDROutput(t *testing.T) {
	checkOutput(
		t,
		"CIDR only",
		true,
		false,
		false,
		false,
		[]interface{}{
			"network",
			"1.0.0.0/24",
			"4.69.140.16/29",
			"5.61.192.0/21",
			"2001:4220::/32",
			"2402:d000::/32",
			"2406:4000::/32",
		},
	)
}

func TestRangeOutput(t *testing.T) {
	checkOutput(
		t,
		"range only",
		false,
		true,
		false,
		false,
		[]interface{}{
			"network_start_ip,network_last_ip",
			"1.0.0.0,1.0.0.255",
			"4.69.140.16,4.69.140.23",
			"5.61.192.0,5.61.199.255",
			"2001:4220::,2001:4220:ffff:ffff:ffff:ffff:ffff:ffff",
			"2402:d000::,2402:d000:ffff:ffff:ffff:ffff:ffff:ffff",
			"2406:4000::,2406:4000:ffff:ffff:ffff:ffff:ffff:ffff",
		},
	)
}

func TestIntRangeOutput(t *testing.T) {
	checkOutput(
		t,
		"integer range only",
		false,
		false,
		true,
		false,
		[]interface{}{
			"network_start_integer,network_last_integer",
			"16777216,16777471",
			"71666704,71666711",
			"87932928,87934975",
			"42541829336310884227257139937291534336,42541829415539046741521477530835484671",
			"47866811183171600627242296191018336256,47866811262399763141506633784562286591",
			"47884659703622814097215369772150030336,47884659782850976611479707365693980671",
		},
	)
}

func TestHexRangeOutput(t *testing.T) {
	checkOutput(
		t,
		"hex range only",
		false,
		false,
		false,
		true,
		[]interface{}{
			"network_start_hex,network_last_hex",
			"1000000,10000ff",
			"4458c10,4458c17",
			"53dc000,53dc7ff",
			"20014220000000000000000000000000,20014220ffffffffffffffffffffffff",
			"2402d000000000000000000000000000,2402d000ffffffffffffffffffffffff",
			"24064000000000000000000000000000,24064000ffffffffffffffffffffffff",
		},
	)
}

func TestAllOutput(t *testing.T) {
	checkOutput(
		t,
		"all output options",
		true,
		true,
		true,
		true,
		[]interface{}{
			// nolint: lll
			"network,network_start_ip,network_last_ip,network_start_integer,network_last_integer,network_start_hex,network_last_hex",
			"1.0.0.0/24,1.0.0.0,1.0.0.255,16777216,16777471,1000000,10000ff",
			"4.69.140.16/29,4.69.140.16,4.69.140.23,71666704,71666711,4458c10,4458c17",
			"5.61.192.0/21,5.61.192.0,5.61.199.255,87932928,87934975,53dc000,53dc7ff",
			// nolint: lll
			"2001:4220::/32,2001:4220::,2001:4220:ffff:ffff:ffff:ffff:ffff:ffff,42541829336310884227257139937291534336,42541829415539046741521477530835484671,20014220000000000000000000000000,20014220ffffffffffffffffffffffff",
			// nolint: lll
			"2402:d000::/32,2402:d000::,2402:d000:ffff:ffff:ffff:ffff:ffff:ffff,47866811183171600627242296191018336256,47866811262399763141506633784562286591,2402d000000000000000000000000000,2402d000ffffffffffffffffffffffff",
			// nolint: lll
			"2406:4000::/32,2406:4000::,2406:4000:ffff:ffff:ffff:ffff:ffff:ffff,47884659703622814097215369772150030336,47884659782850976611479707365693980671,24064000000000000000000000000000,24064000ffffffffffffffffffffffff",
		},
	)
}

func checkOutput(
	t *testing.T,
	name string,
	cidr bool,
	ipRange bool,
	intRange bool,
	hexRange bool,
	expected []interface{},
) {
	// nolint: lll
	input := `network,geoname_id,registered_country_geoname_id,represented_country_geoname_id,is_anonymous_proxy,is_satellite_provider
1.0.0.0/24,2077456,2077456,,0,0
4.69.140.16/29,6252001,6252001,,0,0
5.61.192.0/21,2635167,2635167,,0,0
2001:4220::/32,357994,357994,,0,0
2402:d000::/32,1227603,1227603,,0,0
2406:4000::/32,1835841,1835841,,0,0
`
	var outbuf bytes.Buffer

	err := Convert(strings.NewReader(input), &outbuf, cidr, ipRange, intRange, hexRange)
	if err != nil {
		t.Fatal(err)
	}

	// This is a regexp as Go 1.4 does not quote empty fields while earlier
	// versions do
	// nolint: lll
	outTMPL := `%s,geoname_id,registered_country_geoname_id,represented_country_geoname_id,is_anonymous_proxy,is_satellite_provider
%s,2077456,2077456,(?:"")?,0,0
%s,6252001,6252001,(?:"")?,0,0
%s,2635167,2635167,(?:"")?,0,0
%s,357994,357994,(?:"")?,0,0
%s,1227603,1227603,(?:"")?,0,0
%s,1835841,1835841,(?:"")?,0,0
`

	assert.Regexp(
		t,
		fmt.Sprintf(outTMPL, expected...),
		outbuf.String(),
		name,
	)
}

func TestFileWriting(t *testing.T) {
	input := `network,something
1.0.0.0/24,"some more"
`

	// nolint: lll
	expected := `network,network_start_ip,network_last_ip,network_start_integer,network_last_integer,network_start_hex,network_last_hex,something
1.0.0.0/24,1.0.0.0,1.0.0.255,16777216,16777471,1000000,10000ff,some more
`

	inFile, err := ioutil.TempFile("", "input")
	if err != nil {
		t.Fatal(err)
	}
	defer inFile.Close() // nolint: gosec

	outFile, err := ioutil.TempFile("", "output")
	if err != nil {
		t.Fatal(err)
	}
	defer outFile.Close() // nolint: gosec

	_, err = inFile.WriteString(input)
	require.NoError(t, err)

	err = ConvertFile(inFile.Name(), outFile.Name(), true, true, true, true)
	if err != nil {
		t.Fatal(err)
	}

	buf := bytes.NewBuffer(nil)
	_, err = io.Copy(buf, outFile)
	require.NoError(t, err)

	assert.Equal(t, expected, buf.String())
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Jetstack cert-manager contributors.

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 generate

import (
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
)

type CertificateConfig struct {
	// metadata
	Name, Namespace string

	// common parameters
	IssuerName, IssuerKind string
	SecretName             string
	CommonName             string
	DNSNames               []string

	// ACME parameters
	SolverConfig v1alpha1.SolverConfig
	ACMEOrderURL string
}

func Certificate(cfg CertificateConfig) *v1alpha1.Certificate {
	return &v1alpha1.Certificate{
		ObjectMeta: metav1.ObjectMeta{
			Name:      cfg.Name,
			Namespace: cfg.Namespace,
		},
		Spec: v1alpha1.CertificateSpec{
			SecretName: cfg.SecretName,
			IssuerRef: v1alpha1.ObjectReference{
				Name: cfg.IssuerName,
				Kind: cfg.IssuerKind,
			},
			CommonName: cfg.CommonName,
			DNSNames:   cfg.DNSNames,
			ACME: &v1alpha1.ACMECertificateConfig{
				Config: []v1alpha1.DomainSolverConfig{
					{
						Domains:      cfg.DNSNames,
						SolverConfig: cfg.SolverConfig,
					},
				},
			},
		},
		Status: v1alpha1.CertificateStatus{
			ACME: &v1alpha1.CertificateACMEStatus{
				Order: v1alpha1.ACMEOrderStatus{
					URL: cfg.ACMEOrderURL,
				},
			},
		},
	}
}
<commit_msg>Update Certificate generate function for new API type<commit_after>/*
Copyright 2018 The Jetstack cert-manager contributors.

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 generate

import (
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
)

type CertificateConfig struct {
	// metadata
	Name, Namespace string

	// common parameters
	IssuerName, IssuerKind string
	SecretName             string
	CommonName             string
	DNSNames               []string

	// ACME parameters
	SolverConfig v1alpha1.SolverConfig
	ACMEOrderURL string
}

func Certificate(cfg CertificateConfig) *v1alpha1.Certificate {
	return &v1alpha1.Certificate{
		ObjectMeta: metav1.ObjectMeta{
			Name:      cfg.Name,
			Namespace: cfg.Namespace,
		},
		Spec: v1alpha1.CertificateSpec{
			SecretName: cfg.SecretName,
			IssuerRef: v1alpha1.ObjectReference{
				Name: cfg.IssuerName,
				Kind: cfg.IssuerKind,
			},
			CommonName: cfg.CommonName,
			DNSNames:   cfg.DNSNames,
			ACME: &v1alpha1.ACMECertificateConfig{
				Config: []v1alpha1.DomainSolverConfig{
					{
						Domains:      cfg.DNSNames,
						SolverConfig: cfg.SolverConfig,
					},
				},
			},
		},
		Status: v1alpha1.CertificateStatus{
			ACME: &v1alpha1.CertificateACMEStatus{
				OrderRef: &v1alpha1.LocalObjectReference{
					Name: "",
				},
			},
		},
	}
}
<|endoftext|>


<commit_before>package tests

import (
	"fmt"
	"testing"
	"time"

	"github.com/deis/deis/tests/dockercliutils"
	"github.com/deis/deis/tests/etcdutils"
	"github.com/deis/deis/tests/mockserviceutils"
	"github.com/deis/deis/tests/utils"
)

func runDeisControllerTest(t *testing.T, testSessionUID string, etcdPort string, servicePort string) {
	cli, stdout, stdoutPipe := dockercliutils.GetNewClient()
	done := make(chan bool, 1)
	err := dockercliutils.BuildImage(t, "../", "deis/controller:"+testSessionUID)
	if err != nil {
		t.Fatal(err)
	}
	ipaddr := utils.GetHostIPAddress()
	done <- true
	go func() {
		<-done
		err = dockercliutils.RunContainer(cli,
			"--name", "deis-controller-"+testSessionUID,
			"--rm",
			"-p", servicePort+":8000",
			"-e", "PUBLISH="+servicePort,
			"-e", "HOST="+ipaddr,
			"-e", "ETCD_PORT="+etcdPort,
			"deis/controller:"+testSessionUID)
	}()
	time.Sleep(5000 * time.Millisecond)
	dockercliutils.PrintToStdout(t, stdout, stdoutPipe, "Booting")
	if err != nil {
		t.Fatal(err)
	}
}

func TestController(t *testing.T) {
	setkeys := []string{"/deis/registry/protocol",
		"deis/registry/host",
		"/deis/registry/port",
		"/deis/cache/host",
		"/deis/cache/port"}
	setdir := []string{"/deis/controller",
		"/deis/cache",
		"/deis/database",
		"/deis/registry",
		"/deis/domains"}
	var testSessionUID = utils.NewUuid()
	fmt.Println("UUID for the session Controller Test :" + testSessionUID)
	etcdPort := utils.GetRandomPort()
	servicePort := utils.GetRandomPort()
	dbPort := utils.GetRandomPort()
	dockercliutils.RunEtcdTest(t, testSessionUID, etcdPort)
	fmt.Println("starting controller test:")
	Controllerhandler := etcdutils.InitetcdValues(setdir, setkeys, etcdPort)
	etcdutils.Publishvalues(t, Controllerhandler)
	mockserviceutils.RunMockDatabase(t, testSessionUID, etcdPort, dbPort)
	fmt.Println("starting Controller component test")
	runDeisControllerTest(t, testSessionUID, etcdPort, servicePort)
	dockercliutils.DeisServiceTest(
		t, "deis-controller-"+testSessionUID, servicePort, "http")
	dockercliutils.ClearTestSession(t, testSessionUID)
}
<commit_msg>fix(tests): build docker image as first test step<commit_after>package tests

import (
	"fmt"
	"testing"
	"time"

	"github.com/deis/deis/tests/dockercliutils"
	"github.com/deis/deis/tests/etcdutils"
	"github.com/deis/deis/tests/mockserviceutils"
	"github.com/deis/deis/tests/utils"
)

func runDeisControllerTest(t *testing.T, testSessionUID string, etcdPort string, servicePort string) {
	var err error
	cli, stdout, stdoutPipe := dockercliutils.GetNewClient()
	done := make(chan bool, 1)
	ipaddr := utils.GetHostIPAddress()
	done <- true
	go func() {
		<-done
		err = dockercliutils.RunContainer(cli,
			"--name", "deis-controller-"+testSessionUID,
			"--rm",
			"-p", servicePort+":8000",
			"-e", "PUBLISH="+servicePort,
			"-e", "HOST="+ipaddr,
			"-e", "ETCD_PORT="+etcdPort,
			"deis/controller:"+testSessionUID)
	}()
	time.Sleep(5000 * time.Millisecond)
	dockercliutils.PrintToStdout(t, stdout, stdoutPipe, "Booting")
	if err != nil {
		t.Fatal(err)
	}
}

func TestController(t *testing.T) {
	setkeys := []string{
		"/deis/registry/protocol",
		"deis/registry/host",
		"/deis/registry/port",
		"/deis/cache/host",
		"/deis/cache/port",
	}
	setdir := []string{
		"/deis/controller",
		"/deis/cache",
		"/deis/database",
		"/deis/registry",
		"/deis/domains",
	}
	testSessionUID := utils.NewUuid()
	err := dockercliutils.BuildImage(t, "../", "deis/controller:"+testSessionUID)
	if err != nil {
		t.Fatal(err)
	}
	etcdPort := utils.GetRandomPort()
	servicePort := utils.GetRandomPort()
	dbPort := utils.GetRandomPort()
	dockercliutils.RunEtcdTest(t, testSessionUID, etcdPort)
	fmt.Println("starting controller test:")
	Controllerhandler := etcdutils.InitetcdValues(setdir, setkeys, etcdPort)
	etcdutils.Publishvalues(t, Controllerhandler)
	mockserviceutils.RunMockDatabase(t, testSessionUID, etcdPort, dbPort)
	fmt.Println("starting Controller component test")
	runDeisControllerTest(t, testSessionUID, etcdPort, servicePort)
	dockercliutils.DeisServiceTest(
		t, "deis-controller-"+testSessionUID, servicePort, "http")
	dockercliutils.ClearTestSession(t, testSessionUID)
}
<|endoftext|>


<commit_before>package movingmedian

import (
	"container/heap"
	"math"
)

type elt struct {
	f   float64
	idx int
}

type float64Heap []*elt

func (h float64Heap) Len() int { return len(h) }
func (h float64Heap) Swap(i, j int) {
	h[i], h[j] = h[j], h[i]
	h[i].idx = i
	h[j].idx = j
}

func (h *float64Heap) Push(x interface{}) {
	e := x.(*elt)
	e.idx = len(*h)
	*h = append(*h, e)
}

func (h *float64Heap) Pop() interface{} {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[0 : n-1]
	return x
}

type minFloat64Heap struct {
	float64Heap
}

func (h minFloat64Heap) Less(i, j int) bool { return h.float64Heap[i].f < h.float64Heap[j].f }

type maxFloat64Heap struct {
	float64Heap
}

func (h maxFloat64Heap) Less(i, j int) bool { return h.float64Heap[i].f > h.float64Heap[j].f }

type MovingMedian struct {
	idx     int
	nelts   int
	queue   []elt
	maxHeap maxFloat64Heap
	minHeap minFloat64Heap
}

func NewMovingMedian(size int) MovingMedian {
	m := MovingMedian{
		queue:   make([]elt, size),
		maxHeap: maxFloat64Heap{},
		minHeap: minFloat64Heap{},
	}

	heap.Init(&m.maxHeap)
	heap.Init(&m.minHeap)
	return m
}

func (m *MovingMedian) Push(v float64) {

	if m.nelts >= len(m.queue) {
		old := &m.queue[m.idx]

		if len(m.queue) == 1 || old.f > m.minHeap.float64Heap[0].f {
			heap.Remove(&m.minHeap, old.idx)
		} else {
			heap.Remove(&m.maxHeap, old.idx)
		}
	}

	m.queue[m.idx] = elt{f: v}
	e := &m.queue[m.idx]

	m.nelts++
	m.idx++

	if m.idx >= len(m.queue) {
		m.idx = 0
	}

	if m.minHeap.Len() == 0 ||
		v > m.minHeap.float64Heap[0].f {
		heap.Push(&m.minHeap, e)
	} else {
		heap.Push(&m.maxHeap, e)
	}

	if m.maxHeap.Len() > (m.minHeap.Len() + 1) {
		moveItem := heap.Pop(&m.maxHeap)
		heap.Push(&m.minHeap, moveItem)
	} else if m.minHeap.Len() > (m.maxHeap.Len() + 1) {
		moveItem := heap.Pop(&m.minHeap)
		heap.Push(&m.maxHeap, moveItem)
	}
}

func (m *MovingMedian) Median() float64 {
	if len(m.queue) == 0 {
		return math.NaN()
	}

	wsize := m.nelts
	if m.nelts > len(m.queue) {
		wsize = len(m.queue)
	}

	if (wsize % 2) == 0 {
		return (m.maxHeap.float64Heap[0].f + m.minHeap.float64Heap[0].f) / 2
	}

	if m.maxHeap.Len() > m.minHeap.Len() {
		return m.maxHeap.float64Heap[0].f
	}

	return m.minHeap.float64Heap[0].f
}
<commit_msg>properly remove element from the correct heap<commit_after>package movingmedian

import (
	"container/heap"
	"math"
)

type elt struct {
	f   float64
	idx int
}

type float64Heap []*elt

func (h float64Heap) Len() int { return len(h) }
func (h float64Heap) Swap(i, j int) {
	h[i], h[j] = h[j], h[i]
	h[i].idx = i
	h[j].idx = j
}

func (h *float64Heap) Push(x interface{}) {
	e := x.(*elt)
	e.idx = len(*h)
	*h = append(*h, e)
}

func (h *float64Heap) Pop() interface{} {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[0 : n-1]
	return x
}

type minFloat64Heap struct {
	float64Heap
}

func (h minFloat64Heap) Less(i, j int) bool { return h.float64Heap[i].f < h.float64Heap[j].f }

type maxFloat64Heap struct {
	float64Heap
}

func (h maxFloat64Heap) Less(i, j int) bool { return h.float64Heap[i].f > h.float64Heap[j].f }

type MovingMedian struct {
	idx     int
	nelts   int
	queue   []elt
	maxHeap maxFloat64Heap
	minHeap minFloat64Heap
}

func NewMovingMedian(size int) MovingMedian {
	m := MovingMedian{
		queue:   make([]elt, size),
		maxHeap: maxFloat64Heap{},
		minHeap: minFloat64Heap{},
	}

	heap.Init(&m.maxHeap)
	heap.Init(&m.minHeap)
	return m
}

func (m *MovingMedian) balanceHeaps() {
	if m.maxHeap.Len() > (m.minHeap.Len() + 1) {
		moveItem := heap.Pop(&m.maxHeap)
		heap.Push(&m.minHeap, moveItem)
	} else if m.minHeap.Len() > (m.maxHeap.Len() + 1) {
		moveItem := heap.Pop(&m.minHeap)
		heap.Push(&m.maxHeap, moveItem)
	}

}

func (m *MovingMedian) Push(v float64) {

	if m.nelts >= len(m.queue) {
		old := &m.queue[m.idx]

		if old.idx < m.minHeap.Len() && old == m.minHeap.float64Heap[old.idx] {
			heap.Remove(&m.minHeap, old.idx)
		} else {
			heap.Remove(&m.maxHeap, old.idx)
		}

		m.balanceHeaps()
	}

	m.queue[m.idx] = elt{f: v}
	e := &m.queue[m.idx]

	m.nelts++
	m.idx++

	if m.idx >= len(m.queue) {
		m.idx = 0
	}

	if m.minHeap.Len() == 0 ||
		v > m.minHeap.float64Heap[0].f {
		heap.Push(&m.minHeap, e)
	} else {
		heap.Push(&m.maxHeap, e)
	}

	m.balanceHeaps()
}

func (m *MovingMedian) Median() float64 {
	if len(m.queue) == 0 {
		return math.NaN()
	}

	wsize := m.nelts
	if m.nelts > len(m.queue) {
		wsize = len(m.queue)
	}

	if (wsize % 2) == 0 {
		return (m.maxHeap.float64Heap[0].f + m.minHeap.float64Heap[0].f) / 2
	}

	if m.maxHeap.Len() > m.minHeap.Len() {
		return m.maxHeap.float64Heap[0].f
	}

	return m.minHeap.float64Heap[0].f
}
<|endoftext|>


<commit_before>package cli

import (
	flag "github.com/docker/docker/pkg/mflag"
	"github.com/docker/go-connections/tlsconfig"
)

// CommonFlags represents flags that are common to both the client and the daemon.
type CommonFlags struct {
	FlagSet   *flag.FlagSet
	PostParse func()

	Debug      bool
	Hosts      []string
	LogLevel   string
	TLS        bool
	TLSVerify  bool
	TLSOptions *tlsconfig.Options
	TrustKey   string
}

// Command is the struct contains command name and description
type Command struct {
	Name        string
	Description string
}

var dockerCommands = []Command{
	{"attach", "Attach to a running container"},
	{"build", "Build an image from a Dockerfile"},
	{"commit", "Create a new image from a container's changes"},
	{"cp", "Copy files/folders between a container and the local filesystem"},
	{"create", "Create a new container"},
	{"diff", "Inspect changes on a container's filesystem"},
	{"events", "Get real time events from the server"},
	{"exec", "Run a command in a running container"},
	{"export", "Export a container's filesystem as a tar archive"},
	{"history", "Show the history of an image"},
	{"images", "List images"},
	{"import", "Import the contents from a tarball to create a filesystem image"},
	{"info", "Display system-wide information"},
	{"inspect", "Return low-level information on a container or image"},
	{"kill", "Kill a running container"},
	{"load", "Load an image from a tar archive or STDIN"},
	{"login", "Register or log in to a Docker registry"},
	{"logout", "Log out from a Docker registry"},
	{"logs", "Fetch the logs of a container"},
	{"network", "Manage Docker networks"},
	{"pause", "Pause all processes within a container"},
	{"port", "List port mappings or a specific mapping for the CONTAINER"},
	{"ps", "List containers"},
	{"pull", "Pull an image or a repository from a registry"},
	{"push", "Push an image or a repository to a registry"},
	{"rename", "Rename a container"},
	{"restart", "Restart a container"},
	{"rm", "Remove one or more containers"},
	{"rmi", "Remove one or more images"},
	{"run", "Run a command in a new container"},
	{"save", "Save an image(s) to a tar archive"},
	{"search", "Search the Docker Hub for images"},
	{"start", "Start one or more stopped containers"},
	{"stats", "Display a live stream of container(s) resource usage statistics"},
	{"stop", "Stop a running container"},
	{"tag", "Tag an image into a repository"},
	{"top", "Display the running processes of a container"},
	{"unpause", "Unpause all processes within a container"},
	{"update", "Update resources of one or more containers"},
	{"version", "Show the Docker version information"},
	{"volume", "Manage Docker volumes"},
	{"wait", "Block until a container stops, then print its exit code"},
}

// DockerCommands stores all the docker command
var DockerCommands = make(map[string]Command)

func init() {
	for _, cmd := range dockerCommands {
		DockerCommands[cmd.Name] = cmd
	}
}
<commit_msg>fix grammar error<commit_after>package cli

import (
	flag "github.com/docker/docker/pkg/mflag"
	"github.com/docker/go-connections/tlsconfig"
)

// CommonFlags represents flags that are common to both the client and the daemon.
type CommonFlags struct {
	FlagSet   *flag.FlagSet
	PostParse func()

	Debug      bool
	Hosts      []string
	LogLevel   string
	TLS        bool
	TLSVerify  bool
	TLSOptions *tlsconfig.Options
	TrustKey   string
}

// Command is the struct containing the command name and description
type Command struct {
	Name        string
	Description string
}

var dockerCommands = []Command{
	{"attach", "Attach to a running container"},
	{"build", "Build an image from a Dockerfile"},
	{"commit", "Create a new image from a container's changes"},
	{"cp", "Copy files/folders between a container and the local filesystem"},
	{"create", "Create a new container"},
	{"diff", "Inspect changes on a container's filesystem"},
	{"events", "Get real time events from the server"},
	{"exec", "Run a command in a running container"},
	{"export", "Export a container's filesystem as a tar archive"},
	{"history", "Show the history of an image"},
	{"images", "List images"},
	{"import", "Import the contents from a tarball to create a filesystem image"},
	{"info", "Display system-wide information"},
	{"inspect", "Return low-level information on a container or image"},
	{"kill", "Kill a running container"},
	{"load", "Load an image from a tar archive or STDIN"},
	{"login", "Register or log in to a Docker registry"},
	{"logout", "Log out from a Docker registry"},
	{"logs", "Fetch the logs of a container"},
	{"network", "Manage Docker networks"},
	{"pause", "Pause all processes within a container"},
	{"port", "List port mappings or a specific mapping for the CONTAINER"},
	{"ps", "List containers"},
	{"pull", "Pull an image or a repository from a registry"},
	{"push", "Push an image or a repository to a registry"},
	{"rename", "Rename a container"},
	{"restart", "Restart a container"},
	{"rm", "Remove one or more containers"},
	{"rmi", "Remove one or more images"},
	{"run", "Run a command in a new container"},
	{"save", "Save an image(s) to a tar archive"},
	{"search", "Search the Docker Hub for images"},
	{"start", "Start one or more stopped containers"},
	{"stats", "Display a live stream of container(s) resource usage statistics"},
	{"stop", "Stop a running container"},
	{"tag", "Tag an image into a repository"},
	{"top", "Display the running processes of a container"},
	{"unpause", "Unpause all processes within a container"},
	{"update", "Update resources of one or more containers"},
	{"version", "Show the Docker version information"},
	{"volume", "Manage Docker volumes"},
	{"wait", "Block until a container stops, then print its exit code"},
}

// DockerCommands stores all the docker command
var DockerCommands = make(map[string]Command)

func init() {
	for _, cmd := range dockerCommands {
		DockerCommands[cmd.Name] = cmd
	}
}
<|endoftext|>


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

package buildkite

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"
	"strconv"
	"strings"

	"github.com/google/go-querystring/query"
)

const (
	defaultBaseURL = "https://api.buildkite.com/"
	userAgent      = "go-buildkite/" + Version
)

// A Client manages communication with the buildkite API.
type Client struct {
	// HTTP client used to communicate with the API.
	client *http.Client

	// Base URL for API requests.  Defaults to the public buildkite API. BaseURL should
	// always be specified with a trailing slash.
	BaseURL *url.URL

	// User agent used when communicating with the buildkite API.
	UserAgent string

	// Services used for talking to different parts of the buildkite API.
	Agents        *AgentsService
	Builds        *BuildsService
	Organizations *OrganizationsService
	Projects      *ProjectsService
	User          *UserService
}

// ListOptions specifies the optional parameters to various List methods that
// support pagination.
type ListOptions struct {
	// For paginated result sets, page of results to retrieve.
	Page int `url:"page,omitempty"`

	// For paginated result sets, the number of results to include per page.
	PerPage int `url:"per_page,omitempty"`
}

// NewClient returns a new buildkite API client. As API calls require authentication
// you MUST supply a client which provides the required API key.
func NewClient(httpClient *http.Client) *Client {

	baseURL, _ := url.Parse(defaultBaseURL)

	c := &Client{
		client:    httpClient,
		BaseURL:   baseURL,
		UserAgent: userAgent,
	}

	c.Agents = &AgentsService{c}
	c.Builds = &BuildsService{c}
	c.Organizations = &OrganizationsService{c}
	c.Projects = &ProjectsService{c}
	c.User = &UserService{c}

	return c
}

// NewRequest creates an API request. A relative URL can be provided in urlStr,
// in which case it is resolved relative to the BaseURL of the Client.
// Relative URLs should always be specified without a preceding slash.  If
// specified, the value pointed to by body is JSON encoded and included as the
// request body.
func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) {
	rel, err := url.Parse(urlStr)
	if err != nil {
		return nil, err
	}

	u := c.BaseURL.ResolveReference(rel)

	buf := new(bytes.Buffer)
	if body != nil {
		err := json.NewEncoder(buf).Encode(body)
		if err != nil {
			return nil, err
		}
	}

	req, err := http.NewRequest(method, u.String(), buf)
	if err != nil {
		return nil, err
	}

	if c.UserAgent != "" {
		req.Header.Add("User-Agent", c.UserAgent)
	}

	return req, nil
}

// Response is a buildkite API response.  This wraps the standard http.Response
// returned from buildkite and provides convenient access to things like
// pagination links.
type Response struct {
	*http.Response

	// These fields provide the page values for paginating through a set of
	// results.  Any or all of these may be set to the zero value for
	// responses that are not part of a paginated set, or for which there
	// are no additional pages.

	NextPage  int
	PrevPage  int
	FirstPage int
	LastPage  int
}

// newResponse creats a new Response for the provided http.Response.
func newResponse(r *http.Response) *Response {
	response := &Response{Response: r}
	response.populatePageValues()
	return response
}

// populatePageValues parses the HTTP Link response headers and populates the
// various pagination link values in the Reponse.
func (r *Response) populatePageValues() {
	if links, ok := r.Response.Header["Link"]; ok && len(links) > 0 {
		for _, link := range strings.Split(links[0], ",") {
			segments := strings.Split(strings.TrimSpace(link), ";")

			// link must at least have href and rel
			if len(segments) < 2 {
				continue
			}

			// ensure href is properly formatted
			if !strings.HasPrefix(segments[0], "<") || !strings.HasSuffix(segments[0], ">") {
				continue
			}

			// try to pull out page parameter
			url, err := url.Parse(segments[0][1 : len(segments[0])-1])
			if err != nil {
				continue
			}
			page := url.Query().Get("page")
			if page == "" {
				continue
			}

			for _, segment := range segments[1:] {
				switch strings.TrimSpace(segment) {
				case `rel="next"`:
					r.NextPage, _ = strconv.Atoi(page)
				case `rel="prev"`:
					r.PrevPage, _ = strconv.Atoi(page)
				case `rel="first"`:
					r.FirstPage, _ = strconv.Atoi(page)
				case `rel="last"`:
					r.LastPage, _ = strconv.Atoi(page)
				}

			}
		}
	}
}

// Do sends an API request and returns the API response.  The API response is
// JSON decoded and stored in the value pointed to by v, or returned as an
// error if an API error has occurred.  If v implements the io.Writer
// interface, the raw response body will be written to v, without attempting to
// first decode it.
func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()
	defer io.Copy(ioutil.Discard, resp.Body)

	response := newResponse(resp)

	err = checkResponse(resp)
	if err != nil {
		// even though there was an error, we still return the response
		// in case the caller wants to inspect it further
		return response, err
	}

	if v != nil {
		if w, ok := v.(io.Writer); ok {
			io.Copy(w, resp.Body)
		} else {
			err = json.NewDecoder(resp.Body).Decode(v)
		}
	}
	return response, err
}

// ErrorResponse provides a message.
type ErrorResponse struct {
	Response *http.Response // HTTP response that caused this error
	Message  string         `json:"message"` // error message
}

func (r *ErrorResponse) Error() string {
	return fmt.Sprintf("%v %v: %d %v",
		r.Response.Request.Method, r.Response.Request.URL,
		r.Response.StatusCode, r.Message)
}

func checkResponse(r *http.Response) error {
	if c := r.StatusCode; 200 <= c && c <= 299 {
		return nil
	}
	errorResponse := &ErrorResponse{Response: r}
	data, err := ioutil.ReadAll(r.Body)
	if err == nil && data != nil {
		json.Unmarshal(data, errorResponse)
	}
	return errorResponse
}

// addOptions adds the parameters in opt as URL query parameters to s.  opt
// must be a struct whose fields may contain "url" tags.
func addOptions(s string, opt interface{}) (string, error) {
	v := reflect.ValueOf(opt)
	if v.Kind() == reflect.Ptr && v.IsNil() {
		return s, nil
	}

	u, err := url.Parse(s)
	if err != nil {
		return s, err
	}

	qs, err := query.Values(opt)
	if err != nil {
		return s, err
	}

	u.RawQuery = qs.Encode()
	return u.String(), nil
}

// Int is a helper routine that allocates a new int value
// to store v and returns a pointer to it, but unlike Int
// its argument value is an int.
func Int(v int) *int {
	p := new(int)
	*p = v
	return p
}

// String is a helper routine that allocates a new string value
// to store v and returns a pointer to it.
func String(v string) *string {
	p := new(string)
	*p = v
	return p
}
<commit_msg>Added HTTP debugging.<commit_after>// Copyright 2014 Mark Wolfe. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package buildkite

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/httputil"
	"net/url"
	"reflect"
	"strconv"
	"strings"

	"github.com/google/go-querystring/query"
)

const (
	defaultBaseURL = "https://api.buildkite.com/"
	userAgent      = "go-buildkite/" + Version
)

var (
	httpDebug = false
)

// A Client manages communication with the buildkite API.
type Client struct {
	// HTTP client used to communicate with the API.
	client *http.Client

	// Base URL for API requests.  Defaults to the public buildkite API. BaseURL should
	// always be specified with a trailing slash.
	BaseURL *url.URL

	// User agent used when communicating with the buildkite API.
	UserAgent string

	// Services used for talking to different parts of the buildkite API.
	Agents        *AgentsService
	Builds        *BuildsService
	Organizations *OrganizationsService
	Projects      *ProjectsService
	User          *UserService
}

// ListOptions specifies the optional parameters to various List methods that
// support pagination.
type ListOptions struct {
	// For paginated result sets, page of results to retrieve.
	Page int `url:"page,omitempty"`

	// For paginated result sets, the number of results to include per page.
	PerPage int `url:"per_page,omitempty"`
}

// NewClient returns a new buildkite API client. As API calls require authentication
// you MUST supply a client which provides the required API key.
func NewClient(httpClient *http.Client) *Client {

	baseURL, _ := url.Parse(defaultBaseURL)

	c := &Client{
		client:    httpClient,
		BaseURL:   baseURL,
		UserAgent: userAgent,
	}

	c.Agents = &AgentsService{c}
	c.Builds = &BuildsService{c}
	c.Organizations = &OrganizationsService{c}
	c.Projects = &ProjectsService{c}
	c.User = &UserService{c}

	return c
}

// SetHttpDebug this enables global http request/response dumping for this API
func SetHttpDebug(flag bool) {
	httpDebug = flag
}

// NewRequest creates an API request. A relative URL can be provided in urlStr,
// in which case it is resolved relative to the BaseURL of the Client.
// Relative URLs should always be specified without a preceding slash.  If
// specified, the value pointed to by body is JSON encoded and included as the
// request body.
func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) {
	rel, err := url.Parse(urlStr)
	if err != nil {
		return nil, err
	}

	u := c.BaseURL.ResolveReference(rel)

	buf := new(bytes.Buffer)
	if body != nil {
		err := json.NewEncoder(buf).Encode(body)
		if err != nil {
			return nil, err
		}
	}

	req, err := http.NewRequest(method, u.String(), buf)
	if err != nil {
		return nil, err
	}

	if c.UserAgent != "" {
		req.Header.Add("User-Agent", c.UserAgent)
	}

	return req, nil
}

// Response is a buildkite API response.  This wraps the standard http.Response
// returned from buildkite and provides convenient access to things like
// pagination links.
type Response struct {
	*http.Response

	// These fields provide the page values for paginating through a set of
	// results.  Any or all of these may be set to the zero value for
	// responses that are not part of a paginated set, or for which there
	// are no additional pages.

	NextPage  int
	PrevPage  int
	FirstPage int
	LastPage  int
}

// newResponse creats a new Response for the provided http.Response.
func newResponse(r *http.Response) *Response {
	response := &Response{Response: r}
	response.populatePageValues()
	return response
}

// populatePageValues parses the HTTP Link response headers and populates the
// various pagination link values in the Reponse.
func (r *Response) populatePageValues() {
	if links, ok := r.Response.Header["Link"]; ok && len(links) > 0 {
		for _, link := range strings.Split(links[0], ",") {
			segments := strings.Split(strings.TrimSpace(link), ";")

			// link must at least have href and rel
			if len(segments) < 2 {
				continue
			}

			// ensure href is properly formatted
			if !strings.HasPrefix(segments[0], "<") || !strings.HasSuffix(segments[0], ">") {
				continue
			}

			// try to pull out page parameter
			url, err := url.Parse(segments[0][1 : len(segments[0])-1])
			if err != nil {
				continue
			}
			page := url.Query().Get("page")
			if page == "" {
				continue
			}

			for _, segment := range segments[1:] {
				switch strings.TrimSpace(segment) {
				case `rel="next"`:
					r.NextPage, _ = strconv.Atoi(page)
				case `rel="prev"`:
					r.PrevPage, _ = strconv.Atoi(page)
				case `rel="first"`:
					r.FirstPage, _ = strconv.Atoi(page)
				case `rel="last"`:
					r.LastPage, _ = strconv.Atoi(page)
				}

			}
		}
	}
}

// Do sends an API request and returns the API response.  The API response is
// JSON decoded and stored in the value pointed to by v, or returned as an
// error if an API error has occurred.  If v implements the io.Writer
// interface, the raw response body will be written to v, without attempting to
// first decode it.
func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()
	defer io.Copy(ioutil.Discard, resp.Body)

	// dump requests
	if httpDebug {
		var (
			dump []byte
			err  error
		)

		dump, err = httputil.DumpRequest(req, true)

		if err == nil {
			fmt.Printf("DEBUG request uri=%s\n%s\n", req.URL, dump)
		}

		dump, err = httputil.DumpResponse(resp, true)

		if err == nil {
			fmt.Printf("DEBUG response uri=%s\n%s\n", req.URL, dump)
		}
	}

	response := newResponse(resp)

	err = checkResponse(resp)
	if err != nil {
		// even though there was an error, we still return the response
		// in case the caller wants to inspect it further
		return response, err
	}

	if v != nil {
		if w, ok := v.(io.Writer); ok {
			io.Copy(w, resp.Body)
		} else {
			err = json.NewDecoder(resp.Body).Decode(v)
		}
	}
	return response, err
}

// ErrorResponse provides a message.
type ErrorResponse struct {
	Response *http.Response // HTTP response that caused this error
	Message  string         `json:"message"` // error message
}

func (r *ErrorResponse) Error() string {
	return fmt.Sprintf("%v %v: %d %v",
		r.Response.Request.Method, r.Response.Request.URL,
		r.Response.StatusCode, r.Message)
}

func checkResponse(r *http.Response) error {
	if c := r.StatusCode; 200 <= c && c <= 299 {
		return nil
	}
	errorResponse := &ErrorResponse{Response: r}
	data, err := ioutil.ReadAll(r.Body)
	if err == nil && data != nil {
		json.Unmarshal(data, errorResponse)
	}
	return errorResponse
}

// addOptions adds the parameters in opt as URL query parameters to s.  opt
// must be a struct whose fields may contain "url" tags.
func addOptions(s string, opt interface{}) (string, error) {
	v := reflect.ValueOf(opt)
	if v.Kind() == reflect.Ptr && v.IsNil() {
		return s, nil
	}

	u, err := url.Parse(s)
	if err != nil {
		return s, err
	}

	qs, err := query.Values(opt)
	if err != nil {
		return s, err
	}

	u.RawQuery = qs.Encode()
	return u.String(), nil
}

// Int is a helper routine that allocates a new int value
// to store v and returns a pointer to it, but unlike Int
// its argument value is an int.
func Int(v int) *int {
	p := new(int)
	*p = v
	return p
}

// String is a helper routine that allocates a new string value
// to store v and returns a pointer to it.
func String(v string) *string {
	p := new(string)
	*p = v
	return p
}
<|endoftext|>


<commit_before>package kite

import (
	"encoding/json"
	"io/ioutil"
	"kite/protocol"
	"log"
	"strings"
)

// Options is passed to kite.New when creating new instance.
type Options struct {
	// Mandatory fields
	Kitename    string
	Version     string
	Environment string
	Region      string

	// Optional fields
	PublicIP   string              // default: 0.0.0.0
	Port       string              // default: random
	Path       string              // default: /kite
	Visibility protocol.Visibility // default: protocol.Private

	// Do not authenticate incoming requests
	DisableAuthentication bool
}

// validate fields of the options struct. It exits if an error is occured.
func (o *Options) validate() {
	if o.Kitename == "" {
		log.Fatal("ERROR: options.Kitename field is not set")
	}

	if digits := strings.Split(o.Version, "."); len(digits) != 3 {
		log.Fatal("ERROR: please use 3-digits semantic versioning for options.version")
	}

	if o.Region == "" {
		log.Fatal("ERROR: options.Region field is not set")
	}

	if o.Environment == "" {
		log.Fatal("ERROR: options.Environment field is not set")
	}

	if o.PublicIP == "" {
		o.PublicIP = "127.0.0.1"
	}

	if o.Port == "" {
		o.Port = "0" // OS binds to an automatic port
	}

	if o.Path == "" {
		o.Path = "/kite"
	}

	if o.Path[0] != '/' {
		o.Path = "/" + o.Path
	}

	if o.Visibility == protocol.Visibility("") {
		o.Visibility = protocol.Private
	}
}

// Read options from a file.
func ReadKiteOptions(configfile string) (*Options, error) {
	file, err := ioutil.ReadFile(configfile)
	if err != nil {
		return nil, err
	}

	options := &Options{}
	return options, json.Unmarshal(file, &options)
}
<commit_msg>use kitename as default websocket path<commit_after>package kite

import (
	"encoding/json"
	"io/ioutil"
	"kite/protocol"
	"log"
	"strings"
)

// Options is passed to kite.New when creating new instance.
type Options struct {
	// Mandatory fields
	Kitename    string
	Version     string
	Environment string
	Region      string

	// Optional fields
	PublicIP   string              // default: 0.0.0.0
	Port       string              // default: random
	Path       string              // default: /<kitename>
	Visibility protocol.Visibility // default: protocol.Private

	// Do not authenticate incoming requests
	DisableAuthentication bool
}

// validate fields of the options struct. It exits if an error is occured.
func (o *Options) validate() {
	if o.Kitename == "" {
		log.Fatal("ERROR: options.Kitename field is not set")
	}

	if digits := strings.Split(o.Version, "."); len(digits) != 3 {
		log.Fatal("ERROR: please use 3-digits semantic versioning for options.version")
	}

	if o.Region == "" {
		log.Fatal("ERROR: options.Region field is not set")
	}

	if o.Environment == "" {
		log.Fatal("ERROR: options.Environment field is not set")
	}

	if o.PublicIP == "" {
		o.PublicIP = "127.0.0.1"
	}

	if o.Port == "" {
		o.Port = "0" // OS binds to an automatic port
	}

	if o.Path == "" {
		o.Path = "/" + o.Kitename
	}

	if o.Path[0] != '/' {
		o.Path = "/" + o.Path
	}

	if o.Visibility == protocol.Visibility("") {
		o.Visibility = protocol.Private
	}
}

// Read options from a file.
func ReadKiteOptions(configfile string) (*Options, error) {
	file, err := ioutil.ReadFile(configfile)
	if err != nil {
		return nil, err
	}

	options := &Options{}
	return options, json.Unmarshal(file, &options)
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 Matthew Dawson <matthew@mjdsystems.ca>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package main

import (
	"bytes"

	"encoding/base64"

	"net/url"
	"time"

	riak "github.com/tpjg/goriakpbc"
)

type Feed struct {
	Url url.URL `riak:"url"`

	Title     string    `riak:"title"`
	LastCheck time.Time `riak:"last_check"`

	ItemKeys        ItemKeyList `riak:"item_keys"`
	DeletedItemKeys ItemKeyList `riak:"deleted_items"`

	NextCheck time.Time `riak:"next_check"`

	riak.Model `riak:"feeds"`
}

type FeedItem struct {
	Title   string `riak:"title"`
	Author  string `riak:"author"`
	Content string `riak:"content"`

	Url url.URL `riak:"url"`

	PubDate time.Time `riak:"publication_date"`

	riak.Model `riak:"items"`
}

type ItemKey []byte

func (l ItemKey) Less(r Comparable) bool {
	return bytes.Compare(l, r.(ItemKey)) == -1
}
func (l *ItemKey) UnmarshalJSON(input []byte) error {
	input = input[1 : len(input)-1]

	*l = make(ItemKey, base64.StdEncoding.DecodedLen(len(input)))
	n, err := base64.StdEncoding.Decode(*l, input)

	if err != nil {
		return err
	} else {
		*l = (*l)[0:n]
		return nil
	}
}

type ItemKeyList []ItemKey

func (list *ItemKeyList) Append(key Comparable) {
	*list = append(*list, key.(ItemKey))
}

func (list ItemKeyList) Get(index int) Comparable {
	return list[index]
}

func (list *ItemKeyList) RemoveAt(index int) {
	*list = append((*list)[:index], (*list)[index+1:]...)
}

func (list ItemKeyList) Len() int {
	return len(list)
}

func (ItemKeyList) Make() ComparableArray {
	return &ItemKeyList{}
}

func (f *Feed) Resolve(siblingsCount int) error {
	// First get the siblings!
	siblingsI, err := f.Siblings(&Feed{})
	if err != nil {
		return err
	}
	siblings := siblingsI.([]Feed)

	// Set the Url, as it is constant
	f.Url = siblings[0].Url

	for i := 0; i < siblingsCount; i++ {
		// Resolve regular feed details.  Basically, take the latest version!
		// If this is the first object, it will have a zero time of year 1st.  If a feed is claiming
		// be older then that, well it just won't work.
		if siblings[i].LastCheck.After(f.LastCheck) {
			f.Title = siblings[i].Title
			f.LastCheck = siblings[i].LastCheck
			f.NextCheck = siblings[i].NextCheck
		}

		// for the item lists, merge and de-dup using insert slice sort!
		f.ItemKeys = *InsertSliceSort(&f.ItemKeys, &siblings[i].ItemKeys).(*ItemKeyList)
		f.DeletedItemKeys = *InsertSliceSort(&f.DeletedItemKeys, &siblings[i].DeletedItemKeys).(*ItemKeyList)
	}
	RemoveSliceElements(&f.ItemKeys, &f.DeletedItemKeys)

	return nil
}

func (f *FeedItem) Resolve(siblingsCount int) error {
	// First get the siblings!
	siblingsI, err := f.Siblings(&FeedItem{})
	if err != nil {
		return err
	}
	siblings := siblingsI.([]FeedItem)

	for i := 0; i < siblingsCount; i++ {
		// Feed items are simple.  What ever claims is the latest update wins.  This should come from
		// the feed when possible.  Otherwise it is generated by the system, but should still be ok.
		if siblings[i].PubDate.After(f.PubDate) {
			f.Title = siblings[i].Title
			f.Author = siblings[i].Author
			f.Content = siblings[i].Content
			f.Url = siblings[i].Url
			f.PubDate = siblings[i].PubDate
		}
	}

	///@todo: I need to merge indexes here.  Currently I can't though due to library restrictions.

	return nil
}
<commit_msg>Add a function to make it easy to add a create ItemKey.<commit_after>/*
 * Copyright (C) 2013 Matthew Dawson <matthew@mjdsystems.ca>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package main

import (
	"bytes"
	"encoding/binary"

	"encoding/base64"

	"net/url"
	"time"

	riak "github.com/tpjg/goriakpbc"
)

type Feed struct {
	Url url.URL `riak:"url"`

	Title     string    `riak:"title"`
	LastCheck time.Time `riak:"last_check"`

	ItemKeys        ItemKeyList `riak:"item_keys"`
	DeletedItemKeys ItemKeyList `riak:"deleted_items"`

	NextCheck time.Time `riak:"next_check"`

	riak.Model `riak:"feeds"`
}

type FeedItem struct {
	Title   string `riak:"title"`
	Author  string `riak:"author"`
	Content string `riak:"content"`

	Url url.URL `riak:"url"`

	PubDate time.Time `riak:"publication_date"`

	riak.Model `riak:"items"`
}

type ItemKey []byte

func NewItemKey(id uint64, rawId []byte) ItemKey {
	buf := &bytes.Buffer{}

	binary.Write(buf, binary.BigEndian, id)
	buf.WriteString("-")
	buf.Write(rawId)

	return buf.Bytes()
}

func (l ItemKey) Less(r Comparable) bool {
	return bytes.Compare(l, r.(ItemKey)) == -1
}
func (l *ItemKey) UnmarshalJSON(input []byte) error {
	input = input[1 : len(input)-1]

	*l = make(ItemKey, base64.StdEncoding.DecodedLen(len(input)))
	n, err := base64.StdEncoding.Decode(*l, input)

	if err != nil {
		return err
	} else {
		*l = (*l)[0:n]
		return nil
	}
}

type ItemKeyList []ItemKey

func (list *ItemKeyList) Append(key Comparable) {
	*list = append(*list, key.(ItemKey))
}

func (list ItemKeyList) Get(index int) Comparable {
	return list[index]
}

func (list *ItemKeyList) RemoveAt(index int) {
	*list = append((*list)[:index], (*list)[index+1:]...)
}

func (list ItemKeyList) Len() int {
	return len(list)
}

func (ItemKeyList) Make() ComparableArray {
	return &ItemKeyList{}
}

func (f *Feed) Resolve(siblingsCount int) error {
	// First get the siblings!
	siblingsI, err := f.Siblings(&Feed{})
	if err != nil {
		return err
	}
	siblings := siblingsI.([]Feed)

	// Set the Url, as it is constant
	f.Url = siblings[0].Url

	for i := 0; i < siblingsCount; i++ {
		// Resolve regular feed details.  Basically, take the latest version!
		// If this is the first object, it will have a zero time of year 1st.  If a feed is claiming
		// be older then that, well it just won't work.
		if siblings[i].LastCheck.After(f.LastCheck) {
			f.Title = siblings[i].Title
			f.LastCheck = siblings[i].LastCheck
			f.NextCheck = siblings[i].NextCheck
		}

		// for the item lists, merge and de-dup using insert slice sort!
		f.ItemKeys = *InsertSliceSort(&f.ItemKeys, &siblings[i].ItemKeys).(*ItemKeyList)
		f.DeletedItemKeys = *InsertSliceSort(&f.DeletedItemKeys, &siblings[i].DeletedItemKeys).(*ItemKeyList)
	}
	RemoveSliceElements(&f.ItemKeys, &f.DeletedItemKeys)

	return nil
}

func (f *FeedItem) Resolve(siblingsCount int) error {
	// First get the siblings!
	siblingsI, err := f.Siblings(&FeedItem{})
	if err != nil {
		return err
	}
	siblings := siblingsI.([]FeedItem)

	for i := 0; i < siblingsCount; i++ {
		// Feed items are simple.  What ever claims is the latest update wins.  This should come from
		// the feed when possible.  Otherwise it is generated by the system, but should still be ok.
		if siblings[i].PubDate.After(f.PubDate) {
			f.Title = siblings[i].Title
			f.Author = siblings[i].Author
			f.Content = siblings[i].Content
			f.Url = siblings[i].Url
			f.PubDate = siblings[i].PubDate
		}
	}

	///@todo: I need to merge indexes here.  Currently I can't though due to library restrictions.

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	g "github.com/oatot/oatot/generated"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"log"
	"reflect"
	"unsafe"
)

// #include "../game/g_local.h"
// #include "../game/bg_public.h"
import "C"

const maxActiveBidsN = 5
const bidsPerPageN = 15
const maxCStrLen = 1024

var (
	grpcAddr = "127.0.0.1:13283"
	client   g.OatotClient
)

func StringToC(str string, cStr *C.char) {
	size := len(str)
	var slice []C.char
	sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&slice)))
	sliceHeader.Cap = maxCStrLen
	sliceHeader.Len = maxCStrLen
	sliceHeader.Data = uintptr(unsafe.Pointer(cStr))
	for i := 0; i < size; i++ {
		slice[i] = C.char(str[i])
	}
}

func CBidFromGo(in *g.Bid, out *C.bid_t) {
	//TODO: implement time storage in backend.
	//timeStr := (*in.OpenTime).String()
	out.amount = C.int(*in.Amount)
	out.bet_ID = C.int(*in.BetId)
	StringToC(*in.Horse, &(out.horse[0]))
	StringToC(*in.Currency, &(out.currency[0]))
	//StringToC(timeStr, &(out.open_time[0]))
}

func CFullbidFromGo(in *g.Bid, out *C.fullbid_t) {
	//TODO: implement time storage in backend.
	//timeStr := (*in.CloseTime).String()
	CBidFromGo(in, &out.open_bid)
	out.prize = C.int(*in.Prize)
	StringToC(*in.Winner, &(out.winner[0]))
	//StringToC(timeStr, &(out.close_time[0]))
}

func CCurrencySummaryFromGo(in *g.CurrencySummary) C.currencySummary_t {
	return C.currencySummary_t{
		total_bet:   C.int(*in.TotalBet),
		total_prize: C.int(*in.TotalPrize),
		total_lost:  C.int(*in.TotalLost),
		bets_won:    C.int(*in.BetsWon),
		bets_lost:   C.int(*in.BetsLost),
	}
}

//export GInitializeClient
func GInitializeClient() {
	if client == nil {
		// Set up a connection to the server.
		conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure())
		if err != nil {
			log.Fatalf("Did not connect: %v", err)
		}
		client = g.NewOatotClient(conn)
	}
}

//export GOaChangeGameStage
func GOaChangeGameStage(newStage C.int) {
	newStageVal := uint64(newStage)
	_, err := client.OaChangeGameStage(
		context.Background(),
		&g.OaChangeGameStageRequest{
			NewStage: &newStageVal,
		},
	)
	if err != nil {
		log.Fatalf("OaChangeGameStage: %v", err)
	}
}

//export GOaCloseBids
func GOaCloseBids(winner *C.char) {
	winnerStr := C.GoString(winner)
	_, err := client.OaCloseBids(
		context.Background(),
		&g.OaCloseBidsRequest{
			Winner: &winnerStr,
		},
	)
	if err != nil {
		log.Fatalf("OaCloseBids: %v", err)
	}
}

//export GOaCloseBidsByIncident
func GOaCloseBidsByIncident() {
	_, err := client.OaCloseBidsByIncident(
		context.Background(),
		&g.OaCloseBidsByIncidentRequest{},
	)
	if err != nil {
		log.Fatalf("OaCloseBidsByIncident: %v", err)
	}
}

//export GOaIsNew
func GOaIsNew(clGuid *C.char) C.int {
	clGuidStr := C.GoString(clGuid)
	res, err := client.OaIsNew(
		context.Background(),
		&g.OaIsNewRequest{
			OaAuth: &g.OaAuth{ClGuid: &clGuidStr},
		},
	)
	if err != nil {
		log.Fatalf("OaIsNew: %v", err)
	}
	if *res.Result {
		return C.int(1)
	} else {
		return C.int(0)
	}
}

//export GOaRegister
func GOaRegister(clGuid *C.char) {
	clGuidStr := C.GoString(clGuid)
	_, err := client.OaRegister(
		context.Background(),
		&g.OaRegisterRequest{
			OaAuth: &g.OaAuth{ClGuid: &clGuidStr},
		},
	)
	if err != nil {
		log.Fatalf("OaRegister: %v", err)
	}
}

//export GOaTransferMoney
func GOaTransferMoney(clGuid *C.char, amount C.int, currency *C.char) {
	clGuidStr := C.GoString(clGuid)
	currencyStr := C.GoString(currency)
	amountVal := uint64(amount)
	_, err := client.OaTransferMoney(
		context.Background(),
		&g.OaTransferMoneyRequest{
			Amount:   &amountVal,
			OaAuth:   &g.OaAuth{ClGuid: &clGuidStr},
			Currency: &currencyStr,
		},
	)
	if err != nil {
		log.Fatalf("OaTransferMoney: %v", err)
	}
}

//export GOaActiveBidsSums
func GOaActiveBidsSums(horse *C.char) C.betSum_t {
	horseStr := C.GoString(horse)
	res, err := client.OaActiveBidsSums(
		context.Background(),
		&g.OaActiveBidsSumsRequest{
			Horse: &horseStr,
		},
	)
	if err != nil {
		log.Fatalf("OaActiveBidsSums: %v", err)
	}
	return C.betSum_t{C.int(*res.OacAmount), C.int(*res.BtcAmount)}
}

//export GOaMyBalance
func GOaMyBalance(clGuid *C.char, currency *C.char) C.balance_t {
	clGuidStr := C.GoString(clGuid)
	currencyStr := C.GoString(currency)
	res, err := client.OaMyBalance(
		context.Background(),
		&g.OaMyBalanceRequest{
			OaAuth:   &g.OaAuth{ClGuid: &clGuidStr},
			Currency: &currencyStr,
		},
	)
	if err != nil {
		log.Fatalf("OaMyBalance: %v", err)
	}
	return C.balance_t{C.int(*res.FreeMoney), C.int(*res.MoneyOnBids)}
}

//export GOaMyBid
func GOaMyBid(clGuid *C.char, bid C.bid_t) {
	clGuidStr := C.GoString(clGuid)
	horseStr := C.GoString(&(bid.horse[0]))
	currencyStr := C.GoString(&(bid.currency[0]))
	amountVal := uint64(bid.amount)
	bidN := &g.Bid{
		Horse:    &horseStr,
		Currency: &currencyStr,
		Amount:   &amountVal,
	}
	_, err := client.OaMyBid(
		context.Background(),
		&g.OaMyBidRequest{
			OaAuth: &g.OaAuth{ClGuid: &clGuidStr},
			Bid:    bidN,
		},
	)
	if err != nil {
		log.Fatalf("OaMyBid: %v", err)
	}
}

//export GOaDiscardBet
func GOaDiscardBet(clGuid *C.char, betId C.int) {
	clGuidStr := C.GoString(clGuid)
	betIdVal := uint64(betId)
	_, err := client.OaDiscardBet(
		context.Background(),
		&g.OaDiscardBetRequest{
			OaAuth: &g.OaAuth{ClGuid: &clGuidStr},
			BetId:  &betIdVal,
		},
	)
	if err != nil {
		log.Fatalf("OaDiscardBet: %v", err)
	}
}

//export GOaMyActiveBids
func GOaMyActiveBids(clGuid *C.char, activeBids *C.bid_t) C.int {
	clGuidStr := C.GoString(clGuid)
	res, err := client.OaMyActiveBids(
		context.Background(),
		&g.OaMyActiveBidsRequest{
			OaAuth: &g.OaAuth{ClGuid: &clGuidStr},
		},
	)
	if err != nil {
		log.Fatalf("OaMyActiveBids: %v", err)
	}
	size := len(res.Bids)
	var bids []C.bid_t
	sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&bids)))
	sliceHeader.Cap = maxActiveBidsN
	sliceHeader.Len = maxActiveBidsN
	sliceHeader.Data = uintptr(unsafe.Pointer(activeBids))
	for i := 0; i < size; i++ {
		CBidFromGo(res.Bids[i], &bids[i])
	}
	return C.int(size)
}

//export GOaMyPastBids
func GOaMyPastBids(clGuid *C.char, page *C.char, nextPage *C.char, pastBids *C.fullbid_t) C.int {
	clGuidStr := C.GoString(clGuid)
	pageStr := C.GoString(page)
	res, err := client.OaMyPastBids(
		context.Background(),
		&g.OaMyPastBidsRequest{
			OaAuth: &g.OaAuth{ClGuid: &clGuidStr},
			Page:   &pageStr,
		},
	)
	if err != nil {
		log.Fatalf("OaMyPastBids: %v", err)
	}
	size := len(res.Bids)
	var bids []C.fullbid_t
	sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&bids)))
	sliceHeader.Cap = bidsPerPageN
	sliceHeader.Len = bidsPerPageN
	sliceHeader.Data = uintptr(unsafe.Pointer(pastBids))
	for i := 0; i < size; i++ {
		CFullbidFromGo(res.Bids[i], &bids[i])
	}
	StringToC(*res.NextPage, nextPage)
	return C.int(size)
	return 0
}

//export GOaMyBidsSummary
func GOaMyBidsSummary(clGuid *C.char) C.bidsSummary_t {
	clGuidStr := C.GoString(clGuid)
	res, err := client.OaMyBidsSummary(
		context.Background(),
		&g.OaMyBidsSummaryRequest{
			OaAuth: &g.OaAuth{ClGuid: &clGuidStr},
		},
	)
	if err != nil {
		log.Fatalf("OaMyBidsSummary: %v", err)
	}
	oacSummary := CCurrencySummaryFromGo(res.OacSummary)
	btcSummary := CCurrencySummaryFromGo(res.BtcSummary)
	return C.bidsSummary_t{oacSummary, btcSummary}
}

func main() {}
<commit_msg>Go client: add \0 at the end of all strings before returning to C<commit_after>package main

import (
	g "github.com/oatot/oatot/generated"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"log"
	"reflect"
	"unsafe"
)

// #include "../game/g_local.h"
// #include "../game/bg_public.h"
import "C"

const maxActiveBidsN = 5
const bidsPerPageN = 15
const maxCStrLen = 1024

var (
	grpcAddr = "127.0.0.1:13283"
	client   g.OatotClient
)

func StringToC(str string, cStr *C.char) {
	size := len(str)
	var slice []C.char
	sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&slice)))
	sliceHeader.Cap = maxCStrLen
	sliceHeader.Len = maxCStrLen
	sliceHeader.Data = uintptr(unsafe.Pointer(cStr))
	for i := 0; i < size; i++ {
		slice[i] = C.char(str[i])
	}
	slice[size] = C.char(byte('\x00'))
}

func CBidFromGo(in *g.Bid, out *C.bid_t) {
	//TODO: implement time storage in backend.
	//timeStr := (*in.OpenTime).String()
	out.amount = C.int(*in.Amount)
	out.bet_ID = C.int(*in.BetId)
	StringToC(*in.Horse, &(out.horse[0]))
	StringToC(*in.Currency, &(out.currency[0]))
	//StringToC(timeStr, &(out.open_time[0]))
}

func CFullbidFromGo(in *g.Bid, out *C.fullbid_t) {
	//TODO: implement time storage in backend.
	//timeStr := (*in.CloseTime).String()
	CBidFromGo(in, &out.open_bid)
	out.prize = C.int(*in.Prize)
	StringToC(*in.Winner, &(out.winner[0]))
	//StringToC(timeStr, &(out.close_time[0]))
}

func CCurrencySummaryFromGo(in *g.CurrencySummary) C.currencySummary_t {
	return C.currencySummary_t{
		total_bet:   C.int(*in.TotalBet),
		total_prize: C.int(*in.TotalPrize),
		total_lost:  C.int(*in.TotalLost),
		bets_won:    C.int(*in.BetsWon),
		bets_lost:   C.int(*in.BetsLost),
	}
}

//export GInitializeClient
func GInitializeClient() {
	if client == nil {
		// Set up a connection to the server.
		conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure())
		if err != nil {
			log.Fatalf("Did not connect: %v", err)
		}
		client = g.NewOatotClient(conn)
	}
}

//export GOaChangeGameStage
func GOaChangeGameStage(newStage C.int) {
	newStageVal := uint64(newStage)
	_, err := client.OaChangeGameStage(
		context.Background(),
		&g.OaChangeGameStageRequest{
			NewStage: &newStageVal,
		},
	)
	if err != nil {
		log.Fatalf("OaChangeGameStage: %v", err)
	}
}

//export GOaCloseBids
func GOaCloseBids(winner *C.char) {
	winnerStr := C.GoString(winner)
	_, err := client.OaCloseBids(
		context.Background(),
		&g.OaCloseBidsRequest{
			Winner: &winnerStr,
		},
	)
	if err != nil {
		log.Fatalf("OaCloseBids: %v", err)
	}
}

//export GOaCloseBidsByIncident
func GOaCloseBidsByIncident() {
	_, err := client.OaCloseBidsByIncident(
		context.Background(),
		&g.OaCloseBidsByIncidentRequest{},
	)
	if err != nil {
		log.Fatalf("OaCloseBidsByIncident: %v", err)
	}
}

//export GOaIsNew
func GOaIsNew(clGuid *C.char) C.int {
	clGuidStr := C.GoString(clGuid)
	res, err := client.OaIsNew(
		context.Background(),
		&g.OaIsNewRequest{
			OaAuth: &g.OaAuth{ClGuid: &clGuidStr},
		},
	)
	if err != nil {
		log.Fatalf("OaIsNew: %v", err)
	}
	if *res.Result {
		return C.int(1)
	} else {
		return C.int(0)
	}
}

//export GOaRegister
func GOaRegister(clGuid *C.char) {
	clGuidStr := C.GoString(clGuid)
	_, err := client.OaRegister(
		context.Background(),
		&g.OaRegisterRequest{
			OaAuth: &g.OaAuth{ClGuid: &clGuidStr},
		},
	)
	if err != nil {
		log.Fatalf("OaRegister: %v", err)
	}
}

//export GOaTransferMoney
func GOaTransferMoney(clGuid *C.char, amount C.int, currency *C.char) {
	clGuidStr := C.GoString(clGuid)
	currencyStr := C.GoString(currency)
	amountVal := uint64(amount)
	_, err := client.OaTransferMoney(
		context.Background(),
		&g.OaTransferMoneyRequest{
			Amount:   &amountVal,
			OaAuth:   &g.OaAuth{ClGuid: &clGuidStr},
			Currency: &currencyStr,
		},
	)
	if err != nil {
		log.Fatalf("OaTransferMoney: %v", err)
	}
}

//export GOaActiveBidsSums
func GOaActiveBidsSums(horse *C.char) C.betSum_t {
	horseStr := C.GoString(horse)
	res, err := client.OaActiveBidsSums(
		context.Background(),
		&g.OaActiveBidsSumsRequest{
			Horse: &horseStr,
		},
	)
	if err != nil {
		log.Fatalf("OaActiveBidsSums: %v", err)
	}
	return C.betSum_t{C.int(*res.OacAmount), C.int(*res.BtcAmount)}
}

//export GOaMyBalance
func GOaMyBalance(clGuid *C.char, currency *C.char) C.balance_t {
	clGuidStr := C.GoString(clGuid)
	currencyStr := C.GoString(currency)
	res, err := client.OaMyBalance(
		context.Background(),
		&g.OaMyBalanceRequest{
			OaAuth:   &g.OaAuth{ClGuid: &clGuidStr},
			Currency: &currencyStr,
		},
	)
	if err != nil {
		log.Fatalf("OaMyBalance: %v", err)
	}
	return C.balance_t{C.int(*res.FreeMoney), C.int(*res.MoneyOnBids)}
}

//export GOaMyBid
func GOaMyBid(clGuid *C.char, bid C.bid_t) {
	clGuidStr := C.GoString(clGuid)
	horseStr := C.GoString(&(bid.horse[0]))
	currencyStr := C.GoString(&(bid.currency[0]))
	amountVal := uint64(bid.amount)
	bidN := &g.Bid{
		Horse:    &horseStr,
		Currency: &currencyStr,
		Amount:   &amountVal,
	}
	_, err := client.OaMyBid(
		context.Background(),
		&g.OaMyBidRequest{
			OaAuth: &g.OaAuth{ClGuid: &clGuidStr},
			Bid:    bidN,
		},
	)
	if err != nil {
		log.Fatalf("OaMyBid: %v", err)
	}
}

//export GOaDiscardBet
func GOaDiscardBet(clGuid *C.char, betId C.int) {
	clGuidStr := C.GoString(clGuid)
	betIdVal := uint64(betId)
	_, err := client.OaDiscardBet(
		context.Background(),
		&g.OaDiscardBetRequest{
			OaAuth: &g.OaAuth{ClGuid: &clGuidStr},
			BetId:  &betIdVal,
		},
	)
	if err != nil {
		log.Fatalf("OaDiscardBet: %v", err)
	}
}

//export GOaMyActiveBids
func GOaMyActiveBids(clGuid *C.char, activeBids *C.bid_t) C.int {
	clGuidStr := C.GoString(clGuid)
	res, err := client.OaMyActiveBids(
		context.Background(),
		&g.OaMyActiveBidsRequest{
			OaAuth: &g.OaAuth{ClGuid: &clGuidStr},
		},
	)
	if err != nil {
		log.Fatalf("OaMyActiveBids: %v", err)
	}
	size := len(res.Bids)
	var bids []C.bid_t
	sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&bids)))
	sliceHeader.Cap = maxActiveBidsN
	sliceHeader.Len = maxActiveBidsN
	sliceHeader.Data = uintptr(unsafe.Pointer(activeBids))
	for i := 0; i < size; i++ {
		CBidFromGo(res.Bids[i], &bids[i])
	}
	return C.int(size)
}

//export GOaMyPastBids
func GOaMyPastBids(clGuid *C.char, page *C.char, nextPage *C.char, pastBids *C.fullbid_t) C.int {
	clGuidStr := C.GoString(clGuid)
	pageStr := C.GoString(page)
	res, err := client.OaMyPastBids(
		context.Background(),
		&g.OaMyPastBidsRequest{
			OaAuth: &g.OaAuth{ClGuid: &clGuidStr},
			Page:   &pageStr,
		},
	)
	if err != nil {
		log.Fatalf("OaMyPastBids: %v", err)
	}
	size := len(res.Bids)
	var bids []C.fullbid_t
	sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&bids)))
	sliceHeader.Cap = bidsPerPageN
	sliceHeader.Len = bidsPerPageN
	sliceHeader.Data = uintptr(unsafe.Pointer(pastBids))
	for i := 0; i < size; i++ {
		CFullbidFromGo(res.Bids[i], &bids[i])
	}
	StringToC(*res.NextPage, nextPage)
	return C.int(size)
	return 0
}

//export GOaMyBidsSummary
func GOaMyBidsSummary(clGuid *C.char) C.bidsSummary_t {
	clGuidStr := C.GoString(clGuid)
	res, err := client.OaMyBidsSummary(
		context.Background(),
		&g.OaMyBidsSummaryRequest{
			OaAuth: &g.OaAuth{ClGuid: &clGuidStr},
		},
	)
	if err != nil {
		log.Fatalf("OaMyBidsSummary: %v", err)
	}
	oacSummary := CCurrencySummaryFromGo(res.OacSummary)
	btcSummary := CCurrencySummaryFromGo(res.BtcSummary)
	return C.bidsSummary_t{oacSummary, btcSummary}
}

func main() {}
<|endoftext|>


<commit_before>// The state package enables reading, observing, and changing
// the state stored in MongoDB of a whole environment
// managed by juju.
package mstate

import (
	"fmt"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"launchpad.net/juju-core/charm"
	"launchpad.net/juju-core/trivial"
	"launchpad.net/juju-core/version"
	"net/url"
)

// Tools describes a particular set of juju tools and where to find them.
type Tools struct {
	version.Binary
	URL string
}

// State represents the state of an environment
// managed by juju.
type State struct {
	db        *mgo.Database
	cfgnodes  *mgo.Collection
	charms    *mgo.Collection
	machines  *mgo.Collection
	relations *mgo.Collection
	services  *mgo.Collection
	units     *mgo.Collection
}

// AddMachine creates a new machine state.
func (s *State) AddMachine() (m *Machine, err error) {
	defer trivial.ErrorContextf(&err, "cannot add a new machine")
	id, err := s.sequence("machine")
	if err != nil {
		return nil, err
	}
	mdoc := machineDoc{
		Id:   id,
		Life: Alive,
	}
	err = s.machines.Insert(mdoc)
	if err != nil {
		return nil, err
	}
	return newMachine(s, &mdoc), nil
}

// RemoveMachine removes the machine with the the given id.
func (s *State) RemoveMachine(id int) error {
	sel := bson.D{{"_id", id}, {"life", Alive}}
	change := bson.D{{"$set", bson.D{{"life", Dying}}}}
	err := s.machines.Update(sel, change)
	if err != nil {
		return fmt.Errorf("cannot remove machine %d: %v", id, err)
	}
	return nil
}

// AllMachines returns all machines in the environment.
func (s *State) AllMachines() (machines []*Machine, err error) {
	mdocs := []machineDoc{}
	sel := bson.D{{"life", Alive}}
	err = s.machines.Find(sel).Select(bson.D{{"_id", 1}}).All(&mdocs)
	if err != nil {
		return nil, fmt.Errorf("cannot get all machines: %v", err)
	}
	for _, doc := range mdocs {
		machines = append(machines, newMachine(s, &doc))
	}
	return
}

// Machine returns the machine with the given id.
func (s *State) Machine(id int) (*Machine, error) {
	mdoc := &machineDoc{}
	sel := bson.D{{"_id", id}, {"life", Alive}}
	err := s.machines.Find(sel).One(mdoc)
	if err != nil {
		return nil, fmt.Errorf("cannot get machine %d: %v", id, err)
	}
	return newMachine(s, mdoc), nil
}

// AddCharm adds the ch charm with curl to the state.  bundleUrl must be
// set to a URL where the bundle for ch may be downloaded from.
// On success the newly added charm state is returned.
func (s *State) AddCharm(ch charm.Charm, curl *charm.URL, bundleURL *url.URL, bundleSha256 string) (stch *Charm, err error) {
	cdoc := &charmDoc{
		URL:          curl,
		Meta:         ch.Meta(),
		Config:       ch.Config(),
		BundleURL:    bundleURL,
		BundleSha256: bundleSha256,
	}
	err = s.charms.Insert(cdoc)
	if err != nil {
		return nil, fmt.Errorf("cannot add charm %q: %v", curl, err)
	}
	return newCharm(s, cdoc)
}

// Charm returns the charm with the given URL.
func (s *State) Charm(curl *charm.URL) (*Charm, error) {
	cdoc := &charmDoc{}
	err := s.charms.Find(bson.D{{"_id", curl}}).One(cdoc)
	if err != nil {
		return nil, fmt.Errorf("cannot get charm %q: %v", curl, err)
	}

	return newCharm(s, cdoc)
}

// AddService creates a new service state with the given unique name
// and the charm state.
func (s *State) AddService(name string, ch *Charm) (service *Service, err error) {
	sdoc := serviceDoc{
		Name:     name,
		CharmURL: ch.URL(),
		Life:     Alive,
	}
	err = s.services.Insert(sdoc)
	if err != nil {
		return nil, fmt.Errorf("cannot add service %q:", name, err)
	}
	return &Service{st: s, doc: sdoc}, nil
}

// RemoveService removes a service from the state. It will also remove all
// its units and break any of its existing relations.
func (s *State) RemoveService(svc *Service) (err error) {
	// TODO(mue) Will change with full txn integration.
	defer trivial.ErrorContextf(&err, "cannot remove service %q", svc)

	if svc.doc.Life != Dead {
		panic(fmt.Errorf("service %q is not dead", svc))
	}
	// Remove relations first, to minimize unwanted hook executions.
	rels, err := svc.Relations()
	if err != nil {
		return err
	}
	for _, rel := range rels {
		err = rel.Die()
		if err != nil {
			return err
		}
		err = s.RemoveRelation(rel)
		if err != nil {
			return err
		}
	}
	// Remove the units.
	units, err := svc.AllUnits()
	if err != nil {
		return err
	}
	for _, unit := range units {
		err = unit.Die()
		if err != nil {
			return err
		}
		if err = svc.RemoveUnit(unit); err != nil {
			return err
		}
	}
	// Remove the service.
	sel := bson.D{
		{"_id", svc.doc.Name},
		{"life", Dead},
	}
	err = s.services.Remove(sel)
	if err != nil {
		return err
	}
	return nil
}

// Service returns a service state by name.
func (s *State) Service(name string) (service *Service, err error) {
	sdoc := serviceDoc{}
	sel := bson.D{{"_id", name}}
	err = s.services.Find(sel).One(&sdoc)
	if err != nil {
		return nil, fmt.Errorf("cannot get service %q: %v", name, err)
	}
	return &Service{st: s, doc: sdoc}, nil
}

// AllServices returns all deployed services in the environment.
func (s *State) AllServices() (services []*Service, err error) {
	sdocs := []serviceDoc{}
	err = s.services.Find(bson.D{}).All(&sdocs)
	if err != nil {
		return nil, fmt.Errorf("cannot get all services")
	}
	for _, v := range sdocs {
		services = append(services, &Service{st: s, doc: v})
	}
	return services, nil
}

// AddRelation creates a new relation with the given endpoints.
func (s *State) AddRelation(endpoints ...RelationEndpoint) (r *Relation, err error) {
	defer trivial.ErrorContextf(&err, "cannot add relation %q", relationKey(endpoints))
	switch len(endpoints) {
	case 1:
		if endpoints[0].RelationRole != RolePeer {
			return nil, fmt.Errorf("single endpoint must be a peer relation")
		}
	case 2:
		if !endpoints[0].CanRelateTo(&endpoints[1]) {
			return nil, fmt.Errorf("endpoints do not relate")
		}
	default:
		return nil, fmt.Errorf("cannot relate %d endpoints", len(endpoints))
	}

	var scope charm.RelationScope
	for _, v := range endpoints {
		if v.RelationScope == charm.ScopeContainer {
			scope = charm.ScopeContainer
		}
		// BUG(aram): potential race in the time between getting the service
		// to validate the endpoint and actually writting the relation
		// into MongoDB; the service might have disappeared.
		_, err = s.Service(v.ServiceName)
		if err != nil {
			return nil, err
		}
	}
	if scope == charm.ScopeContainer {
		for i := range endpoints {
			endpoints[i].RelationScope = scope
		}
	}
	id, err := s.sequence("relation")
	if err != nil {
		return nil, err
	}
	doc := relationDoc{
		Id:        id,
		Key:       relationKey(endpoints),
		Endpoints: endpoints,
		Life:      Alive,
	}
	err = s.relations.Insert(doc)
	if err != nil {
		return nil, err
	}
	return newRelation(s, &doc), nil
}

// Relation returns the existing relation with the given endpoints.
func (s *State) Relation(endpoints ...RelationEndpoint) (r *Relation, err error) {
	defer trivial.ErrorContextf(&err, "cannot get relation %q", relationKey(endpoints))

	doc := relationDoc{}
	err = s.relations.Find(bson.D{{"key", relationKey(endpoints)}}).One(&doc)
	if err != nil {
		return nil, err
	}
	return newRelation(s, &doc), nil
}

// RemoveRelation removes the supplied relation.
func (s *State) RemoveRelation(r *Relation) (err error) {
	defer trivial.ErrorContextf(&err, "cannot remove relation %q", r.doc.Key)

	if r.doc.Life != Dead {
		panic(fmt.Errorf("relation %q is not dead", r))
	}
	sel := bson.D{
		{"_id", r.doc.Id},
		{"life", Dead},
	}
	err = s.relations.Remove(sel)
	if err != nil {
		return err
	}
	return nil
}

// Unit returns a unit by name.
func (s *State) Unit(name string) (*Unit, error) {
	doc := unitDoc{}
	err := s.units.FindId(name).One(&doc)
	if err != nil {
		return nil, fmt.Errorf("cannot get unit %q: %v", name, err)
	}
	return newUnit(s, &doc), nil
}
<commit_msg>mstate: added/changed comments after review<commit_after>// The state package enables reading, observing, and changing
// the state stored in MongoDB of a whole environment
// managed by juju.
package mstate

import (
	"fmt"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"launchpad.net/juju-core/charm"
	"launchpad.net/juju-core/trivial"
	"launchpad.net/juju-core/version"
	"net/url"
)

// Tools describes a particular set of juju tools and where to find them.
type Tools struct {
	version.Binary
	URL string
}

// State represents the state of an environment
// managed by juju.
type State struct {
	db        *mgo.Database
	cfgnodes  *mgo.Collection
	charms    *mgo.Collection
	machines  *mgo.Collection
	relations *mgo.Collection
	services  *mgo.Collection
	units     *mgo.Collection
}

// AddMachine creates a new machine state.
func (s *State) AddMachine() (m *Machine, err error) {
	defer trivial.ErrorContextf(&err, "cannot add a new machine")
	id, err := s.sequence("machine")
	if err != nil {
		return nil, err
	}
	mdoc := machineDoc{
		Id:   id,
		Life: Alive,
	}
	err = s.machines.Insert(mdoc)
	if err != nil {
		return nil, err
	}
	return newMachine(s, &mdoc), nil
}

// RemoveMachine removes the machine with the the given id.
func (s *State) RemoveMachine(id int) error {
	sel := bson.D{{"_id", id}, {"life", Alive}}
	change := bson.D{{"$set", bson.D{{"life", Dying}}}}
	err := s.machines.Update(sel, change)
	if err != nil {
		return fmt.Errorf("cannot remove machine %d: %v", id, err)
	}
	return nil
}

// AllMachines returns all machines in the environment.
func (s *State) AllMachines() (machines []*Machine, err error) {
	mdocs := []machineDoc{}
	sel := bson.D{{"life", Alive}}
	err = s.machines.Find(sel).Select(bson.D{{"_id", 1}}).All(&mdocs)
	if err != nil {
		return nil, fmt.Errorf("cannot get all machines: %v", err)
	}
	for _, doc := range mdocs {
		machines = append(machines, newMachine(s, &doc))
	}
	return
}

// Machine returns the machine with the given id.
func (s *State) Machine(id int) (*Machine, error) {
	mdoc := &machineDoc{}
	sel := bson.D{{"_id", id}, {"life", Alive}}
	err := s.machines.Find(sel).One(mdoc)
	if err != nil {
		return nil, fmt.Errorf("cannot get machine %d: %v", id, err)
	}
	return newMachine(s, mdoc), nil
}

// AddCharm adds the ch charm with curl to the state.  bundleUrl must be
// set to a URL where the bundle for ch may be downloaded from.
// On success the newly added charm state is returned.
func (s *State) AddCharm(ch charm.Charm, curl *charm.URL, bundleURL *url.URL, bundleSha256 string) (stch *Charm, err error) {
	cdoc := &charmDoc{
		URL:          curl,
		Meta:         ch.Meta(),
		Config:       ch.Config(),
		BundleURL:    bundleURL,
		BundleSha256: bundleSha256,
	}
	err = s.charms.Insert(cdoc)
	if err != nil {
		return nil, fmt.Errorf("cannot add charm %q: %v", curl, err)
	}
	return newCharm(s, cdoc)
}

// Charm returns the charm with the given URL.
func (s *State) Charm(curl *charm.URL) (*Charm, error) {
	cdoc := &charmDoc{}
	err := s.charms.Find(bson.D{{"_id", curl}}).One(cdoc)
	if err != nil {
		return nil, fmt.Errorf("cannot get charm %q: %v", curl, err)
	}

	return newCharm(s, cdoc)
}

// AddService creates a new service state with the given unique name
// and the charm state.
func (s *State) AddService(name string, ch *Charm) (service *Service, err error) {
	sdoc := serviceDoc{
		Name:     name,
		CharmURL: ch.URL(),
		Life:     Alive,
	}
	err = s.services.Insert(sdoc)
	if err != nil {
		return nil, fmt.Errorf("cannot add service %q:", name, err)
	}
	return &Service{st: s, doc: sdoc}, nil
}

// RemoveService removes a service from the state. It will also remove all
// its units and break any of its existing relations.
func (s *State) RemoveService(svc *Service) (err error) {
	// TODO Integrate with txn and do lifecycle properly.
	defer trivial.ErrorContextf(&err, "cannot remove service %q", svc)

	if svc.doc.Life != Dead {
		panic(fmt.Errorf("service %q is not dead", svc))
	}
	// Remove relations first, to minimize unwanted hook executions.
	rels, err := svc.Relations()
	if err != nil {
		return err
	}
	for _, rel := range rels {
		err = rel.Die()
		if err != nil {
			return err
		}
		err = s.RemoveRelation(rel)
		if err != nil {
			return err
		}
	}
	// TODO Will be deleted with proper lifecycle integration.
	units, err := svc.AllUnits()
	if err != nil {
		return err
	}
	for _, unit := range units {
		err = unit.Die()
		if err != nil {
			return err
		}
		if err = svc.RemoveUnit(unit); err != nil {
			return err
		}
	}
	// Remove the service.
	sel := bson.D{
		{"_id", svc.doc.Name},
		{"life", Dead},
	}
	err = s.services.Remove(sel)
	if err != nil {
		return err
	}
	return nil
}

// Service returns a service state by name.
func (s *State) Service(name string) (service *Service, err error) {
	sdoc := serviceDoc{}
	sel := bson.D{{"_id", name}}
	err = s.services.Find(sel).One(&sdoc)
	if err != nil {
		return nil, fmt.Errorf("cannot get service %q: %v", name, err)
	}
	return &Service{st: s, doc: sdoc}, nil
}

// AllServices returns all deployed services in the environment.
func (s *State) AllServices() (services []*Service, err error) {
	sdocs := []serviceDoc{}
	err = s.services.Find(bson.D{}).All(&sdocs)
	if err != nil {
		return nil, fmt.Errorf("cannot get all services")
	}
	for _, v := range sdocs {
		services = append(services, &Service{st: s, doc: v})
	}
	return services, nil
}

// AddRelation creates a new relation with the given endpoints.
func (s *State) AddRelation(endpoints ...RelationEndpoint) (r *Relation, err error) {
	defer trivial.ErrorContextf(&err, "cannot add relation %q", relationKey(endpoints))
	switch len(endpoints) {
	case 1:
		if endpoints[0].RelationRole != RolePeer {
			return nil, fmt.Errorf("single endpoint must be a peer relation")
		}
	case 2:
		if !endpoints[0].CanRelateTo(&endpoints[1]) {
			return nil, fmt.Errorf("endpoints do not relate")
		}
	default:
		return nil, fmt.Errorf("cannot relate %d endpoints", len(endpoints))
	}

	var scope charm.RelationScope
	for _, v := range endpoints {
		if v.RelationScope == charm.ScopeContainer {
			scope = charm.ScopeContainer
		}
		// BUG(aram): potential race in the time between getting the service
		// to validate the endpoint and actually writting the relation
		// into MongoDB; the service might have disappeared.
		_, err = s.Service(v.ServiceName)
		if err != nil {
			return nil, err
		}
	}
	if scope == charm.ScopeContainer {
		for i := range endpoints {
			endpoints[i].RelationScope = scope
		}
	}
	id, err := s.sequence("relation")
	if err != nil {
		return nil, err
	}
	doc := relationDoc{
		Id:        id,
		Key:       relationKey(endpoints),
		Endpoints: endpoints,
		Life:      Alive,
	}
	err = s.relations.Insert(doc)
	if err != nil {
		return nil, err
	}
	return newRelation(s, &doc), nil
}

// Relation returns the existing relation with the given endpoints.
func (s *State) Relation(endpoints ...RelationEndpoint) (r *Relation, err error) {
	defer trivial.ErrorContextf(&err, "cannot get relation %q", relationKey(endpoints))

	doc := relationDoc{}
	err = s.relations.Find(bson.D{{"key", relationKey(endpoints)}}).One(&doc)
	if err != nil {
		return nil, err
	}
	return newRelation(s, &doc), nil
}

// RemoveRelation removes the supplied relation.
func (s *State) RemoveRelation(r *Relation) (err error) {
	defer trivial.ErrorContextf(&err, "cannot remove relation %q", r.doc.Key)

	if r.doc.Life != Dead {
		panic(fmt.Errorf("relation %q is not dead", r))
	}
	sel := bson.D{
		{"_id", r.doc.Id},
		{"life", Dead},
	}
	err = s.relations.Remove(sel)
	if err != nil {
		return err
	}
	return nil
}

// Unit returns a unit by name.
func (s *State) Unit(name string) (*Unit, error) {
	doc := unitDoc{}
	err := s.units.FindId(name).One(&doc)
	if err != nil {
		return nil, fmt.Errorf("cannot get unit %q: %v", name, err)
	}
	return newUnit(s, &doc), nil
}
<|endoftext|>