<commit_before>package client

import (
	"fmt"
	"html/template"
	"net/url"

	"sourcegraph.com/sourcegraph/api_router"
	"sourcegraph.com/sourcegraph/srcgraph/authorship"
	"sourcegraph.com/sourcegraph/srcgraph/graph"
	"sourcegraph.com/sourcegraph/srcgraph/person"
	"sourcegraph.com/sourcegraph/srcgraph/repo"
)

type SymbolsService interface {
	Get(symbol SymbolSpec, opt *GetSymbolOptions) (*Symbol, *Response, error)
	List(opt *SymbolListOptions) ([]*Symbol, *Response, error)
	ListExamples(symbol SymbolSpec, opt *SymbolExampleListOptions) ([]*Example, *Response, error)
	ListAuthors(symbol SymbolSpec, opt *SymbolAuthorListOptions) ([]*AugmentedSymbolAuthor, *Response, error)
	ListClients(symbol SymbolSpec, opt *SymbolClientListOptions) ([]*AugmentedSymbolClient, *Response, error)
	ListDependentRepositories(symbol SymbolSpec, opt *SymbolDependentRepositoryListOptions) ([]*AugmentedRepoRef, *Response, error)
	ListImplementations(symbol SymbolSpec, opt *SymbolListImplementationsOptions) ([]*Symbol, *Response, error)
	ListInterfaces(symbol SymbolSpec, opt *SymbolListInterfacesOptions) ([]*Symbol, *Response, error)
	CountByRepository(repo RepositorySpec) (*graph.SymbolCounts, *Response, error)
}

type SymbolSpec struct {
	SID int64

	Repo     string
	UnitType string
	Unit     string
	Path     string
}

func (s *SymbolSpec) SymbolKey() graph.SymbolKey {
	return graph.SymbolKey{
		Repo:     repo.URI(s.Repo),
		UnitType: s.UnitType,
		Unit:     s.Unit,
		Path:     graph.SymbolPath(s.Path),
	}
}

func NewSymbolSpecFromSymbolKey(key graph.SymbolKey) SymbolSpec {
	return SymbolSpec{
		Repo:     string(key.Repo),
		UnitType: key.UnitType,
		Unit:     key.Unit,
		Path:     string(key.Path),
	}
}

type symbolsService struct {
	client *Client
}

var _ SymbolsService = &symbolsService{}

type Symbol struct {
	graph.Symbol

	Stat map[graph.StatType]int `json:",omitempty"`

	Doc      string           `json:",omitempty"`
	DefHTML  template.HTML    `json:",omitempty"`
	DocPages []*graph.DocPage `json:",omitempty"`
}

func (s *Symbol) XRefs() int     { return s.Stat["xrefs"] }
func (s *Symbol) RRefs() int     { return s.Stat["rrefs"] }
func (s *Symbol) URefs() int     { return s.Stat["urefs"] }
func (s *Symbol) TotalRefs() int { return s.XRefs() + s.RRefs() + s.URefs() }

type GetSymbolOptions struct {
	Annotate bool `url:",omitempty"`
	DocPages bool `url:",omitempty"`
}

func (s *symbolsService) Get(symbol SymbolSpec, opt *GetSymbolOptions) (*Symbol, *Response, error) {
	var url *url.URL
	var err error
	if symbol.SID != 0 {
		url, err = s.client.url(api_router.SymbolBySID, map[string]string{"SID": fmt.Sprintf("%d", symbol.SID)}, opt)
	} else {
		url, err = s.client.url(api_router.Symbol, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	}
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var symbol_ *Symbol
	resp, err := s.client.Do(req, &symbol_)
	if err != nil {
		return nil, resp, err
	}

	return symbol_, resp, nil
}

type SymbolListOptions struct {
	RepositoryURI string `url:",omitempty"`
	Query         string `url:",omitempty"`

	Sort      string `url:",omitempty"`
	Direction string `url:",omitempty"`

	Kinds        []string `url:",omitempty,comma"`
	SpecificKind string   `url:",omitempty"`

	Scope     string `url:",omitempty"`
	Recursive bool   `url:",omitempty"`
	Exported  bool   `url:",omitempty"`
	Doc       bool   `url:",omitempty"`

	ListOptions
}

func (s *symbolsService) List(opt *SymbolListOptions) ([]*Symbol, *Response, error) {
	url, err := s.client.url(api_router.Symbols, nil, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var symbols []*Symbol
	resp, err := s.client.Do(req, &symbols)
	if err != nil {
		return nil, resp, err
	}

	return symbols, resp, nil
}

type Example struct {
	graph.Ref
	SrcHTML template.HTML
}

type Examples []*Example

func (r *Example) sortKey() string     { return fmt.Sprintf("%+v", r) }
func (vs Examples) Len() int           { return len(vs) }
func (vs Examples) Swap(i, j int)      { vs[i], vs[j] = vs[j], vs[i] }
func (vs Examples) Less(i, j int) bool { return vs[i].sortKey() < vs[j].sortKey() }

type SymbolExampleListOptions struct {
	Annotate bool

	ListOptions
}

func (s *symbolsService) ListExamples(symbol SymbolSpec, opt *SymbolExampleListOptions) ([]*Example, *Response, error) {
	url, err := s.client.url(api_router.SymbolExamples, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var examples []*Example
	resp, err := s.client.Do(req, &examples)
	if err != nil {
		return nil, resp, err
	}

	return examples, resp, nil
}

type AugmentedSymbolAuthor struct {
	User *person.User
	*authorship.SymbolAuthor
}

type SymbolAuthorListOptions struct {
	ListOptions
}

func (s *symbolsService) ListAuthors(symbol SymbolSpec, opt *SymbolAuthorListOptions) ([]*AugmentedSymbolAuthor, *Response, error) {
	url, err := s.client.url(api_router.SymbolAuthors, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var authors []*AugmentedSymbolAuthor
	resp, err := s.client.Do(req, &authors)
	if err != nil {
		return nil, resp, err
	}

	return authors, resp, nil
}

type AugmentedSymbolClient struct {
	User *person.User
	*authorship.SymbolClient
}

type SymbolClientListOptions struct {
	ListOptions
}

func (s *symbolsService) ListClients(symbol SymbolSpec, opt *SymbolClientListOptions) ([]*AugmentedSymbolClient, *Response, error) {
	url, err := s.client.url(api_router.SymbolClients, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var clients []*AugmentedSymbolClient
	resp, err := s.client.Do(req, &clients)
	if err != nil {
		return nil, resp, err
	}

	return clients, resp, nil
}

type AugmentedRepoRef struct {
	Repo  *repo.Repository
	Count int
}

type SymbolDependentRepositoryListOptions struct {
	ListOptions
}

func (s *symbolsService) ListDependentRepositories(symbol SymbolSpec, opt *SymbolDependentRepositoryListOptions) ([]*AugmentedRepoRef, *Response, error) {
	url, err := s.client.url(api_router.SymbolDependents, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var dependents []*AugmentedRepoRef
	resp, err := s.client.Do(req, &dependents)
	if err != nil {
		return nil, resp, err
	}

	return dependents, resp, nil
}

type SymbolListImplementationsOptions struct {
	ListOptions
}

func (s *symbolsService) ListImplementations(symbol SymbolSpec, opt *SymbolListImplementationsOptions) ([]*Symbol, *Response, error) {
	url, err := s.client.url(api_router.SymbolImplementations, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var symbols []*Symbol
	resp, err := s.client.Do(req, &symbols)
	if err != nil {
		return nil, resp, err
	}

	return symbols, resp, nil
}

type SymbolListInterfacesOptions struct {
	ListOptions
}

func (s *symbolsService) ListInterfaces(symbol SymbolSpec, opt *SymbolListInterfacesOptions) ([]*Symbol, *Response, error) {
	url, err := s.client.url(api_router.SymbolInterfaces, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var symbols []*Symbol
	resp, err := s.client.Do(req, &symbols)
	if err != nil {
		return nil, resp, err
	}

	return symbols, resp, nil
}

func (s *symbolsService) CountByRepository(repo RepositorySpec) (*graph.SymbolCounts, *Response, error) {
	url, err := s.client.url(api_router.RepositorySymbolCounts, map[string]string{"RepoURI": repo.URI}, nil)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var counts *graph.SymbolCounts
	resp, err := s.client.Do(req, &counts)
	if err != nil {
		return nil, resp, err
	}

	return counts, resp, nil
}

type MockSymbolsService struct {
	Get_                       func(symbol SymbolSpec, opt *GetSymbolOptions) (*Symbol, *Response, error)
	List_                      func(opt *SymbolListOptions) ([]*Symbol, *Response, error)
	ListExamples_              func(symbol SymbolSpec, opt *SymbolExampleListOptions) ([]*Example, *Response, error)
	ListAuthors_               func(symbol SymbolSpec, opt *SymbolAuthorListOptions) ([]*AugmentedSymbolAuthor, *Response, error)
	ListClients_               func(symbol SymbolSpec, opt *SymbolClientListOptions) ([]*AugmentedSymbolClient, *Response, error)
	ListDependentRepositories_ func(symbol SymbolSpec, opt *SymbolDependentRepositoryListOptions) ([]*AugmentedRepoRef, *Response, error)
	ListImplementations_       func(symbol SymbolSpec, opt *SymbolListImplementationsOptions) ([]*Symbol, *Response, error)
	ListInterfaces_            func(symbol SymbolSpec, opt *SymbolListInterfacesOptions) ([]*Symbol, *Response, error)
	CountByRepository_         func(repo RepositorySpec) (*graph.SymbolCounts, *Response, error)
}

var _ SymbolsService = MockSymbolsService{}

func (s MockSymbolsService) Get(symbol SymbolSpec, opt *GetSymbolOptions) (*Symbol, *Response, error) {
	if s.Get_ == nil {
		return nil, &Response{}, nil
	}
	return s.Get_(symbol, opt)
}

func (s MockSymbolsService) List(opt *SymbolListOptions) ([]*Symbol, *Response, error) {
	if s.List_ == nil {
		return nil, &Response{}, nil
	}
	return s.List_(opt)
}

func (s MockSymbolsService) ListExamples(symbol SymbolSpec, opt *SymbolExampleListOptions) ([]*Example, *Response, error) {
	if s.ListExamples_ == nil {
		return nil, &Response{}, nil
	}
	return s.ListExamples_(symbol, opt)
}

func (s MockSymbolsService) ListAuthors(symbol SymbolSpec, opt *SymbolAuthorListOptions) ([]*AugmentedSymbolAuthor, *Response, error) {
	if s.ListAuthors_ == nil {
		return nil, &Response{}, nil
	}
	return s.ListAuthors_(symbol, opt)
}

func (s MockSymbolsService) ListClients(symbol SymbolSpec, opt *SymbolClientListOptions) ([]*AugmentedSymbolClient, *Response, error) {
	if s.ListClients_ == nil {
		return nil, &Response{}, nil
	}
	return s.ListClients_(symbol, opt)
}

func (s MockSymbolsService) ListDependentRepositories(symbol SymbolSpec, opt *SymbolDependentRepositoryListOptions) ([]*AugmentedRepoRef, *Response, error) {
	if s.ListDependentRepositories_ == nil {
		return nil, &Response{}, nil
	}
	return s.ListDependentRepositories_(symbol, opt)
}

func (s MockSymbolsService) ListImplementations(symbol SymbolSpec, opt *SymbolListImplementationsOptions) ([]*Symbol, *Response, error) {
	if s.ListImplementations_ == nil {
		return nil, &Response{}, nil
	}
	return s.ListImplementations_(symbol, opt)
}

func (s MockSymbolsService) ListInterfaces(symbol SymbolSpec, opt *SymbolListInterfacesOptions) ([]*Symbol, *Response, error) {
	if s.ListInterfaces_ == nil {
		return nil, &Response{}, nil
	}
	return s.ListInterfaces_(symbol, opt)
}

func (s MockSymbolsService) CountByRepository(repo RepositorySpec) (*graph.SymbolCounts, *Response, error) {
	if s.CountByRepository_ == nil {
		return &graph.SymbolCounts{}, &Response{}, nil
	}
	return s.CountByRepository_(repo)
}
<commit_msg>SymbolSpec method<commit_after>package client

import (
	"fmt"
	"html/template"
	"net/url"

	"sourcegraph.com/sourcegraph/api_router"
	"sourcegraph.com/sourcegraph/srcgraph/authorship"
	"sourcegraph.com/sourcegraph/srcgraph/graph"
	"sourcegraph.com/sourcegraph/srcgraph/person"
	"sourcegraph.com/sourcegraph/srcgraph/repo"
)

type SymbolsService interface {
	Get(symbol SymbolSpec, opt *GetSymbolOptions) (*Symbol, *Response, error)
	List(opt *SymbolListOptions) ([]*Symbol, *Response, error)
	ListExamples(symbol SymbolSpec, opt *SymbolExampleListOptions) ([]*Example, *Response, error)
	ListAuthors(symbol SymbolSpec, opt *SymbolAuthorListOptions) ([]*AugmentedSymbolAuthor, *Response, error)
	ListClients(symbol SymbolSpec, opt *SymbolClientListOptions) ([]*AugmentedSymbolClient, *Response, error)
	ListDependentRepositories(symbol SymbolSpec, opt *SymbolDependentRepositoryListOptions) ([]*AugmentedRepoRef, *Response, error)
	ListImplementations(symbol SymbolSpec, opt *SymbolListImplementationsOptions) ([]*Symbol, *Response, error)
	ListInterfaces(symbol SymbolSpec, opt *SymbolListInterfacesOptions) ([]*Symbol, *Response, error)
	CountByRepository(repo RepositorySpec) (*graph.SymbolCounts, *Response, error)
}

type SymbolSpec struct {
	SID int64

	Repo     string
	UnitType string
	Unit     string
	Path     string
}

func (s *SymbolSpec) SymbolKey() graph.SymbolKey {
	return graph.SymbolKey{
		Repo:     repo.URI(s.Repo),
		UnitType: s.UnitType,
		Unit:     s.Unit,
		Path:     graph.SymbolPath(s.Path),
	}
}

func NewSymbolSpecFromSymbolKey(key graph.SymbolKey) SymbolSpec {
	return SymbolSpec{
		Repo:     string(key.Repo),
		UnitType: key.UnitType,
		Unit:     key.Unit,
		Path:     string(key.Path),
	}
}

type symbolsService struct {
	client *Client
}

var _ SymbolsService = &symbolsService{}

type Symbol struct {
	graph.Symbol

	Stat map[graph.StatType]int `json:",omitempty"`

	Doc      string           `json:",omitempty"`
	DefHTML  template.HTML    `json:",omitempty"`
	DocPages []*graph.DocPage `json:",omitempty"`
}

func (s *Symbol) SymbolSpec() SymbolSpec {
	spec := NewSymbolSpecFromSymbolKey(s.Symbol.SymbolKey)
	spec.SID = int64(s.Symbol.SID)
	return spec
}

func (s *Symbol) XRefs() int     { return s.Stat["xrefs"] }
func (s *Symbol) RRefs() int     { return s.Stat["rrefs"] }
func (s *Symbol) URefs() int     { return s.Stat["urefs"] }
func (s *Symbol) TotalRefs() int { return s.XRefs() + s.RRefs() + s.URefs() }

type GetSymbolOptions struct {
	Annotate bool `url:",omitempty"`
	DocPages bool `url:",omitempty"`
}

func (s *symbolsService) Get(symbol SymbolSpec, opt *GetSymbolOptions) (*Symbol, *Response, error) {
	var url *url.URL
	var err error
	if symbol.SID != 0 {
		url, err = s.client.url(api_router.SymbolBySID, map[string]string{"SID": fmt.Sprintf("%d", symbol.SID)}, opt)
	} else {
		url, err = s.client.url(api_router.Symbol, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	}
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var symbol_ *Symbol
	resp, err := s.client.Do(req, &symbol_)
	if err != nil {
		return nil, resp, err
	}

	return symbol_, resp, nil
}

type SymbolListOptions struct {
	RepositoryURI string `url:",omitempty"`
	Query         string `url:",omitempty"`

	Sort      string `url:",omitempty"`
	Direction string `url:",omitempty"`

	Kinds        []string `url:",omitempty,comma"`
	SpecificKind string   `url:",omitempty"`

	Scope     string `url:",omitempty"`
	Recursive bool   `url:",omitempty"`
	Exported  bool   `url:",omitempty"`
	Doc       bool   `url:",omitempty"`

	ListOptions
}

func (s *symbolsService) List(opt *SymbolListOptions) ([]*Symbol, *Response, error) {
	url, err := s.client.url(api_router.Symbols, nil, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var symbols []*Symbol
	resp, err := s.client.Do(req, &symbols)
	if err != nil {
		return nil, resp, err
	}

	return symbols, resp, nil
}

type Example struct {
	graph.Ref
	SrcHTML template.HTML
}

type Examples []*Example

func (r *Example) sortKey() string     { return fmt.Sprintf("%+v", r) }
func (vs Examples) Len() int           { return len(vs) }
func (vs Examples) Swap(i, j int)      { vs[i], vs[j] = vs[j], vs[i] }
func (vs Examples) Less(i, j int) bool { return vs[i].sortKey() < vs[j].sortKey() }

type SymbolExampleListOptions struct {
	Annotate bool

	ListOptions
}

func (s *symbolsService) ListExamples(symbol SymbolSpec, opt *SymbolExampleListOptions) ([]*Example, *Response, error) {
	url, err := s.client.url(api_router.SymbolExamples, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var examples []*Example
	resp, err := s.client.Do(req, &examples)
	if err != nil {
		return nil, resp, err
	}

	return examples, resp, nil
}

type AugmentedSymbolAuthor struct {
	User *person.User
	*authorship.SymbolAuthor
}

type SymbolAuthorListOptions struct {
	ListOptions
}

func (s *symbolsService) ListAuthors(symbol SymbolSpec, opt *SymbolAuthorListOptions) ([]*AugmentedSymbolAuthor, *Response, error) {
	url, err := s.client.url(api_router.SymbolAuthors, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var authors []*AugmentedSymbolAuthor
	resp, err := s.client.Do(req, &authors)
	if err != nil {
		return nil, resp, err
	}

	return authors, resp, nil
}

type AugmentedSymbolClient struct {
	User *person.User
	*authorship.SymbolClient
}

type SymbolClientListOptions struct {
	ListOptions
}

func (s *symbolsService) ListClients(symbol SymbolSpec, opt *SymbolClientListOptions) ([]*AugmentedSymbolClient, *Response, error) {
	url, err := s.client.url(api_router.SymbolClients, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var clients []*AugmentedSymbolClient
	resp, err := s.client.Do(req, &clients)
	if err != nil {
		return nil, resp, err
	}

	return clients, resp, nil
}

type AugmentedRepoRef struct {
	Repo  *repo.Repository
	Count int
}

type SymbolDependentRepositoryListOptions struct {
	ListOptions
}

func (s *symbolsService) ListDependentRepositories(symbol SymbolSpec, opt *SymbolDependentRepositoryListOptions) ([]*AugmentedRepoRef, *Response, error) {
	url, err := s.client.url(api_router.SymbolDependents, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var dependents []*AugmentedRepoRef
	resp, err := s.client.Do(req, &dependents)
	if err != nil {
		return nil, resp, err
	}

	return dependents, resp, nil
}

type SymbolListImplementationsOptions struct {
	ListOptions
}

func (s *symbolsService) ListImplementations(symbol SymbolSpec, opt *SymbolListImplementationsOptions) ([]*Symbol, *Response, error) {
	url, err := s.client.url(api_router.SymbolImplementations, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var symbols []*Symbol
	resp, err := s.client.Do(req, &symbols)
	if err != nil {
		return nil, resp, err
	}

	return symbols, resp, nil
}

type SymbolListInterfacesOptions struct {
	ListOptions
}

func (s *symbolsService) ListInterfaces(symbol SymbolSpec, opt *SymbolListInterfacesOptions) ([]*Symbol, *Response, error) {
	url, err := s.client.url(api_router.SymbolInterfaces, map[string]string{"RepoURI": symbol.Repo, "UnitType": symbol.UnitType, "Unit": symbol.Unit, "Path": symbol.Path}, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var symbols []*Symbol
	resp, err := s.client.Do(req, &symbols)
	if err != nil {
		return nil, resp, err
	}

	return symbols, resp, nil
}

func (s *symbolsService) CountByRepository(repo RepositorySpec) (*graph.SymbolCounts, *Response, error) {
	url, err := s.client.url(api_router.RepositorySymbolCounts, map[string]string{"RepoURI": repo.URI}, nil)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", url.String(), nil)
	if err != nil {
		return nil, nil, err
	}

	var counts *graph.SymbolCounts
	resp, err := s.client.Do(req, &counts)
	if err != nil {
		return nil, resp, err
	}

	return counts, resp, nil
}

type MockSymbolsService struct {
	Get_                       func(symbol SymbolSpec, opt *GetSymbolOptions) (*Symbol, *Response, error)
	List_                      func(opt *SymbolListOptions) ([]*Symbol, *Response, error)
	ListExamples_              func(symbol SymbolSpec, opt *SymbolExampleListOptions) ([]*Example, *Response, error)
	ListAuthors_               func(symbol SymbolSpec, opt *SymbolAuthorListOptions) ([]*AugmentedSymbolAuthor, *Response, error)
	ListClients_               func(symbol SymbolSpec, opt *SymbolClientListOptions) ([]*AugmentedSymbolClient, *Response, error)
	ListDependentRepositories_ func(symbol SymbolSpec, opt *SymbolDependentRepositoryListOptions) ([]*AugmentedRepoRef, *Response, error)
	ListImplementations_       func(symbol SymbolSpec, opt *SymbolListImplementationsOptions) ([]*Symbol, *Response, error)
	ListInterfaces_            func(symbol SymbolSpec, opt *SymbolListInterfacesOptions) ([]*Symbol, *Response, error)
	CountByRepository_         func(repo RepositorySpec) (*graph.SymbolCounts, *Response, error)
}

var _ SymbolsService = MockSymbolsService{}

func (s MockSymbolsService) Get(symbol SymbolSpec, opt *GetSymbolOptions) (*Symbol, *Response, error) {
	if s.Get_ == nil {
		return nil, &Response{}, nil
	}
	return s.Get_(symbol, opt)
}

func (s MockSymbolsService) List(opt *SymbolListOptions) ([]*Symbol, *Response, error) {
	if s.List_ == nil {
		return nil, &Response{}, nil
	}
	return s.List_(opt)
}

func (s MockSymbolsService) ListExamples(symbol SymbolSpec, opt *SymbolExampleListOptions) ([]*Example, *Response, error) {
	if s.ListExamples_ == nil {
		return nil, &Response{}, nil
	}
	return s.ListExamples_(symbol, opt)
}

func (s MockSymbolsService) ListAuthors(symbol SymbolSpec, opt *SymbolAuthorListOptions) ([]*AugmentedSymbolAuthor, *Response, error) {
	if s.ListAuthors_ == nil {
		return nil, &Response{}, nil
	}
	return s.ListAuthors_(symbol, opt)
}

func (s MockSymbolsService) ListClients(symbol SymbolSpec, opt *SymbolClientListOptions) ([]*AugmentedSymbolClient, *Response, error) {
	if s.ListClients_ == nil {
		return nil, &Response{}, nil
	}
	return s.ListClients_(symbol, opt)
}

func (s MockSymbolsService) ListDependentRepositories(symbol SymbolSpec, opt *SymbolDependentRepositoryListOptions) ([]*AugmentedRepoRef, *Response, error) {
	if s.ListDependentRepositories_ == nil {
		return nil, &Response{}, nil
	}
	return s.ListDependentRepositories_(symbol, opt)
}

func (s MockSymbolsService) ListImplementations(symbol SymbolSpec, opt *SymbolListImplementationsOptions) ([]*Symbol, *Response, error) {
	if s.ListImplementations_ == nil {
		return nil, &Response{}, nil
	}
	return s.ListImplementations_(symbol, opt)
}

func (s MockSymbolsService) ListInterfaces(symbol SymbolSpec, opt *SymbolListInterfacesOptions) ([]*Symbol, *Response, error) {
	if s.ListInterfaces_ == nil {
		return nil, &Response{}, nil
	}
	return s.ListInterfaces_(symbol, opt)
}

func (s MockSymbolsService) CountByRepository(repo RepositorySpec) (*graph.SymbolCounts, *Response, error) {
	if s.CountByRepository_ == nil {
		return &graph.SymbolCounts{}, &Response{}, nil
	}
	return s.CountByRepository_(repo)
}
<|endoftext|>


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

// +build ignore

// This binary tests that PCAP packet capture is working correctly by issuing
// HTTP requests, then making sure we actually capture data off the wire.
package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"time"

	"github.com/google/gopacket/pcap"
)

var mode = flag.String("mode", "basic", "One of: basic,filtered,timestamp")

func generatePackets() {
	if resp, err := http.Get("http://code.google.com"); err != nil {
		log.Printf("Could not get HTTP: %v", err)
	} else {
		resp.Body.Close()
	}
}

func main() {
	flag.Parse()
	ifaces, err := net.Interfaces()
	if err != nil {
		log.Fatal(err)
	}
	for _, iface := range ifaces {
		log.Printf("Trying capture on %q", iface.Name)
		if err := tryCapture(iface); err != nil {
			log.Printf("Error capturing on %q: %v", iface.Name, err)
		} else {
			log.Printf("Successfully captured on %q", iface.Name)
			return
		}
	}
	os.Exit(1)
}

func tryCapture(iface net.Interface) error {
	if iface.Name[:2] == "lo" {
		return errors.New("skipping loopback")
	}
	var h *pcap.Handle
	var err error
	switch *mode {
	case "basic":
		h, err = pcap.OpenLive(iface.Name, 65536, false, time.Second*3)
		if err != nil {
			return fmt.Errorf("openlive: %v", err)
		}
		defer h.Close()
	case "filtered":
		h, err = pcap.OpenLive(iface.Name, 65536, false, time.Second*3)
		if err != nil {
			return fmt.Errorf("openlive: %v", err)
		}
		defer h.Close()
		if err := h.SetBPFFilter("port 80 or port 443"); err != nil {
			return fmt.Errorf("setbpf: %v", err)
		}
	case "timestamp":
		u, err := pcap.NewInactiveHandle(iface.Name)
		if err != nil {
			return err
		}
		defer u.CleanUp()
		if err = u.SetSnapLen(65536); err != nil {
			return err
		} else if err = u.SetPromisc(false); err != nil {
			return err
		} else if err = u.SetTimeout(time.Second * 3); err != nil {
			return err
		}
		sources := u.SupportedTimestamps()
		if len(sources) == 0 {
			return errors.New("no supported timestamp sources")
		} else if err := u.SetTimestampSource(sources[0]); err != nil {
			return fmt.Errorf("settimestampsource(%v): %v", sources[0], err)
		} else if h, err = u.Activate(); err != nil {
			return fmt.Errorf("could not activate: %v", err)
		}
		defer h.Close()
	default:
		panic("Invalid --mode: " + *mode)
	}
	go generatePackets()
	h.ReadPacketData() // Do one dummy read to clear any timeouts.
	data, ci, err := h.ReadPacketData()
	if err != nil {
		return fmt.Errorf("readpacketdata: %v", err)
	}
	log.Printf("Read packet, %v bytes, CI: %+v", len(data), ci)
	return nil
}
<commit_msg>Support windows in pcap_tester<commit_after>// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.

// +build ignore

// This binary tests that PCAP packet capture is working correctly by issuing
// HTTP requests, then making sure we actually capture data off the wire.
package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"time"

	"github.com/google/gopacket/pcap"
)

var mode = flag.String("mode", "basic", "One of: basic,filtered,timestamp")

func generatePackets() {
	if resp, err := http.Get("http://code.google.com"); err != nil {
		log.Printf("Could not get HTTP: %v", err)
	} else {
		resp.Body.Close()
	}
}

func main() {
	flag.Parse()
	ifaces, err := pcap.FindAllDevs()
	if err != nil {
		log.Fatal(err)
	}
	for _, iface := range ifaces {
		log.Printf("Trying capture on %q", iface.Name)
		if err := tryCapture(iface); err != nil {
			log.Printf("Error capturing on %q: %v", iface.Name, err)
		} else {
			log.Printf("Successfully captured on %q", iface.Name)
			return
		}
	}
	os.Exit(1)
}

func tryCapture(iface pcap.Interface) error {
	if iface.Name[:2] == "lo" {
		return errors.New("skipping loopback")
	}
	var h *pcap.Handle
	var err error
	switch *mode {
	case "basic":
		h, err = pcap.OpenLive(iface.Name, 65536, false, time.Second*3)
		if err != nil {
			return fmt.Errorf("openlive: %v", err)
		}
		defer h.Close()
	case "filtered":
		h, err = pcap.OpenLive(iface.Name, 65536, false, time.Second*3)
		if err != nil {
			return fmt.Errorf("openlive: %v", err)
		}
		defer h.Close()
		if err := h.SetBPFFilter("port 80 or port 443"); err != nil {
			return fmt.Errorf("setbpf: %v", err)
		}
	case "timestamp":
		u, err := pcap.NewInactiveHandle(iface.Name)
		if err != nil {
			return err
		}
		defer u.CleanUp()
		if err = u.SetSnapLen(65536); err != nil {
			return err
		} else if err = u.SetPromisc(false); err != nil {
			return err
		} else if err = u.SetTimeout(time.Second * 3); err != nil {
			return err
		}
		sources := u.SupportedTimestamps()
		if len(sources) == 0 {
			return errors.New("no supported timestamp sources")
		} else if err := u.SetTimestampSource(sources[0]); err != nil {
			return fmt.Errorf("settimestampsource(%v): %v", sources[0], err)
		} else if h, err = u.Activate(); err != nil {
			return fmt.Errorf("could not activate: %v", err)
		}
		defer h.Close()
	default:
		panic("Invalid --mode: " + *mode)
	}
	go generatePackets()
	h.ReadPacketData() // Do one dummy read to clear any timeouts.
	data, ci, err := h.ReadPacketData()
	if err != nil {
		return fmt.Errorf("readpacketdata: %v", err)
	}
	log.Printf("Read packet, %v bytes, CI: %+v", len(data), ci)
	return nil
}
<|endoftext|>


<commit_before>package cf_http_test

import (
	"net/http"
	"time"

	cf_http "github.com/cloudfoundry-incubator/cf-http"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("CfHttp", func() {
	Describe("NewClient", func() {
		Context("when a default timeout has been initialized", func() {
			var timeout time.Duration

			BeforeEach(func() {
				timeout = 1 * time.Second
				cf_http.Initialize(timeout)
			})

			It("returns an http client with the default timeout set", func() {
				Ω(*cf_http.NewClient()).Should(Equal(http.Client{
					Timeout: timeout,
				}))
			})
		})

		Context("when nothing has been initialized", func() {
			It("returns a DefaultClient-equivalent http client", func() {
				Ω(*cf_http.NewClient()).Should(Equal(*http.DefaultClient))
			})
		})
	})
})
<commit_msg>Fix import for cf_http<commit_after>package cf_http_test

import (
	"net/http"
	"time"

	"github.com/cloudfoundry-incubator/cf_http"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("CfHttp", func() {
	Describe("NewClient", func() {
		Context("when a default timeout has been initialized", func() {
			var timeout time.Duration

			BeforeEach(func() {
				timeout = 1 * time.Second
				cf_http.Initialize(timeout)
			})

			It("returns an http client with the default timeout set", func() {
				Ω(*cf_http.NewClient()).Should(Equal(http.Client{
					Timeout: timeout,
				}))
			})
		})

		Context("when nothing has been initialized", func() {
			It("returns a DefaultClient-equivalent http client", func() {
				Ω(*cf_http.NewClient()).Should(Equal(*http.DefaultClient))
			})
		})
	})
})
<|endoftext|>


<commit_before>package webhog

import (
	"log"
	"time"
)

// Entity is a representation of a webpage and it's corresponding
// UUID that's stored on AWS-S3
type Entity struct {
	Id        int       `json:"id"`
	UUID      string    `field:"uuid" json:"uuid"`
	Url       string    `json:"url"`
	AwsLink   string    `field:"aws_link" json:"aws_link"`
	Status    string    `json:"status"`
	CreatedAt time.Time `field:"created_at" json:"created_at"`
	UpdatedAt time.Time `field:"updated_at" json:"updated_at"`
}

// Find an Entity by UUID and return the AWS S3 link (or status if upload
// is incomplete) - create if it doesn't exist.
func (entity *Entity) Find(query string) (result *Entity) {
	rows, err := Connection.Db.Query("SELECT id,uuid,url,aws_link,status FROM entities WHERE url=? LIMIT 1", query)
	if err != nil {
		log.Println(err)
	}

	for rows.Next() {
		if err := rows.Scan(&entity.Id, &entity.UUID, &entity.Url, &entity.AwsLink, &entity.Status); err != nil {
			log.Println(err)
		}

		return entity
	}

	if err := rows.Err(); err != nil {
		log.Println(err)
	}

	return entity
}

// Create a new entity object in the database.
func (entity *Entity) Create() (result *Entity) {
	res, err := Connection.Db.Exec("INSERT INTO entities(uuid, url, status) VALUES(?, ?, ?)", entity.UUID, entity.Url, entity.Status)
	if err != nil {
		log.Println(err)
	}

	lastId, err := res.LastInsertId()
	if err != nil {
		log.Println("Error in lastId: ", err)
	}

	err = Connection.Db.QueryRow("SELECT id,uuid,url,status from entities where id=?", lastId).
		Scan(&entity.Id, &entity.UUID, &entity.Url, &entity.Status)
	if err != nil {
		log.Println("Error after queryrow: ", err)
	}

	return entity
}

func init() {
	// Register Entity as a Model.
	Register(&Entity{})
}
<commit_msg>check for null columns<commit_after>package webhog

import (
	"database/sql"
	"log"
	"time"
)

// Entity is a representation of a webpage and it's corresponding
// UUID that's stored on AWS-S3
type Entity struct {
	Id        int       `json:"id"`
	UUID      string    `field:"uuid" json:"uuid"`
	Url       string    `json:"url"`
	AwsLink   string    `field:"aws_link" json:"aws_link"`
	Status    string    `json:"status"`
	CreatedAt time.Time `field:"created_at" json:"created_at"`
	UpdatedAt time.Time `field:"updated_at" json:"updated_at"`
}

// Find an Entity by UUID and return the AWS S3 link (or status if upload
// is incomplete) - create if it doesn't exist.
func (entity *Entity) Find(query string) (result *Entity) {
	rows, err := Connection.Db.Query("SELECT id,uuid,url,aws_link,status FROM entities WHERE url=? LIMIT 1", query)
	if err != nil {
		log.Println("Query error in find: ", err)
	}

	for rows.Next() {
		var s sql.NullString
		if err := rows.Scan(&entity.Id, &entity.UUID, &entity.Url, &s, &entity.Status); err != nil {
			log.Println("Scan error in find: ", err)
		}

		// handling null strings with the sql driver is highly irritating
		if s.Valid {
			entity.AwsLink = s.String
		} else {
			entity.AwsLink = ""
		}

		return entity
	}

	if err := rows.Err(); err != nil {
		log.Println("Row error in find: ", err)
	}

	return entity
}

// Create a new entity object in the database.
func (entity *Entity) Create() (result *Entity) {
	res, err := Connection.Db.Exec("INSERT INTO entities(uuid, url, status) VALUES(?, ?, ?)", entity.UUID, entity.Url, entity.Status)
	if err != nil {
		log.Println("Error in exec: ", err)
	}

	lastId, err := res.LastInsertId()
	if err != nil {
		log.Println("Error in lastId: ", err)
	}

	err = Connection.Db.QueryRow("SELECT id,uuid,url,status from entities where id=?", lastId).
		Scan(&entity.Id, &entity.UUID, &entity.Url, &entity.Status)
	if err != nil {
		log.Println("Error after queryrow: ", err)
	}

	return entity
}

func init() {
	// Register Entity as a Model.
	Register(&Entity{})
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"reflect"
	"regexp"
	"strings"

	"github.com/spf13/cobra"

	"github.com/ovh/cds/cli"
	"github.com/ovh/cds/sdk"
)

var (
	workerModelCmd = cli.Command{
		Name:  "model",
		Short: "Manage Worker Model",
	}

	workerModel = cli.NewCommand(workerModelCmd, nil,
		[]*cobra.Command{
			cli.NewListCommand(workerModelListCmd, workerModelListRun, nil),
			cli.NewGetCommand(workerModelShowCmd, workerModelShowRun, nil, withAllCommandModifiers()...),
			cli.NewDeleteCommand(workerModelDeleteCmd, workerModelDeleteRun, nil),
			cli.NewCommand(workerModelAddCmd, workerModelAddRun, nil),
		})
)

var workerModelListCmd = cli.Command{
	Name:  "list",
	Short: "List CDS worker models",
}

func workerModelListRun(v cli.Values) (cli.ListResult, error) {
	workerModels, err := client.WorkerModels()
	if err != nil {
		return nil, err
	}
	return cli.AsListResult(workerModels), nil
}

var workerModelAddCmd = cli.Command{
	Name:  "add",
	Short: "cdsctl worker model add [name] [docker|openstack|vsphere] --group [group]",
	Long: `
Available model type :
- Docker images ("docker")
- Openstack image ("openstack")
- VSphere image ("vsphere")
	`,
	Args: []cli.Arg{
		{Name: "name"},
		{Name: "type"},
		{Name: "group"},
	},
	Flags: []cli.Flag{
		{
			Name:  "image",
			Kind:  reflect.String,
			Usage: "Image value",
		},
		{
			Name:  "flavor",
			Kind:  reflect.String,
			Usage: "Flavor value (only for openstack)",
		},
		{
			Name:  "userdata",
			Kind:  reflect.String,
			Usage: "Path to UserData file (only for vsphere or openstack)",
		},
	},
}

func workerModelAddRun(c cli.Values) error {
	name := c.GetString("name")
	modelType := c.GetString("type")
	groupName := c.GetString("group")
	userdata := c.GetString("userdata")

	var t string
	var image string
	switch modelType {
	case string(sdk.Docker):
		t = sdk.Docker
		image = c.GetString("image")
		if image == "" {
			sdk.Exit("Error: Docker image not provided (--image)\n")
		}
		break
	case string(sdk.Openstack):
		t = sdk.Openstack
		d := sdk.OpenstackModelData{
			Image:  c.GetString("image"),
			Flavor: c.GetString("flavor"),
		}
		if d.Image == "" {
			return fmt.Errorf("Error: Openstack image not provided (--image)")
		}
		if d.Flavor == "" {
			return fmt.Errorf("Error: Openstack flavor not provided (--flavor)")
		}
		if userdata == "" {
			return fmt.Errorf("Error: Openstack UserData file not provided (--userdata)")
		}
		file, err := ioutil.ReadFile(userdata)
		if err != nil {
			return fmt.Errorf("Error: Cannot read Openstack UserData file (%s)", err)
		}
		d.UserData = base64.StdEncoding.EncodeToString([]byte(file))
		data, err := json.Marshal(d)
		if err != nil {
			return fmt.Errorf("Error: Cannot marshal model info (%s)", err)
		}
		image = string(data)
		break
	case string(sdk.VSphere):
		t = sdk.VSphere
		d := sdk.OpenstackModelData{
			Image: c.GetString("image"),
		}
		if d.Image == "" {
			return fmt.Errorf("Error: VSphere image not provided (--image)")
		}

		if userdata == "" {
			return fmt.Errorf("Error: VSphere UserData file not provided (--userdata)")
		}
		file, err := ioutil.ReadFile(userdata)
		if err != nil {
			return fmt.Errorf("Error: Cannot read Openstack UserData file (%s)", err)
		}

		rx := regexp.MustCompile(`(?m)(#.*)$`)
		file = rx.ReplaceAll(file, []byte(""))
		d.UserData = strings.Replace(string(file), "\n", " ; ", -1)

		data, err := sdk.JSONWithoutHTMLEncode(d)
		if err != nil {
			return fmt.Errorf("Error: Cannot marshal model info (%s)", err)
		}
		image = string(data)
		break
	default:
		return fmt.Errorf("Unknown worker type: %s", modelType)
	}

	g, err := client.GroupGet(groupName)
	if err != nil {
		return fmt.Errorf("Error : Unable to get group %s : %s", groupName, err)
	}

	if _, err := client.WorkerModelAdd(name, t, image, g.ID); err != nil {
		return fmt.Errorf("Error: cannot add worker model (%s)", err)
	}

	fmt.Printf("Worker model %s added with success", name)
	return nil
}

var workerModelShowCmd = cli.Command{
	Name:  "show",
	Short: "Show a Worker Model",
	Args: []cli.Arg{
		{Name: "name"},
	},
}

func workerModelShowRun(v cli.Values) (interface{}, error) {
	wm, err := client.WorkerModel(v["name"])
	if err != nil {
		return nil, err
	}
	return wm, nil
}

var workerModelDeleteCmd = cli.Command{
	Name:    "delete",
	Short:   "Delete a CDS worker model",
	Example: `cdsctl worker model delete myModelA myModelB`,
	VariadicArgs: cli.Arg{
		Name: "name",
	},
}

func workerModelDeleteRun(v cli.Values) error {
	if err := client.WorkerModelDelete(v.GetString("name")); err != nil {
		if err.Error() == "worker model not found" && v.GetBool("force") {
			return nil
		}
		return err
	}
	return nil
}
<commit_msg>fix (cdsctl): check err on worker model delete (#2518)<commit_after>package main

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"reflect"
	"regexp"
	"strings"

	"github.com/spf13/cobra"

	"github.com/ovh/cds/cli"
	"github.com/ovh/cds/sdk"
)

var (
	workerModelCmd = cli.Command{
		Name:  "model",
		Short: "Manage Worker Model",
	}

	workerModel = cli.NewCommand(workerModelCmd, nil,
		[]*cobra.Command{
			cli.NewListCommand(workerModelListCmd, workerModelListRun, nil),
			cli.NewGetCommand(workerModelShowCmd, workerModelShowRun, nil, withAllCommandModifiers()...),
			cli.NewDeleteCommand(workerModelDeleteCmd, workerModelDeleteRun, nil),
			cli.NewCommand(workerModelAddCmd, workerModelAddRun, nil),
		})
)

var workerModelListCmd = cli.Command{
	Name:  "list",
	Short: "List CDS worker models",
}

func workerModelListRun(v cli.Values) (cli.ListResult, error) {
	workerModels, err := client.WorkerModels()
	if err != nil {
		return nil, err
	}
	return cli.AsListResult(workerModels), nil
}

var workerModelAddCmd = cli.Command{
	Name:  "add",
	Short: "cdsctl worker model add [name] [docker|openstack|vsphere] --group [group]",
	Long: `
Available model type :
- Docker images ("docker")
- Openstack image ("openstack")
- VSphere image ("vsphere")
	`,
	Args: []cli.Arg{
		{Name: "name"},
		{Name: "type"},
		{Name: "group"},
	},
	Flags: []cli.Flag{
		{
			Name:  "image",
			Kind:  reflect.String,
			Usage: "Image value",
		},
		{
			Name:  "flavor",
			Kind:  reflect.String,
			Usage: "Flavor value (only for openstack)",
		},
		{
			Name:  "userdata",
			Kind:  reflect.String,
			Usage: "Path to UserData file (only for vsphere or openstack)",
		},
	},
}

func workerModelAddRun(c cli.Values) error {
	name := c.GetString("name")
	modelType := c.GetString("type")
	groupName := c.GetString("group")
	userdata := c.GetString("userdata")

	var t string
	var image string
	switch modelType {
	case string(sdk.Docker):
		t = sdk.Docker
		image = c.GetString("image")
		if image == "" {
			sdk.Exit("Error: Docker image not provided (--image)\n")
		}
		break
	case string(sdk.Openstack):
		t = sdk.Openstack
		d := sdk.OpenstackModelData{
			Image:  c.GetString("image"),
			Flavor: c.GetString("flavor"),
		}
		if d.Image == "" {
			return fmt.Errorf("Error: Openstack image not provided (--image)")
		}
		if d.Flavor == "" {
			return fmt.Errorf("Error: Openstack flavor not provided (--flavor)")
		}
		if userdata == "" {
			return fmt.Errorf("Error: Openstack UserData file not provided (--userdata)")
		}
		file, err := ioutil.ReadFile(userdata)
		if err != nil {
			return fmt.Errorf("Error: Cannot read Openstack UserData file (%s)", err)
		}
		d.UserData = base64.StdEncoding.EncodeToString([]byte(file))
		data, err := json.Marshal(d)
		if err != nil {
			return fmt.Errorf("Error: Cannot marshal model info (%s)", err)
		}
		image = string(data)
		break
	case string(sdk.VSphere):
		t = sdk.VSphere
		d := sdk.OpenstackModelData{
			Image: c.GetString("image"),
		}
		if d.Image == "" {
			return fmt.Errorf("Error: VSphere image not provided (--image)")
		}

		if userdata == "" {
			return fmt.Errorf("Error: VSphere UserData file not provided (--userdata)")
		}
		file, err := ioutil.ReadFile(userdata)
		if err != nil {
			return fmt.Errorf("Error: Cannot read Openstack UserData file (%s)", err)
		}

		rx := regexp.MustCompile(`(?m)(#.*)$`)
		file = rx.ReplaceAll(file, []byte(""))
		d.UserData = strings.Replace(string(file), "\n", " ; ", -1)

		data, err := sdk.JSONWithoutHTMLEncode(d)
		if err != nil {
			return fmt.Errorf("Error: Cannot marshal model info (%s)", err)
		}
		image = string(data)
		break
	default:
		return fmt.Errorf("Unknown worker type: %s", modelType)
	}

	g, err := client.GroupGet(groupName)
	if err != nil {
		return fmt.Errorf("Error : Unable to get group %s : %s", groupName, err)
	}

	if _, err := client.WorkerModelAdd(name, t, image, g.ID); err != nil {
		return fmt.Errorf("Error: cannot add worker model (%s)", err)
	}

	fmt.Printf("Worker model %s added with success", name)
	return nil
}

var workerModelShowCmd = cli.Command{
	Name:  "show",
	Short: "Show a Worker Model",
	Args: []cli.Arg{
		{Name: "name"},
	},
}

func workerModelShowRun(v cli.Values) (interface{}, error) {
	wm, err := client.WorkerModel(v["name"])
	if err != nil {
		return nil, err
	}
	return wm, nil
}

var workerModelDeleteCmd = cli.Command{
	Name:    "delete",
	Short:   "Delete a CDS worker model",
	Example: `cdsctl worker model delete myModelA myModelB`,
	VariadicArgs: cli.Arg{
		Name: "name",
	},
}

func workerModelDeleteRun(v cli.Values) error {
	if err := client.WorkerModelDelete(v.GetString("name")); err != nil {
		if sdk.ErrorIs(err, sdk.ErrNoWorkerModel) && v.GetBool("force") {
			return nil
		}
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017 Google Inc.
 *
 * 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 stackdriver

import (
	"fmt"
	"math"
	"path"
	"strings"
	"sync"
	"time"

	"github.com/cloudfoundry-community/stackdriver-tools/src/stackdriver-nozzle/messages"
	"github.com/cloudfoundry/lager"
	"github.com/golang/protobuf/ptypes/timestamp"
	labelpb "google.golang.org/genproto/googleapis/api/label"
	metricpb "google.golang.org/genproto/googleapis/api/metric"
	monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3"
)

type MetricAdapter interface {
	PostMetricEvents([]*messages.MetricEvent) error
}

type Heartbeater interface {
	Start()
	Increment(string)
	IncrementBy(string, uint)
	Stop()
}

type metricAdapter struct {
	projectID             string
	client                MetricClient
	descriptors           map[string]struct{}
	createDescriptorMutex *sync.Mutex
	batchSize             int
	logger                lager.Logger
	heartbeater           Heartbeater
}

type postMetricErr struct {
	metricDescriptor []error
	postErrs         []error
	filteredErrs     []error
	heartbeater      Heartbeater
}

func (pme *postMetricErr) BuildError() error {
	pme.processErrors()
	if pme == nil || len(pme.filteredErrs) == 0 && len(pme.metricDescriptor) == 0 {
		return nil
	}

	return fmt.Errorf("PostMetricEvents, Unexpected Post Errors: %v, Metric Descriptor Errors: %v", pme.filteredErrs, pme.metricDescriptor)
}

func (pme *postMetricErr) AddPostError(err error) {
	pme.postErrs = append(pme.postErrs, err)
}

// Filter expected errors and record telemetry
func (pme *postMetricErr) processErrors() {
	if pme == nil || len(pme.postErrs) == 0 && len(pme.metricDescriptor) == 0 {
		return
	}

	for _, err := range pme.postErrs {
		pme.heartbeater.Increment("metrics.post.errors")

		// This is an expected error once there is more than a single nozzle writing to Stackdriver.
		// If one nozzle writes a metric occurring at time T2 and this one tries to write at T1 (where T2 later than T1)
		// we will receive this error.
		if strings.Contains(err.Error(), `Points must be written in order`) {
			pme.heartbeater.Increment("metrics.post.errors.out_of_order")
		} else {
			pme.heartbeater.Increment("metrics.post.errors.unknown")
			pme.filteredErrs = append(pme.filteredErrs, err)
		}
	}

	metricDescriptorErrs := len(pme.metricDescriptor)
	if metricDescriptorErrs > 0 {
		pme.heartbeater.IncrementBy("metrics.metric_descriptor.errors", uint(metricDescriptorErrs))
	}
}

// NewMetricAdapter returns a MetricAdapater that can write to Stackdriver Monitoring
func NewMetricAdapter(projectID string, client MetricClient, batchSize int, heartbeater Heartbeater, logger lager.Logger) (MetricAdapter, error) {
	ma := &metricAdapter{
		projectID:             projectID,
		client:                client,
		createDescriptorMutex: &sync.Mutex{},
		descriptors:           map[string]struct{}{},
		batchSize:             batchSize,
		logger:                logger,
		heartbeater:           heartbeater,
	}

	err := ma.fetchMetricDescriptorNames()
	return ma, err
}

func (ma *metricAdapter) PostMetricEvents(events []*messages.MetricEvent) error {
	series, postErr := ma.buildTimeSeries(events)
	projectName := path.Join("projects", ma.projectID)

	count := len(series)
	chunks := int(math.Ceil(float64(count) / float64(ma.batchSize)))

	ma.logger.Info("autoCulledMetricsBuffer", lager.Data{"info": fmt.Sprintf("%v metrics will be flushed in %v batches", count, chunks)})
	var low, high int
	for i := 0; i < chunks; i++ {
		low = i * ma.batchSize
		high = low + ma.batchSize
		// if we're at the last chunk, take the remaining size
		// so we don't over index
		if i == chunks-1 {
			high = count
		}

		ma.heartbeater.Increment("metrics.requests")
		err := ma.client.Post(&monitoringpb.CreateTimeSeriesRequest{
			Name:       projectName,
			TimeSeries: series[low:high],
		})

		if err != nil {
			postErr.AddPostError(err)
		}
	}

	return postErr.BuildError()
}

func (ma *metricAdapter) buildTimeSeries(events []*messages.MetricEvent) ([]*monitoringpb.TimeSeries, postMetricErr) {
	var timeSerieses []*monitoringpb.TimeSeries

	compositeErr := postMetricErr{heartbeater: ma.heartbeater}

	for _, event := range events {
		if len(event.Metrics) == 0 {
			continue
		}

		ma.heartbeater.Increment("metrics.events.count")
		for _, metric := range event.Metrics {
			ma.heartbeater.Increment("metrics.timeseries.count")
			err := ma.ensureMetricDescriptor(metric, event.Labels)
			if err != nil {
				compositeErr.metricDescriptor = append(compositeErr.metricDescriptor, err)
				continue
			}

			metricType := path.Join("custom.googleapis.com", metric.Name)
			timeSeries := monitoringpb.TimeSeries{
				Metric: &metricpb.Metric{
					Type:   metricType,
					Labels: event.Labels,
				},
				Points: points(metric.Value, metric.EventTime),
			}
			timeSerieses = append(timeSerieses, &timeSeries)
		}
	}

	return timeSerieses, compositeErr
}

func (ma *metricAdapter) CreateMetricDescriptor(metric *messages.Metric, labels map[string]string) error {
	projectName := path.Join("projects", ma.projectID)
	metricType := path.Join("custom.googleapis.com", metric.Name)
	metricName := path.Join(projectName, "metricDescriptors", metricType)

	var labelDescriptors []*labelpb.LabelDescriptor
	for key := range labels {
		labelDescriptors = append(labelDescriptors, &labelpb.LabelDescriptor{
			Key:       key,
			ValueType: labelpb.LabelDescriptor_STRING,
		})
	}

	req := &monitoringpb.CreateMetricDescriptorRequest{
		Name: projectName,
		MetricDescriptor: &metricpb.MetricDescriptor{
			Name:        metricName,
			Type:        metricType,
			Labels:      labelDescriptors,
			MetricKind:  metricpb.MetricDescriptor_GAUGE,
			ValueType:   metricpb.MetricDescriptor_DOUBLE,
			Unit:        metric.Unit,
			Description: "stackdriver-nozzle created custom metric.",
			DisplayName: metric.Name, // TODO
		},
	}

	return ma.client.CreateMetricDescriptor(req)
}

func (ma *metricAdapter) fetchMetricDescriptorNames() error {
	req := &monitoringpb.ListMetricDescriptorsRequest{
		Name:   fmt.Sprintf("projects/%s", ma.projectID),
		Filter: "metric.type = starts_with(\"custom.googleapis.com/\")",
	}

	descriptors, err := ma.client.ListMetricDescriptors(req)
	if err != nil {
		return err
	}

	for _, descriptor := range descriptors {
		ma.descriptors[descriptor.Name] = struct{}{}
	}
	return nil
}

func (ma *metricAdapter) ensureMetricDescriptor(metric *messages.Metric, labels map[string]string) error {
	if metric.Unit == "" {
		return nil
	}

	ma.createDescriptorMutex.Lock()
	defer ma.createDescriptorMutex.Unlock()

	if _, ok := ma.descriptors[metric.Name]; ok {
		return nil
	}

	err := ma.CreateMetricDescriptor(metric, labels)
	if err != nil {
		return err
	}
	ma.descriptors[metric.Name] = struct{}{}
	return nil
}

func points(value float64, eventTime time.Time) []*monitoringpb.Point {
	timeStamp := timestamp.Timestamp{
		Seconds: eventTime.Unix(),
		Nanos:   int32(eventTime.Nanosecond()),
	}
	point := &monitoringpb.Point{
		Interval: &monitoringpb.TimeInterval{
			EndTime:   &timeStamp,
			StartTime: &timeStamp,
		},
		Value: &monitoringpb.TypedValue{
			Value: &monitoringpb.TypedValue_DoubleValue{
				DoubleValue: value,
			},
		},
	}
	return []*monitoringpb.Point{point}
}
<commit_msg>stackdriver/metric_adpater: emit structured log<commit_after>/*
 * Copyright 2017 Google Inc.
 *
 * 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 stackdriver

import (
	"fmt"
	"math"
	"path"
	"strings"
	"sync"
	"time"

	"github.com/cloudfoundry-community/stackdriver-tools/src/stackdriver-nozzle/messages"
	"github.com/cloudfoundry/lager"
	"github.com/golang/protobuf/ptypes/timestamp"
	labelpb "google.golang.org/genproto/googleapis/api/label"
	metricpb "google.golang.org/genproto/googleapis/api/metric"
	monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3"
)

type MetricAdapter interface {
	PostMetricEvents([]*messages.MetricEvent) error
}

type Heartbeater interface {
	Start()
	Increment(string)
	IncrementBy(string, uint)
	Stop()
}

type metricAdapter struct {
	projectID             string
	client                MetricClient
	descriptors           map[string]struct{}
	createDescriptorMutex *sync.Mutex
	batchSize             int
	logger                lager.Logger
	heartbeater           Heartbeater
}

type postMetricErr struct {
	metricDescriptor []error
	postErrs         []error
	filteredErrs     []error
	heartbeater      Heartbeater
}

func (pme *postMetricErr) BuildError() error {
	pme.processErrors()
	if pme == nil || len(pme.filteredErrs) == 0 && len(pme.metricDescriptor) == 0 {
		return nil
	}

	return fmt.Errorf("PostMetricEvents, Unexpected Post Errors: %v, Metric Descriptor Errors: %v", pme.filteredErrs, pme.metricDescriptor)
}

func (pme *postMetricErr) AddPostError(err error) {
	pme.postErrs = append(pme.postErrs, err)
}

// Filter expected errors and record telemetry
func (pme *postMetricErr) processErrors() {
	if pme == nil || len(pme.postErrs) == 0 && len(pme.metricDescriptor) == 0 {
		return
	}

	for _, err := range pme.postErrs {
		pme.heartbeater.Increment("metrics.post.errors")

		// This is an expected error once there is more than a single nozzle writing to Stackdriver.
		// If one nozzle writes a metric occurring at time T2 and this one tries to write at T1 (where T2 later than T1)
		// we will receive this error.
		if strings.Contains(err.Error(), `Points must be written in order`) {
			pme.heartbeater.Increment("metrics.post.errors.out_of_order")
		} else {
			pme.heartbeater.Increment("metrics.post.errors.unknown")
			pme.filteredErrs = append(pme.filteredErrs, err)
		}
	}

	metricDescriptorErrs := len(pme.metricDescriptor)
	if metricDescriptorErrs > 0 {
		pme.heartbeater.IncrementBy("metrics.metric_descriptor.errors", uint(metricDescriptorErrs))
	}
}

// NewMetricAdapter returns a MetricAdapater that can write to Stackdriver Monitoring
func NewMetricAdapter(projectID string, client MetricClient, batchSize int, heartbeater Heartbeater, logger lager.Logger) (MetricAdapter, error) {
	ma := &metricAdapter{
		projectID:             projectID,
		client:                client,
		createDescriptorMutex: &sync.Mutex{},
		descriptors:           map[string]struct{}{},
		batchSize:             batchSize,
		logger:                logger,
		heartbeater:           heartbeater,
	}

	err := ma.fetchMetricDescriptorNames()
	return ma, err
}

func (ma *metricAdapter) PostMetricEvents(events []*messages.MetricEvent) error {
	series, postErr := ma.buildTimeSeries(events)
	projectName := path.Join("projects", ma.projectID)

	count := len(series)
	chunks := int(math.Ceil(float64(count) / float64(ma.batchSize)))

	ma.logger.Info("metricAdapter.PostMetricEvents", lager.Data{"info": "Posting TimeSeries to Stackdriver", "count": count, "chunks": chunks})
	var low, high int
	for i := 0; i < chunks; i++ {
		low = i * ma.batchSize
		high = low + ma.batchSize
		// if we're at the last chunk, take the remaining size
		// so we don't over index
		if i == chunks-1 {
			high = count
		}

		ma.heartbeater.Increment("metrics.requests")
		err := ma.client.Post(&monitoringpb.CreateTimeSeriesRequest{
			Name:       projectName,
			TimeSeries: series[low:high],
		})

		if err != nil {
			postErr.AddPostError(err)
		}
	}

	return postErr.BuildError()
}

func (ma *metricAdapter) buildTimeSeries(events []*messages.MetricEvent) ([]*monitoringpb.TimeSeries, postMetricErr) {
	var timeSerieses []*monitoringpb.TimeSeries

	compositeErr := postMetricErr{heartbeater: ma.heartbeater}

	for _, event := range events {
		if len(event.Metrics) == 0 {
			continue
		}

		ma.heartbeater.Increment("metrics.events.count")
		for _, metric := range event.Metrics {
			ma.heartbeater.Increment("metrics.timeseries.count")
			err := ma.ensureMetricDescriptor(metric, event.Labels)
			if err != nil {
				compositeErr.metricDescriptor = append(compositeErr.metricDescriptor, err)
				continue
			}

			metricType := path.Join("custom.googleapis.com", metric.Name)
			timeSeries := monitoringpb.TimeSeries{
				Metric: &metricpb.Metric{
					Type:   metricType,
					Labels: event.Labels,
				},
				Points: points(metric.Value, metric.EventTime),
			}
			timeSerieses = append(timeSerieses, &timeSeries)
		}
	}

	return timeSerieses, compositeErr
}

func (ma *metricAdapter) CreateMetricDescriptor(metric *messages.Metric, labels map[string]string) error {
	projectName := path.Join("projects", ma.projectID)
	metricType := path.Join("custom.googleapis.com", metric.Name)
	metricName := path.Join(projectName, "metricDescriptors", metricType)

	var labelDescriptors []*labelpb.LabelDescriptor
	for key := range labels {
		labelDescriptors = append(labelDescriptors, &labelpb.LabelDescriptor{
			Key:       key,
			ValueType: labelpb.LabelDescriptor_STRING,
		})
	}

	req := &monitoringpb.CreateMetricDescriptorRequest{
		Name: projectName,
		MetricDescriptor: &metricpb.MetricDescriptor{
			Name:        metricName,
			Type:        metricType,
			Labels:      labelDescriptors,
			MetricKind:  metricpb.MetricDescriptor_GAUGE,
			ValueType:   metricpb.MetricDescriptor_DOUBLE,
			Unit:        metric.Unit,
			Description: "stackdriver-nozzle created custom metric.",
			DisplayName: metric.Name, // TODO
		},
	}

	return ma.client.CreateMetricDescriptor(req)
}

func (ma *metricAdapter) fetchMetricDescriptorNames() error {
	req := &monitoringpb.ListMetricDescriptorsRequest{
		Name:   fmt.Sprintf("projects/%s", ma.projectID),
		Filter: "metric.type = starts_with(\"custom.googleapis.com/\")",
	}

	descriptors, err := ma.client.ListMetricDescriptors(req)
	if err != nil {
		return err
	}

	for _, descriptor := range descriptors {
		ma.descriptors[descriptor.Name] = struct{}{}
	}
	return nil
}

func (ma *metricAdapter) ensureMetricDescriptor(metric *messages.Metric, labels map[string]string) error {
	if metric.Unit == "" {
		return nil
	}

	ma.createDescriptorMutex.Lock()
	defer ma.createDescriptorMutex.Unlock()

	if _, ok := ma.descriptors[metric.Name]; ok {
		return nil
	}

	err := ma.CreateMetricDescriptor(metric, labels)
	if err != nil {
		return err
	}
	ma.descriptors[metric.Name] = struct{}{}
	return nil
}

func points(value float64, eventTime time.Time) []*monitoringpb.Point {
	timeStamp := timestamp.Timestamp{
		Seconds: eventTime.Unix(),
		Nanos:   int32(eventTime.Nanosecond()),
	}
	point := &monitoringpb.Point{
		Interval: &monitoringpb.TimeInterval{
			EndTime:   &timeStamp,
			StartTime: &timeStamp,
		},
		Value: &monitoringpb.TypedValue{
			Value: &monitoringpb.TypedValue_DoubleValue{
				DoubleValue: value,
			},
		},
	}
	return []*monitoringpb.Point{point}
}
<|endoftext|>


<commit_before>package core

import (
	"flag"
	"fmt"
	"strings"
)

// ServerConfiguration struct
// Most of this configuration comes from json config
type ServerConfiguration struct {
	SourceDomain          string
	WhitelistedExtensions []string
	MaximumWidth          int
	LocalBasePath         string
	MantaBasePath         string
	DefaultQuality        uint
	GraphiteHost          string
	GraphitePort          int
	Events                *EventChannels
	Adapters              *Adapters
}

// EventChannels struct
// Available image processing/downloading events
type EventChannels struct {
	ImageProcessed              chan *ImageConfiguration
	ImageProcessedWithErrors    chan *ImageConfiguration
	OriginalDownloaded          chan *ImageConfiguration
	OriginalDownloadUnavailable chan *ImageConfiguration
}

// ServerConfigurationFromFlags initializes a ServerConfiguration from flags
func ServerConfigurationFromFlags() (*ServerConfiguration, error) {
	var (
		whitelistedExtensions = flag.String("extensions", "jpg,gif,webp", "Whitelisted extensions (separated by commas)")
		localBasePath         = flag.String("local_base_path", "public", "Directory where the images will be saved")
		sourceDomain          = flag.String("source_domain", "http://wanelo.s3.amazonaws.com", "Source domain for images")
		mantaBasePath         = flag.String("manta_base_path", "public/images/development", "base path for manta storage")
		graphiteHost          = flag.String("graphite_host", "127.0.0.1", "Graphite Host")
		graphitePort          = flag.Int("graphite_port", 8125, "Graphite port")
		maximumWidth          = flag.Int("maximum_width", 1000, "maximum image width")
		defaultQuality        = flag.Uint("default_quality", 75, "Default image compression quality")
	)
	flag.Parse()

	sc := &ServerConfiguration{
		WhitelistedExtensions: strings.Split(*whitelistedExtensions, ","),
		LocalBasePath:         *localBasePath,
		GraphitePort:          *graphitePort,
		GraphiteHost:          *graphiteHost,
		MaximumWidth:          *maximumWidth,
		MantaBasePath:         *mantaBasePath,
		DefaultQuality:        *defaultQuality,
		SourceDomain:          *sourceDomain,
	}

	sc.Events = &EventChannels{
		ImageProcessed:     make(chan *ImageConfiguration),
		OriginalDownloaded: make(chan *ImageConfiguration),
	}

	fmt.Printf("ServerConfiguration: %v", sc)
	return sc, nil
}
<commit_msg>Remove debugging line that prints server configuration<commit_after>package core

import (
	"flag"
	"strings"
)

// ServerConfiguration struct
// Most of this configuration comes from json config
type ServerConfiguration struct {
	SourceDomain          string
	WhitelistedExtensions []string
	MaximumWidth          int
	LocalBasePath         string
	MantaBasePath         string
	DefaultQuality        uint
	GraphiteHost          string
	GraphitePort          int
	Events                *EventChannels
	Adapters              *Adapters
}

// EventChannels struct
// Available image processing/downloading events
type EventChannels struct {
	ImageProcessed              chan *ImageConfiguration
	ImageProcessedWithErrors    chan *ImageConfiguration
	OriginalDownloaded          chan *ImageConfiguration
	OriginalDownloadUnavailable chan *ImageConfiguration
}

// ServerConfigurationFromFlags initializes a ServerConfiguration from flags
func ServerConfigurationFromFlags() (*ServerConfiguration, error) {
	var (
		whitelistedExtensions = flag.String("extensions", "jpg,gif,webp", "Whitelisted extensions (separated by commas)")
		localBasePath         = flag.String("local_base_path", "public", "Directory where the images will be saved")
		sourceDomain          = flag.String("source_domain", "http://wanelo.s3.amazonaws.com", "Source domain for images")
		mantaBasePath         = flag.String("manta_base_path", "public/images/development", "base path for manta storage")
		graphiteHost          = flag.String("graphite_host", "127.0.0.1", "Graphite Host")
		graphitePort          = flag.Int("graphite_port", 8125, "Graphite port")
		maximumWidth          = flag.Int("maximum_width", 1000, "maximum image width")
		defaultQuality        = flag.Uint("default_quality", 75, "Default image compression quality")
	)
	flag.Parse()

	sc := &ServerConfiguration{
		WhitelistedExtensions: strings.Split(*whitelistedExtensions, ","),
		LocalBasePath:         *localBasePath,
		GraphitePort:          *graphitePort,
		GraphiteHost:          *graphiteHost,
		MaximumWidth:          *maximumWidth,
		MantaBasePath:         *mantaBasePath,
		DefaultQuality:        *defaultQuality,
		SourceDomain:          *sourceDomain,
	}

	sc.Events = &EventChannels{
		ImageProcessed:     make(chan *ImageConfiguration),
		OriginalDownloaded: make(chan *ImageConfiguration),
	}

	return sc, nil
}
<|endoftext|>


<commit_before><commit_msg>Fixed a bug where config.Timestamp was not included in JSON<commit_after><|endoftext|>


<commit_before>package stash

import (
	"fmt"
)

type Author struct {
	Name  string `"json:name"`
	Email string `"json:emailAddress"`
}

type Commit struct {
	Hash      string `"json:id"`
	Author    *Author
	Timestamp int64 `"json:authorTimestamp"`
}

type CommitResource struct {
	client *Client
}

//Get commit data for commit hash
func (r *CommitResource) Get(apiUrl, project, slug, commitId string) (*Commit, error) {
	commit := Commit{}
	path := fmt.Sprintf("/projects/%s/repos/%s/commits/%s", project, slug,
		commitId)

	if err := r.client.do("GET", path, nil, nil, &commit); err != nil {
		return nil, err
	}

	return &commit, nil
}
<commit_msg>commit timestamp now string type<commit_after>package stash

import (
	"fmt"
)

type Author struct {
	Name  string `"json:name"`
	Email string `"json:emailAddress"`
}

type Commit struct {
	Hash      string `"json:id"`
	Author    *Author
	Timestamp string `"json:authorTimestamp"`
	Message   string `"json:message"`
}

type CommitResource struct {
	client *Client
}

//Get commit data for commit hash
func (r *CommitResource) Get(project, slug, commitId string) (*Commit, error) {
	commit := Commit{}
	path := fmt.Sprintf("/projects/%s/repos/%s/commits/%s", project, slug,
		commitId)

	if err := r.client.do("GET", path, nil, nil, &commit); err != nil {
		return nil, err
	}

	return &commit, nil
}
<|endoftext|>


<commit_before>package cliconfig

import (
	"fmt"
	"strings"
)

const (
	StrDefaultY         string = "[Y/n]"
	StrDefaultN         string = "[y/N]"
	rootServiceQuestion        = `When only a single environment has been defined, should we root the service command.

For example: "depcon mar app list" would become "depcon app list", eliminating the marathon service command since
we are only dealing with a single service and know what it is.

Root single environment`
)

func CreateNewConfigFromUserInput() *ConfigFile {
	fmt.Println("\n-------------------------------[   Generating Initital Configuration   ]-------------------------------")

	configFile, _ := Load("")
	configFile.RootService = getBoolAnswer(rootServiceQuestion, true)
	configFile.Format = getDefaultFormatOption()
	serviceEnv := createEnvironment()
	configEnv := &ConfigEnvironment{
		Marathon: serviceEnv,
	}
	configFile.Environments[serviceEnv.Name] = configEnv
	configFile.Save()

	return configFile
}

func getDefaultFormatOption() string {

	var response string
	fmt.Println("Default output format (can be overriden via runtime flag)")
	fmt.Println("1 - column")
	fmt.Println("2 - json\n")
	fmt.Printf("Option: ")

	fmt.Scanf("%s", &response)
	fmt.Println("")

	if strings.HasPrefix(response, "2") {
		return "json"
	}
	return "column"
}

// Asks a yes or no question and returns the boolean equivalent
func getBoolAnswer(question string, defaultTrue bool) bool {
	var response string
	var yn string

	if defaultTrue {
		yn = StrDefaultY
	} else {
		yn = StrDefaultN
	}

	fmt.Printf("\n%s %s? ", question, yn)
	fmt.Scanf("%s", &response)

	if response == "" {
		if defaultTrue {
			return true
		}
		return false
	}

	response = strings.ToLower(response)
	if strings.HasPrefix(response, "y") {
		return true
	} else if strings.HasPrefix(response, "n") {
		return false
	}

	fmt.Printf("\nERROR: Must response with 'y' or 'no'\n", response)
	return getBoolAnswer(question, defaultTrue)
}
<commit_msg>fixed description, add yaml option to global configuration wizard<commit_after>package cliconfig

import (
	"fmt"
	"strings"
)

const (
	StrDefaultY         string = "[Y/n]"
	StrDefaultN         string = "[y/N]"
	rootServiceQuestion        = `When only a single environment has been defined, should we root the service command.

For example: "depcon mar app list" would become "depcon app list", eliminating the marathon service command since
we are only dealing with a single service and know what it is.

Root single environment`
)

func CreateNewConfigFromUserInput() *ConfigFile {
	fmt.Println("\n-------------------------------[   Generating Initital Configuration   ]-------------------------------")

	configFile, _ := Load("")
	configFile.RootService = getBoolAnswer(rootServiceQuestion, true)
	configFile.Format = getDefaultFormatOption()
	serviceEnv := createEnvironment()
	configEnv := &ConfigEnvironment{
		Marathon: serviceEnv,
	}
	configFile.Environments[serviceEnv.Name] = configEnv
	configFile.Save()

	return configFile
}

func getDefaultFormatOption() string {

	var response string
	fmt.Println("Default output format (can be overridden via runtime flag)")
	fmt.Println("1 - column")
	fmt.Println("2 - json")
	fmt.Println("3 - yaml\n")
	fmt.Printf("Option: ")

	fmt.Scanf("%s", &response)
	fmt.Println("")

	if strings.HasPrefix(response, "2") {
		return "json"
	}
	if strings.HasPrefix(response, "3") {
		return "yaml"
	}
	return "column"
}

// Asks a yes or no question and returns the boolean equivalent
func getBoolAnswer(question string, defaultTrue bool) bool {
	var response string
	var yn string

	if defaultTrue {
		yn = StrDefaultY
	} else {
		yn = StrDefaultN
	}

	fmt.Printf("\n%s %s? ", question, yn)
	fmt.Scanf("%s", &response)

	if response == "" {
		if defaultTrue {
			return true
		}
		return false
	}

	response = strings.ToLower(response)
	if strings.HasPrefix(response, "y") {
		return true
	} else if strings.HasPrefix(response, "n") {
		return false
	}

	fmt.Printf("\nERROR: Must response with 'y' or 'no'\n", response)
	return getBoolAnswer(question, defaultTrue)
}
<|endoftext|>


<commit_before>package backup

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

	"github.com/pivotal-cf/cf-redis-broker/backup/s3bucket"
	"github.com/pivotal-cf/cf-redis-broker/brokerconfig"
	"github.com/pivotal-cf/cf-redis-broker/redis"
	"github.com/pivotal-cf/cf-redis-broker/redis/client"
	"github.com/pivotal-cf/cf-redis-broker/redisconf"
	"github.com/pivotal-golang/lager"
)

type Backup struct {
	Config *brokerconfig.Config
	Logger lager.Logger
}

func (backup Backup) Create(instanceID string) error {
	s3Client := s3bucket.NewClient(
		backup.Config.RedisConfiguration.BackupConfiguration.EndpointUrl,
		backup.Config.RedisConfiguration.BackupConfiguration.S3Region,
		backup.Config.RedisConfiguration.BackupConfiguration.AccessKeyId,
		backup.Config.RedisConfiguration.BackupConfiguration.SecretAccessKey,
	)

	bucket, err := s3Client.GetOrCreate(backup.Config.RedisConfiguration.BackupConfiguration.BucketName)
	if err != nil {
		return err
	}

	err = backup.createSnapshot(instanceID)
	if err != nil {
		return err
	}

	pathToRdbFile := filepath.Join(backup.Config.RedisConfiguration.InstanceDataDirectory, instanceID, "db", "dump.rdb")

	if !backup.validateBackupFileCreatedFor(pathToRdbFile) {
		return nil
	}

	return backup.uploadToS3(instanceID, pathToRdbFile, bucket)
}

func (backup Backup) createSnapshot(instanceID string) error {
	client, err := backup.buildRedisClient(instanceID)
	if err != nil {
		return err
	}

	return client.CreateSnapshot(backup.Config.RedisConfiguration.BackupConfiguration.BGSaveTimeoutSeconds)
}

func (backup Backup) buildRedisClient(instanceID string) (*client.Client, error) {
	localRepo := redis.LocalRepository{RedisConf: backup.Config.RedisConfiguration}
	instance, err := localRepo.FindByID(instanceID)
	if err != nil {
		return nil, err
	}

	instanceConf, err := redisconf.Load(localRepo.InstanceConfigPath(instanceID))
	if err != nil {
		return nil, err
	}

	return client.Connect(instance.Host, uint(instance.Port), instance.Password, instanceConf)
}

func (backup Backup) validateBackupFileCreatedFor(pathToRdbFile string) bool {
	if !fileExists(pathToRdbFile) {
		backup.Logger.Info("dump.rb not found, skipping instance backup", lager.Data{
			"Local file": pathToRdbFile,
		})
		return false
	}
	return true
}

func (backup Backup) uploadToS3(instanceID, pathToRdbFile string, bucket s3bucket.Bucket) error {
	rdbBytes, err := ioutil.ReadFile(pathToRdbFile)
	if err != nil {
		return err
	}

	remotePath := fmt.Sprintf("%s/%s", backup.Config.RedisConfiguration.BackupConfiguration.Path, instanceID)

	backup.Logger.Info("Backing up instance", lager.Data{
		"Local file":  pathToRdbFile,
		"Remote file": remotePath,
	})

	return bucket.Upload(rdbBytes, remotePath)
}

func fileExists(path string) bool {
	_, err := os.Stat(path)
	return err == nil || os.IsExist(err)
}
<commit_msg>simplify check for dump.rdb before uploading backup<commit_after>package backup

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

	"github.com/pivotal-cf/cf-redis-broker/backup/s3bucket"
	"github.com/pivotal-cf/cf-redis-broker/brokerconfig"
	"github.com/pivotal-cf/cf-redis-broker/redis"
	"github.com/pivotal-cf/cf-redis-broker/redis/client"
	"github.com/pivotal-cf/cf-redis-broker/redisconf"
	"github.com/pivotal-golang/lager"
)

type Backup struct {
	Config *brokerconfig.Config
	Logger lager.Logger
}

func (backup Backup) Create(instanceID string) error {
	s3Client := s3bucket.NewClient(
		backup.Config.RedisConfiguration.BackupConfiguration.EndpointUrl,
		backup.Config.RedisConfiguration.BackupConfiguration.S3Region,
		backup.Config.RedisConfiguration.BackupConfiguration.AccessKeyId,
		backup.Config.RedisConfiguration.BackupConfiguration.SecretAccessKey,
	)

	bucket, err := s3Client.GetOrCreate(backup.Config.RedisConfiguration.BackupConfiguration.BucketName)
	if err != nil {
		return err
	}

	err = backup.createSnapshot(instanceID)
	if err != nil {
		return err
	}

	pathToRdbFile := filepath.Join(backup.Config.RedisConfiguration.InstanceDataDirectory, instanceID, "db", "dump.rdb")

	if !fileExists(pathToRdbFile) {
		backup.Logger.Info("dump.rdb not found, skipping instance backup", lager.Data{
			"Local file": pathToRdbFile,
		})
		return nil
	}

	return backup.uploadToS3(instanceID, pathToRdbFile, bucket)
}

func (backup Backup) createSnapshot(instanceID string) error {
	client, err := backup.buildRedisClient(instanceID)
	if err != nil {
		return err
	}

	return client.CreateSnapshot(backup.Config.RedisConfiguration.BackupConfiguration.BGSaveTimeoutSeconds)
}

func (backup Backup) buildRedisClient(instanceID string) (*client.Client, error) {
	localRepo := redis.LocalRepository{RedisConf: backup.Config.RedisConfiguration}
	instance, err := localRepo.FindByID(instanceID)
	if err != nil {
		return nil, err
	}

	instanceConf, err := redisconf.Load(localRepo.InstanceConfigPath(instanceID))
	if err != nil {
		return nil, err
	}

	return client.Connect(instance.Host, uint(instance.Port), instance.Password, instanceConf)
}

func (backup Backup) uploadToS3(instanceID, pathToRdbFile string, bucket s3bucket.Bucket) error {
	rdbBytes, err := ioutil.ReadFile(pathToRdbFile)
	if err != nil {
		return err
	}

	remotePath := fmt.Sprintf("%s/%s", backup.Config.RedisConfiguration.BackupConfiguration.Path, instanceID)

	backup.Logger.Info("Backing up instance", lager.Data{
		"Local file":  pathToRdbFile,
		"Remote file": remotePath,
	})

	return bucket.Upload(rdbBytes, remotePath)
}

func fileExists(path string) bool {
	_, err := os.Stat(path)
	return err == nil || os.IsExist(err)
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"log"
	"os/exec"
)

type AccessPointManager struct {
	NetworkInterface string
	HostapdJob       UpstartJob
	config           AssistantConfig
}

func NewAccessPointManager(config AssistantConfig) *AccessPointManager {
	manager := &AccessPointManager{}
	manager.NetworkInterface = "ap0"
	manager.HostapdJob = UpstartJob{"hostapd-ap0"}
	manager.config = config

	return manager
}

func (a *AccessPointManager) StartHostAP() {
	a.HostapdJob.Stop()
	a.HostapdJob.Start()
}

func (a *AccessPointManager) StopHostAP() {
	a.HostapdJob.Stop()
}

func (a *AccessPointManager) WriteAPConfig() {
	s := ""
	s += "interface=ap0\n"
	s += "driver=nl80211\n"
	s += "ssid=" + a.config.Wireless_Host.SSID + "\n"
	s += "hw_mode=g\n"
	s += "channel=6\n"
	s += "macaddr_acl=0\n"
	s += "auth_algs=1\n"
	s += "ignore_broadcast_ssid=0\n"
	s += "wpa=3\n"
	s += "wpa_passphrase=" + a.config.Wireless_Host.Key + "\n"
	s += "wpa_key_mgmt=WPA-PSK\n"
	s += "wpa_pairwise=TKIP\n"
	s += "rsn_pairwise=CCMP\n"
	ioutil.WriteFile("/data/etc/hostapd-ap0.conf", []byte(s), 0600)
}

func (a *AccessPointManager) iptables(cmd ...string) {
	log.Println("iptables ", cmd)
	err := exec.Command("/sbin/iptables", cmd...).Run()
	if err != nil {
		log.Fatal("iptables failed: ", err)
	}
}

func (a *AccessPointManager) SetupFirewall() {
	if a.config.Wireless_Host.Full_Network_Access {
		a.iptables("-F")
	} else {
		a.iptables("-P", "INPUT", "ACCEPT")
		a.iptables("-P", "OUTPUT", "ACCEPT")
		a.iptables("-P", "FORWARD", "ACCEPT")
		a.iptables("-F")

		// Allow the pairing webserver to be seen from the AP
		a.iptables("-A", "INPUT", "-i", a.NetworkInterface, "-p", "tcp", "--dport", "8888", "-j", "ACCEPT")
		a.iptables("-A", "INPUT", "-i", a.NetworkInterface, "-p", "tcp", "--dport", "80", "-j", "ACCEPT")
		a.iptables("-A", "INPUT", "-i", a.NetworkInterface, "-p", "tcp", "--dport", "9001", "-j", "ACCEPT")

		// Allow clients to get IP addresses from DHCP
		a.iptables("-A", "INPUT", "-i", a.NetworkInterface, "-p", "udp", "--dport", "67:68", "-j", "ACCEPT")

		// allow nothing on here. before doing this, we will eventually allow setup access on one port.
		a.iptables("-A", "INPUT", "-i", a.NetworkInterface, "-j", "DROP")
	}
}
<commit_msg>Add ssh port.<commit_after>package main

import (
	"io/ioutil"
	"log"
	"os/exec"
)

type AccessPointManager struct {
	NetworkInterface string
	HostapdJob       UpstartJob
	config           AssistantConfig
}

func NewAccessPointManager(config AssistantConfig) *AccessPointManager {
	manager := &AccessPointManager{}
	manager.NetworkInterface = "ap0"
	manager.HostapdJob = UpstartJob{"hostapd-ap0"}
	manager.config = config

	return manager
}

func (a *AccessPointManager) StartHostAP() {
	a.HostapdJob.Stop()
	a.HostapdJob.Start()
}

func (a *AccessPointManager) StopHostAP() {
	a.HostapdJob.Stop()
}

func (a *AccessPointManager) WriteAPConfig() {
	s := ""
	s += "interface=ap0\n"
	s += "driver=nl80211\n"
	s += "ssid=" + a.config.Wireless_Host.SSID + "\n"
	s += "hw_mode=g\n"
	s += "channel=6\n"
	s += "macaddr_acl=0\n"
	s += "auth_algs=1\n"
	s += "ignore_broadcast_ssid=0\n"
	s += "wpa=3\n"
	s += "wpa_passphrase=" + a.config.Wireless_Host.Key + "\n"
	s += "wpa_key_mgmt=WPA-PSK\n"
	s += "wpa_pairwise=TKIP\n"
	s += "rsn_pairwise=CCMP\n"
	ioutil.WriteFile("/data/etc/hostapd-ap0.conf", []byte(s), 0600)
}

func (a *AccessPointManager) iptables(cmd ...string) {
	log.Println("iptables ", cmd)
	err := exec.Command("/sbin/iptables", cmd...).Run()
	if err != nil {
		log.Fatal("iptables failed: ", err)
	}
}

func (a *AccessPointManager) SetupFirewall() {
	if a.config.Wireless_Host.Full_Network_Access {
		a.iptables("-F")
	} else {
		a.iptables("-P", "INPUT", "ACCEPT")
		a.iptables("-P", "OUTPUT", "ACCEPT")
		a.iptables("-P", "FORWARD", "ACCEPT")
		a.iptables("-F")

		// Allow the pairing webserver to be seen from the AP
		a.iptables("-A", "INPUT", "-i", a.NetworkInterface, "-p", "tcp", "--dport", "8888", "-j", "ACCEPT")
		a.iptables("-A", "INPUT", "-i", a.NetworkInterface, "-p", "tcp", "--dport", "80", "-j", "ACCEPT")
		a.iptables("-A", "INPUT", "-i", a.NetworkInterface, "-p", "tcp", "--dport", "9001", "-j", "ACCEPT")
		a.iptables("-A", "INPUT", "-i", a.NetworkInterface, "-p", "tcp", "--dport", "22", "-j", "ACCEPT")

		// Allow clients to get IP addresses from DHCP
		a.iptables("-A", "INPUT", "-i", a.NetworkInterface, "-p", "udp", "--dport", "67:68", "-j", "ACCEPT")

		// allow nothing on here. before doing this, we will eventually allow setup access on one port.
		a.iptables("-A", "INPUT", "-i", a.NetworkInterface, "-j", "DROP")
	}
}
<|endoftext|>


<commit_before>// Copyright © 2017 National Library of Norway.
// 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 util

import (
	log "github.com/sirupsen/logrus"
	"github.com/spf13/viper"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	api "veidemann_api"
)

func NewControllerClient() (api.ControllerClient, *grpc.ClientConn) {
	conn := newConnection()
	c := api.NewControllerClient(conn)
	return c, conn
}

func NewStatusClient() (api.StatusClient, *grpc.ClientConn) {
	conn := newConnection()
	c := api.NewStatusClient(conn)
	return c, conn
}

func NewReportClient() (api.ReportClient, *grpc.ClientConn) {
	conn := newConnection()
	c := api.NewReportClient(conn)
	return c, conn
}

func newConnection() *grpc.ClientConn {
	address := viper.GetString("controllerAddress")
	log.Debugf("Connecting to %s", address)

	dialOptions := []grpc.DialOption{grpc.WithInsecure()}
	dialOptions = AddCredentials(dialOptions)

	// Set up a connection to the server.
	conn, err := grpc.Dial(address, dialOptions...)
	if err != nil {
		log.Fatalf("Could not connect: %v", err)
	}
	return conn
}

type bearerTokenCred struct {
	tokenType string
	token     string
}

func AddCredentials(opts []grpc.DialOption) []grpc.DialOption {
	a := NewAuth()
	if !a.enabled {
		return opts
	}

	a.CheckStoredAccessToken()
	log.Debugf("Raw IdToken: %s", a.oauth2Token.TokenType)
	if a.rawIdToken == "" {
		return opts
	}

	var bt credentials.PerRPCCredentials = &bearerTokenCred{a.oauth2Token.TokenType, a.rawIdToken}
	return append(opts, grpc.WithPerRPCCredentials(bt))
}

func (b bearerTokenCred) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
	return map[string]string{
		"authorization": b.tokenType + " " + b.token,
	}, nil
}

func (b bearerTokenCred) RequireTransportSecurity() bool {
	return false
}
<commit_msg>Fixed panic caused by trying to log value which sometimes is nil<commit_after>// Copyright © 2017 National Library of Norway.
// 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 util

import (
	log "github.com/sirupsen/logrus"
	"github.com/spf13/viper"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	api "veidemann_api"
)

func NewControllerClient() (api.ControllerClient, *grpc.ClientConn) {
	conn := newConnection()
	c := api.NewControllerClient(conn)
	return c, conn
}

func NewStatusClient() (api.StatusClient, *grpc.ClientConn) {
	conn := newConnection()
	c := api.NewStatusClient(conn)
	return c, conn
}

func NewReportClient() (api.ReportClient, *grpc.ClientConn) {
	conn := newConnection()
	c := api.NewReportClient(conn)
	return c, conn
}

func newConnection() *grpc.ClientConn {
	address := viper.GetString("controllerAddress")
	log.Debugf("Connecting to %s", address)

	dialOptions := []grpc.DialOption{grpc.WithInsecure()}
	dialOptions = AddCredentials(dialOptions)

	// Set up a connection to the server.
	conn, err := grpc.Dial(address, dialOptions...)
	if err != nil {
		log.Fatalf("Could not connect: %v", err)
	}
	return conn
}

type bearerTokenCred struct {
	tokenType string
	token     string
}

func AddCredentials(opts []grpc.DialOption) []grpc.DialOption {
	a := NewAuth()
	if !a.enabled {
		return opts
	}

	a.CheckStoredAccessToken()
	if a.oauth2Token != nil {
		log.Debugf("Raw IdToken: %s", a.oauth2Token.TokenType)
	}
	if a.rawIdToken == "" {
		return opts
	}

	var bt credentials.PerRPCCredentials = &bearerTokenCred{a.oauth2Token.TokenType, a.rawIdToken}
	return append(opts, grpc.WithPerRPCCredentials(bt))
}

func (b bearerTokenCred) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
	return map[string]string{
		"authorization": b.tokenType + " " + b.token,
	}, nil
}

func (b bearerTokenCred) RequireTransportSecurity() bool {
	return false
}
<|endoftext|>


<commit_before>package s3api

import (
	"encoding/xml"
	"fmt"
	"github.com/chrislusf/seaweedfs/weed/s3api/s3_constants"
	"io"
	"net/http"

	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
	"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
	"github.com/chrislusf/seaweedfs/weed/util"
)

// GetObjectTaggingHandler - GET object tagging
// API reference: https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectTagging.html
func (s3a *S3ApiServer) GetObjectTaggingHandler(w http.ResponseWriter, r *http.Request) {

	bucket, object := s3_constants.GetBucketAndObject(r)
	glog.V(3).Infof("GetObjectTaggingHandler %s %s", bucket, object)

	target := util.FullPath(fmt.Sprintf("%s/%s%s", s3a.option.BucketsPath, bucket, object))
	dir, name := target.DirAndName()

	tags, err := s3a.getTags(dir, name)
	if err != nil {
		if err == filer_pb.ErrNotFound {
			glog.Errorf("GetObjectTaggingHandler %s: %v", r.URL, err)
			s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchKey)
		} else {
			glog.Errorf("GetObjectTaggingHandler %s: %v", r.URL, err)
			s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
		}
		return
	}

	writeSuccessResponseXML(w, r, FromTags(tags))

}

// PutObjectTaggingHandler Put object tagging
// API reference: https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectTagging.html
func (s3a *S3ApiServer) PutObjectTaggingHandler(w http.ResponseWriter, r *http.Request) {

	bucket, object := s3_constants.GetBucketAndObject(r)
	glog.V(3).Infof("PutObjectTaggingHandler %s %s", bucket, object)

	target := util.FullPath(fmt.Sprintf("%s/%s%s", s3a.option.BucketsPath, bucket, object))
	dir, name := target.DirAndName()

	tagging := &Tagging{}
	input, err := io.ReadAll(io.LimitReader(r.Body, r.ContentLength))
	if err != nil {
		glog.Errorf("PutObjectTaggingHandler read input %s: %v", r.URL, err)
		s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
		return
	}
	if err = xml.Unmarshal(input, tagging); err != nil {
		glog.Errorf("PutObjectTaggingHandler Unmarshal %s: %v", r.URL, err)
		s3err.WriteErrorResponse(w, r, s3err.ErrMalformedXML)
		return
	}
	tags := tagging.ToTags()
	err = ValidateTags(tags)
	if err != nil {
		glog.Errorf("PutObjectTaggingHandler ValidateTags error %s: %v", r.URL, err)
		s3err.WriteErrorResponse(w, r, s3err.ErrInvalidTag)
	}

	if err = s3a.setTags(dir, name, tagging.ToTags()); err != nil {
		if err == filer_pb.ErrNotFound {
			glog.Errorf("PutObjectTaggingHandler setTags %s: %v", r.URL, err)
			s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchKey)
		} else {
			glog.Errorf("PutObjectTaggingHandler setTags %s: %v", r.URL, err)
			s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
		}
		return
	}

	w.WriteHeader(http.StatusOK)
	s3err.PostLog(r, http.StatusOK, s3err.ErrNone)
}

// DeleteObjectTaggingHandler Delete object tagging
// API reference: https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjectTagging.html
func (s3a *S3ApiServer) DeleteObjectTaggingHandler(w http.ResponseWriter, r *http.Request) {

	bucket, object := s3_constants.GetBucketAndObject(r)
	glog.V(3).Infof("DeleteObjectTaggingHandler %s %s", bucket, object)

	target := util.FullPath(fmt.Sprintf("%s/%s%s", s3a.option.BucketsPath, bucket, object))
	dir, name := target.DirAndName()

	err := s3a.rmTags(dir, name)
	if err != nil {
		if err == filer_pb.ErrNotFound {
			glog.Errorf("DeleteObjectTaggingHandler %s: %v", r.URL, err)
			s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchKey)
		} else {
			glog.Errorf("DeleteObjectTaggingHandler %s: %v", r.URL, err)
			s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
		}
		return
	}

	w.WriteHeader(http.StatusNoContent)
	s3err.PostLog(r, http.StatusNoContent, s3err.ErrNone)
}
<commit_msg>fix return<commit_after>package s3api

import (
	"encoding/xml"
	"fmt"
	"github.com/chrislusf/seaweedfs/weed/s3api/s3_constants"
	"io"
	"net/http"

	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
	"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
	"github.com/chrislusf/seaweedfs/weed/util"
)

// GetObjectTaggingHandler - GET object tagging
// API reference: https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectTagging.html
func (s3a *S3ApiServer) GetObjectTaggingHandler(w http.ResponseWriter, r *http.Request) {

	bucket, object := s3_constants.GetBucketAndObject(r)
	glog.V(3).Infof("GetObjectTaggingHandler %s %s", bucket, object)

	target := util.FullPath(fmt.Sprintf("%s/%s%s", s3a.option.BucketsPath, bucket, object))
	dir, name := target.DirAndName()

	tags, err := s3a.getTags(dir, name)
	if err != nil {
		if err == filer_pb.ErrNotFound {
			glog.Errorf("GetObjectTaggingHandler %s: %v", r.URL, err)
			s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchKey)
		} else {
			glog.Errorf("GetObjectTaggingHandler %s: %v", r.URL, err)
			s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
		}
		return
	}

	writeSuccessResponseXML(w, r, FromTags(tags))

}

// PutObjectTaggingHandler Put object tagging
// API reference: https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectTagging.html
func (s3a *S3ApiServer) PutObjectTaggingHandler(w http.ResponseWriter, r *http.Request) {

	bucket, object := s3_constants.GetBucketAndObject(r)
	glog.V(3).Infof("PutObjectTaggingHandler %s %s", bucket, object)

	target := util.FullPath(fmt.Sprintf("%s/%s%s", s3a.option.BucketsPath, bucket, object))
	dir, name := target.DirAndName()

	tagging := &Tagging{}
	input, err := io.ReadAll(io.LimitReader(r.Body, r.ContentLength))
	if err != nil {
		glog.Errorf("PutObjectTaggingHandler read input %s: %v", r.URL, err)
		s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
		return
	}
	if err = xml.Unmarshal(input, tagging); err != nil {
		glog.Errorf("PutObjectTaggingHandler Unmarshal %s: %v", r.URL, err)
		s3err.WriteErrorResponse(w, r, s3err.ErrMalformedXML)
		return
	}
	tags := tagging.ToTags()
	err = ValidateTags(tags)
	if err != nil {
		glog.Errorf("PutObjectTaggingHandler ValidateTags error %s: %v", r.URL, err)
		s3err.WriteErrorResponse(w, r, s3err.ErrInvalidTag)
		return
	}

	if err = s3a.setTags(dir, name, tagging.ToTags()); err != nil {
		if err == filer_pb.ErrNotFound {
			glog.Errorf("PutObjectTaggingHandler setTags %s: %v", r.URL, err)
			s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchKey)
		} else {
			glog.Errorf("PutObjectTaggingHandler setTags %s: %v", r.URL, err)
			s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
		}
		return
	}

	w.WriteHeader(http.StatusOK)
	s3err.PostLog(r, http.StatusOK, s3err.ErrNone)
}

// DeleteObjectTaggingHandler Delete object tagging
// API reference: https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjectTagging.html
func (s3a *S3ApiServer) DeleteObjectTaggingHandler(w http.ResponseWriter, r *http.Request) {

	bucket, object := s3_constants.GetBucketAndObject(r)
	glog.V(3).Infof("DeleteObjectTaggingHandler %s %s", bucket, object)

	target := util.FullPath(fmt.Sprintf("%s/%s%s", s3a.option.BucketsPath, bucket, object))
	dir, name := target.DirAndName()

	err := s3a.rmTags(dir, name)
	if err != nil {
		if err == filer_pb.ErrNotFound {
			glog.Errorf("DeleteObjectTaggingHandler %s: %v", r.URL, err)
			s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchKey)
		} else {
			glog.Errorf("DeleteObjectTaggingHandler %s: %v", r.URL, err)
			s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
		}
		return
	}

	w.WriteHeader(http.StatusNoContent)
	s3err.PostLog(r, http.StatusNoContent, s3err.ErrNone)
}
<|endoftext|>