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

package debug

import (
	"bytes"
	"context"
	"go/token"
	"html/template"
	"net"
	"net/http"
	"net/http/pprof"
	_ "net/http/pprof" // pull in the standard pprof handlers
	"path"
	"runtime"
	"strconv"
	"sync"

	"golang.org/x/tools/internal/span"
	"golang.org/x/tools/internal/telemetry/export"
	"golang.org/x/tools/internal/telemetry/export/prometheus"
	"golang.org/x/tools/internal/telemetry/log"
	"golang.org/x/tools/internal/telemetry/tag"
)

type Cache interface {
	ID() string
	FileSet() *token.FileSet
}

type Session interface {
	ID() string
	Cache() Cache
	Files() []*File
	File(hash string) *File
}

type View interface {
	ID() string
	Name() string
	Folder() span.URI
	Session() Session
}

type File struct {
	Session Session
	URI     span.URI
	Data    string
	Error   error
	Hash    string
}

var (
	mu   sync.Mutex
	data = struct {
		Caches   []Cache
		Sessions []Session
		Views    []View
	}{}
)

// AddCache adds a cache to the set being served
func AddCache(cache Cache) {
	mu.Lock()
	defer mu.Unlock()
	data.Caches = append(data.Caches, cache)
}

// DropCache drops a cache from the set being served
func DropCache(cache Cache) {
	mu.Lock()
	defer mu.Unlock()
	//find and remove the cache
	if i, _ := findCache(cache.ID()); i >= 0 {
		copy(data.Caches[i:], data.Caches[i+1:])
		data.Caches[len(data.Caches)-1] = nil
		data.Caches = data.Caches[:len(data.Caches)-1]
	}
}

func findCache(id string) (int, Cache) {
	for i, c := range data.Caches {
		if c.ID() == id {
			return i, c
		}
	}
	return -1, nil
}

func getCache(r *http.Request) interface{} {
	mu.Lock()
	defer mu.Unlock()
	id := path.Base(r.URL.Path)
	result := struct {
		Cache
		Sessions []Session
	}{}
	_, result.Cache = findCache(id)

	// now find all the views that belong to this session
	for _, v := range data.Sessions {
		if v.Cache().ID() == id {
			result.Sessions = append(result.Sessions, v)
		}
	}
	return result
}

func findSession(id string) Session {
	for _, c := range data.Sessions {
		if c.ID() == id {
			return c
		}
	}
	return nil
}

func getSession(r *http.Request) interface{} {
	mu.Lock()
	defer mu.Unlock()
	id := path.Base(r.URL.Path)
	result := struct {
		Session
		Views []View
	}{
		Session: findSession(id),
	}
	// now find all the views that belong to this session
	for _, v := range data.Views {
		if v.Session().ID() == id {
			result.Views = append(result.Views, v)
		}
	}
	return result
}

func findView(id string) View {
	for _, c := range data.Views {
		if c.ID() == id {
			return c
		}
	}
	return nil
}

func getView(r *http.Request) interface{} {
	mu.Lock()
	defer mu.Unlock()
	id := path.Base(r.URL.Path)
	return findView(id)
}

func getFile(r *http.Request) interface{} {
	mu.Lock()
	defer mu.Unlock()
	hash := path.Base(r.URL.Path)
	sid := path.Base(path.Dir(r.URL.Path))
	session := findSession(sid)
	return session.File(hash)
}

func getInfo(r *http.Request) interface{} {
	buf := &bytes.Buffer{}
	PrintVersionInfo(buf, true, HTML)
	return template.HTML(buf.String())
}

func getMemory(r *http.Request) interface{} {
	var m runtime.MemStats
	runtime.ReadMemStats(&m)
	return m
}

// AddSession adds a session to the set being served
func AddSession(session Session) {
	mu.Lock()
	defer mu.Unlock()
	data.Sessions = append(data.Sessions, session)
}

// DropSession drops a session from the set being served
func DropSession(session Session) {
	mu.Lock()
	defer mu.Unlock()
	//find and remove the session
}

// AddView adds a view to the set being served
func AddView(view View) {
	mu.Lock()
	defer mu.Unlock()
	data.Views = append(data.Views, view)
}

// DropView drops a view from the set being served
func DropView(view View) {
	mu.Lock()
	defer mu.Unlock()
	//find and remove the view
}

// Serve starts and runs a debug server in the background.
// It also logs the port the server starts on, to allow for :0 auto assigned
// ports.
func Serve(ctx context.Context, addr string) error {
	mu.Lock()
	defer mu.Unlock()
	if addr == "" {
		return nil
	}
	listener, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	log.Print(ctx, "Debug serving", tag.Of("Port", listener.Addr().(*net.TCPAddr).Port))
	prometheus := prometheus.New()
	rpcs := &rpcs{}
	traces := &traces{}
	export.AddExporters(prometheus, rpcs, traces)
	go func() {
		mux := http.NewServeMux()
		mux.HandleFunc("/", Render(mainTmpl, func(*http.Request) interface{} { return data }))
		mux.HandleFunc("/debug/", Render(debugTmpl, nil))
		mux.HandleFunc("/debug/pprof/", pprof.Index)
		mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
		mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
		mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
		mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
		mux.HandleFunc("/metrics/", prometheus.Serve)
		mux.HandleFunc("/rpc/", Render(rpcTmpl, rpcs.getData))
		mux.HandleFunc("/trace/", Render(traceTmpl, traces.getData))
		mux.HandleFunc("/cache/", Render(cacheTmpl, getCache))
		mux.HandleFunc("/session/", Render(sessionTmpl, getSession))
		mux.HandleFunc("/view/", Render(viewTmpl, getView))
		mux.HandleFunc("/file/", Render(fileTmpl, getFile))
		mux.HandleFunc("/info", Render(infoTmpl, getInfo))
		mux.HandleFunc("/memory", Render(memoryTmpl, getMemory))
		if err := http.Serve(listener, mux); err != nil {
			log.Error(ctx, "Debug server failed", err)
			return
		}
		log.Print(ctx, "Debug server finished")
	}()
	return nil
}

func Render(tmpl *template.Template, fun func(*http.Request) interface{}) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		mu.Lock()
		defer mu.Unlock()
		var data interface{}
		if fun != nil {
			data = fun(r)
		}
		if err := tmpl.Execute(w, data); err != nil {
			log.Error(context.Background(), "", err)
		}
	}
}

func commas(s string) string {
	for i := len(s); i > 3; {
		i -= 3
		s = s[:i] + "," + s[i:]
	}
	return s
}

func fuint64(v uint64) string {
	return commas(strconv.FormatUint(v, 10))
}

func fuint32(v uint32) string {
	return commas(strconv.FormatUint(uint64(v), 10))
}

var BaseTemplate = template.Must(template.New("").Parse(`

<title>{{template "title" .}}</title>

{{block "head" .}}{{end}}

Main
Info
Memory
Metrics
RPC
Trace

{{template "title" .}}

{{block "body" .}}
Unknown page
{{end}}

{{define "cachelink"}}Cache {{.}}{{end}}
{{define "sessionlink"}}Session {{.}}{{end}}
{{define "viewlink"}}View {{.}}{{end}}
{{define "filelink"}}{{.URI}}{{end}}
`)).Funcs(template.FuncMap{
	"fuint64": fuint64,
	"fuint32": fuint32,
})

var mainTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(`
{{define "title"}}GoPls server information{{end}}
{{define "body"}}

Caches

{{range .Caches}}
{{template "cachelink" .ID}}
{{end}}

Sessions

{{range .Sessions}}
{{template "sessionlink" .ID}} from {{template "cachelink" .Cache.ID}}
{{end}}

Views

{{range .Views}}
{{.Name}} is {{template "viewlink" .ID}} from {{template "sessionlink" .Session.ID}} in {{.Folder}}
{{end}}

{{end}}
`))

var infoTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(`
{{define "title"}}GoPls version information{{end}}
{{define "body"}}
{{.}}
{{end}}
`))

var memoryTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(`
{{define "title"}}GoPls memory usage{{end}}
{{define "head"}}<meta http-equiv="refresh" content="5">{{end}}
{{define "body"}}

Stats

Allocated bytes	{{fuint64 .HeapAlloc}}

Total allocated bytes	{{fuint64 .TotalAlloc}}

System bytes	{{fuint64 .Sys}}

Heap system bytes	{{fuint64 .HeapSys}}

Malloc calls	{{fuint64 .Mallocs}}

Frees	{{fuint64 .Frees}}

Idle heap bytes	{{fuint64 .HeapIdle}}

In use bytes	{{fuint64 .HeapInuse}}

Released to system bytes	{{fuint64 .HeapReleased}}

Heap object count	{{fuint64 .HeapObjects}}

Stack in use bytes	{{fuint64 .StackInuse}}

Stack from system bytes	{{fuint64 .StackSys}}

Bucket hash bytes	{{fuint64 .BuckHashSys}}

GC metadata bytes	{{fuint64 .GCSys}}

Off heap bytes	{{fuint64 .OtherSys}}

By size

Size	Mallocs	Frees

{{range .BySize}}
{{fuint32 .Size}}	{{fuint64 .Mallocs}}	{{fuint64 .Frees}}
{{end}}

{{end}}
`))

var debugTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(`
{{define "title"}}GoPls Debug pages{{end}}
{{define "body"}}
Profiling
{{end}}
`))

var cacheTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(`
{{define "title"}}Cache {{.ID}}{{end}}
{{define "body"}}

Sessions

{{range .Sessions}}
{{template "sessionlink" .ID}}
{{end}}

{{end}}
`))

var sessionTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(`
{{define "title"}}Session {{.ID}}{{end}}
{{define "body"}}
From: {{template "cachelink" .Cache.ID}}

Views

{{range .Views}}
{{.Name}} is {{template "viewlink" .ID}} in {{.Folder}}
{{end}}

Files

{{range .Files}}
{{template "filelink" .}}
{{end}}

{{end}}
`))

var viewTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(`
{{define "title"}}View {{.ID}}{{end}}
{{define "body"}}
Name: {{.Name}}

Folder: {{.Folder}}

From: {{template "sessionlink" .Session.ID}}

Environment

{{range .Env}}
{{.}}
{{end}}

{{end}}
`))

var fileTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(`
{{define "title"}}File {{.Hash}}{{end}}
{{define "body"}}
From: {{template "sessionlink" .Session.ID}}

URI: {{.URI}}

Hash: {{.Hash}}

Error: {{.Error}}

Contents

{{.Data}}

{{end}}
`))
<commit_msg>internal/lsp: fix the debug info pages<commit_after>// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package debug

import (
	"bytes"
	"context"
	"go/token"
	"html/template"
	"net"
	"net/http"
	"net/http/pprof"
	_ "net/http/pprof" // pull in the standard pprof handlers
	"path"
	"runtime"
	"strconv"
	"sync"

	"golang.org/x/tools/internal/span"
	"golang.org/x/tools/internal/telemetry/export"
	"golang.org/x/tools/internal/telemetry/export/prometheus"
	"golang.org/x/tools/internal/telemetry/log"
	"golang.org/x/tools/internal/telemetry/tag"
)

type Cache interface {
	ID() string
	FileSet() *token.FileSet
}

type Session interface {
	ID() string
	Cache() Cache
	Files() []*File
	File(hash string) *File
}

type View interface {
	ID() string
	Name() string
	Folder() span.URI
	Session() Session
}

type File struct {
	Session Session
	URI     span.URI
	Data    string
	Error   error
	Hash    string
}

var (
	mu   sync.Mutex
	data = struct {
		Caches   []Cache
		Sessions []Session
		Views    []View
	}{}
)

// AddCache adds a cache to the set being served
func AddCache(cache Cache) {
	mu.Lock()
	defer mu.Unlock()
	data.Caches = append(data.Caches, cache)
}

// DropCache drops a cache from the set being served
func DropCache(cache Cache) {
	mu.Lock()
	defer mu.Unlock()
	//find and remove the cache
	if i, _ := findCache(cache.ID()); i >= 0 {
		copy(data.Caches[i:], data.Caches[i+1:])
		data.Caches[len(data.Caches)-1] = nil
		data.Caches = data.Caches[:len(data.Caches)-1]
	}
}

func findCache(id string) (int, Cache) {
	for i, c := range data.Caches {
		if c.ID() == id {
			return i, c
		}
	}
	return -1, nil
}

func getCache(r *http.Request) interface{} {
	mu.Lock()
	defer mu.Unlock()
	id := path.Base(r.URL.Path)
	result := struct {
		Cache
		Sessions []Session
	}{}
	_, result.Cache = findCache(id)

	// now find all the views that belong to this session
	for _, v := range data.Sessions {
		if v.Cache().ID() == id {
			result.Sessions = append(result.Sessions, v)
		}
	}
	return result
}

func findSession(id string) Session {
	for _, c := range data.Sessions {
		if c.ID() == id {
			return c
		}
	}
	return nil
}

func getSession(r *http.Request) interface{} {
	mu.Lock()
	defer mu.Unlock()
	id := path.Base(r.URL.Path)
	result := struct {
		Session
		Views []View
	}{
		Session: findSession(id),
	}
	// now find all the views that belong to this session
	for _, v := range data.Views {
		if v.Session().ID() == id {
			result.Views = append(result.Views, v)
		}
	}
	return result
}

func findView(id string) View {
	for _, c := range data.Views {
		if c.ID() == id {
			return c
		}
	}
	return nil
}

func getView(r *http.Request) interface{} {
	mu.Lock()
	defer mu.Unlock()
	id := path.Base(r.URL.Path)
	return findView(id)
}

func getFile(r *http.Request) interface{} {
	mu.Lock()
	defer mu.Unlock()
	hash := path.Base(r.URL.Path)
	sid := path.Base(path.Dir(r.URL.Path))
	session := findSession(sid)
	return session.File(hash)
}

func getInfo(r *http.Request) interface{} {
	buf := &bytes.Buffer{}
	PrintVersionInfo(buf, true, HTML)
	return template.HTML(buf.String())
}

func getMemory(r *http.Request) interface{} {
	var m runtime.MemStats
	runtime.ReadMemStats(&m)
	return m
}

// AddSession adds a session to the set being served
func AddSession(session Session) {
	mu.Lock()
	defer mu.Unlock()
	data.Sessions = append(data.Sessions, session)
}

// DropSession drops a session from the set being served
func DropSession(session Session) {
	mu.Lock()
	defer mu.Unlock()
	//find and remove the session
}

// AddView adds a view to the set being served
func AddView(view View) {
	mu.Lock()
	defer mu.Unlock()
	data.Views = append(data.Views, view)
}

// DropView drops a view from the set being served
func DropView(view View) {
	mu.Lock()
	defer mu.Unlock()
	//find and remove the view
}

// Serve starts and runs a debug server in the background.
// It also logs the port the server starts on, to allow for :0 auto assigned
// ports.
func Serve(ctx context.Context, addr string) error {
	mu.Lock()
	defer mu.Unlock()
	if addr == "" {
		return nil
	}
	listener, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	log.Print(ctx, "Debug serving", tag.Of("Port", listener.Addr().(*net.TCPAddr).Port))
	prometheus := prometheus.New()
	rpcs := &rpcs{}
	traces := &traces{}
	export.AddExporters(prometheus, rpcs, traces)
	go func() {
		mux := http.NewServeMux()
		mux.HandleFunc("/", Render(mainTmpl, func(*http.Request) interface{} { return data }))
		mux.HandleFunc("/debug/", Render(debugTmpl, nil))
		mux.HandleFunc("/debug/pprof/", pprof.Index)
		mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
		mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
		mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
		mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
		mux.HandleFunc("/metrics/", prometheus.Serve)
		mux.HandleFunc("/rpc/", Render(rpcTmpl, rpcs.getData))
		mux.HandleFunc("/trace/", Render(traceTmpl, traces.getData))
		mux.HandleFunc("/cache/", Render(cacheTmpl, getCache))
		mux.HandleFunc("/session/", Render(sessionTmpl, getSession))
		mux.HandleFunc("/view/", Render(viewTmpl, getView))
		mux.HandleFunc("/file/", Render(fileTmpl, getFile))
		mux.HandleFunc("/info", Render(infoTmpl, getInfo))
		mux.HandleFunc("/memory", Render(memoryTmpl, getMemory))
		if err := http.Serve(listener, mux); err != nil {
			log.Error(ctx, "Debug server failed", err)
			return
		}
		log.Print(ctx, "Debug server finished")
	}()
	return nil
}

func Render(tmpl *template.Template, fun func(*http.Request) interface{}) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		var data interface{}
		if fun != nil {
			data = fun(r)
		}
		if err := tmpl.Execute(w, data); err != nil {
			log.Error(context.Background(), "", err)
		}
	}
}

func commas(s string) string {
	for i := len(s); i > 3; {
		i -= 3
		s = s[:i] + "," + s[i:]
	}
	return s
}

func fuint64(v uint64) string {
	return commas(strconv.FormatUint(v, 10))
}

func fuint32(v uint32) string {
	return commas(strconv.FormatUint(uint64(v), 10))
}

var BaseTemplate = template.Must(template.New("").Parse(`

<title>{{template "title" .}}</title>

{{block "head" .}}{{end}}

Main
Info
Memory
Metrics
RPC
Trace

{{template "title" .}}

{{block "body" .}}
Unknown page
{{end}}

{{define "cachelink"}}Cache {{.}}{{end}}
{{define "sessionlink"}}Session {{.}}{{end}}
{{define "viewlink"}}View {{.}}{{end}}
{{define "filelink"}}{{.URI}}{{end}}
`)).Funcs(template.FuncMap{
	"fuint64": fuint64,
	"fuint32": fuint32,
})

var mainTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(`
{{define "title"}}GoPls server information{{end}}
{{define "body"}}

Caches

{{range .Caches}}
{{template "cachelink" .ID}}
{{end}}

Sessions

{{range .Sessions}}
{{template "sessionlink" .ID}} from {{template "cachelink" .Cache.ID}}
{{end}}

Views

{{range .Views}}
{{.Name}} is {{template "viewlink" .ID}} from {{template "sessionlink" .Session.ID}} in {{.Folder}}
{{end}}

{{end}}
`))

var infoTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(`
{{define "title"}}GoPls version information{{end}}
{{define "body"}}
{{.}}
{{end}}
`))

var memoryTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(`
{{define "title"}}GoPls memory usage{{end}}
{{define "head"}}<meta http-equiv="refresh" content="5">{{end}}
{{define "body"}}

Stats

Allocated bytes	{{fuint64 .HeapAlloc}}

Total allocated bytes	{{fuint64 .TotalAlloc}}

System bytes	{{fuint64 .Sys}}

Heap system bytes	{{fuint64 .HeapSys}}

Malloc calls	{{fuint64 .Mallocs}}

Frees	{{fuint64 .Frees}}

Idle heap bytes	{{fuint64 .HeapIdle}}

In use bytes	{{fuint64 .HeapInuse}}

Released to system bytes	{{fuint64 .HeapReleased}}

Heap object count	{{fuint64 .HeapObjects}}

Stack in use bytes	{{fuint64 .StackInuse}}

Stack from system bytes	{{fuint64 .StackSys}}

Bucket hash bytes	{{fuint64 .BuckHashSys}}

GC metadata bytes	{{fuint64 .GCSys}}

Off heap bytes	{{fuint64 .OtherSys}}

By size

Size	Mallocs	Frees

{{range .BySize}}
{{fuint32 .Size}}	{{fuint64 .Mallocs}}	{{fuint64 .Frees}}
{{end}}

{{end}}
`))

var debugTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(`
{{define "title"}}GoPls Debug pages{{end}}
{{define "body"}}
Profiling
{{end}}
`))

var cacheTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(`
{{define "title"}}Cache {{.ID}}{{end}}
{{define "body"}}

Sessions

{{range .Sessions}}
{{template "sessionlink" .ID}}
{{end}}

{{end}}
`))

var sessionTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(`
{{define "title"}}Session {{.ID}}{{end}}
{{define "body"}}
From: {{template "cachelink" .Cache.ID}}

Views

{{range .Views}}
{{.Name}} is {{template "viewlink" .ID}} in {{.Folder}}
{{end}}

Files

{{range .Files}}
{{template "filelink" .}}
{{end}}

{{end}}
`))

var viewTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(`
{{define "title"}}View {{.ID}}{{end}}
{{define "body"}}
Name: {{.Name}}

Folder: {{.Folder}}

From: {{template "sessionlink" .Session.ID}}

Environment

{{range .Env}}
{{.}}
{{end}}

{{end}}
`))

var fileTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(`
{{define "title"}}File {{.Hash}}{{end}}
{{define "body"}}
From: {{template "sessionlink" .Session.ID}}

URI: {{.URI}}

Hash: {{.Hash}}

Error: {{.Error}}

Contents

{{.Data}}

{{end}}
`))
<|endoftext|>


<commit_before>package model

import (
	"bytes"
	"go/format"
	"io"
	"text/template"
)

// Generate writes a Go file to the given writer.
func GenerateEndpoints(endpoints interface{}, w io.Writer) error {
	tmpl, err := template.New("endpoints").Parse(t)
	if err != nil {
		return err
	}

	out := bytes.NewBuffer(nil)
	if err := tmpl.Execute(out, endpoints); err != nil {
		return err
	}

	b, err := format.Source(bytes.TrimSpace(out.Bytes()))
	if err != nil {
		return err
	}

	_, err = io.Copy(w, bytes.NewReader(b))
	return err
}

const t = `
package aws

// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.

type endpointStruct struct {
	Version   int
	Endpoints map[string]endpointEntry
}

type endpointEntry struct {
	Endpoint string
}

var endpointsMap = endpointStruct{
	Version: {{ .Version }},
	Endpoints: map[string]endpointEntry{
		{{ range $key, $entry := .Endpoints }}"{{ $key }}": endpointEntry{
			Endpoint: "{{ $entry.Endpoint }}",
		},
		{{ end }}
	},
}
`
<commit_msg>Refactor endpoints generator code<commit_after>package model

import (
	"bytes"
	"go/format"
	"io"
	"text/template"
)

// Generate writes a Go file to the given writer.
func GenerateEndpoints(endpoints interface{}, w io.Writer) error {
	tmpl, err := template.New("endpoints").Parse(t)
	if err != nil {
		return err
	}

	out := bytes.NewBuffer(nil)
	if err := tmpl.Execute(out, endpoints); err != nil {
		return err
	}

	b, err := format.Source(bytes.TrimSpace(out.Bytes()))
	if err != nil {
		return err
	}

	_, err = io.Copy(w, bytes.NewReader(b))
	return err
}

const t = `
package endpoints

// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.

type endpointStruct struct {
	Version   int
	Endpoints map[string]endpointEntry
}

type endpointEntry struct {
	Endpoint string
}

var endpointsMap = endpointStruct{
	Version: {{ .Version }},
	Endpoints: map[string]endpointEntry{
		{{ range $key, $entry := .Endpoints }}"{{ $key }}": endpointEntry{
			Endpoint: "{{ $entry.Endpoint }}",
		},
		{{ end }}
	},
}
`
<|endoftext|>


<commit_before>// Copyright (c) 2016 by Richard A. Wilkes. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with
// this file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible With Secondary Licenses", as
// defined by the Mozilla Public License, version 2.0.

package draw

import (
	"github.com/richardwilkes/geom"
	"github.com/richardwilkes/ui/color"
	// #cgo pkg-config: pangocairo
	// #include <pango/pangocairo.h>
	"C"
)

// PaintKind possibilities.
const (
	PaintKindColor          PaintKind = C.CAIRO_PATTERN_TYPE_SOLID
	PaintKindImage          PaintKind = C.CAIRO_PATTERN_TYPE_SURFACE
	PaintKindLinearGradient PaintKind = C.CAIRO_PATTERN_TYPE_LINEAR
	PaintKindRadialGradient PaintKind = C.CAIRO_PATTERN_TYPE_RADIAL
)

// PaintKind defines the possible types of Paint.
type PaintKind int

const (
	// Pixels outside of the pattern are fully transparent.
	PaintModeNone PaintMode = C.CAIRO_EXTEND_NONE
	// The pattern is tiled by repeating.
	PaintModeRepeat PaintMode = C.CAIRO_EXTEND_REPEAT
	// The pattern is tiled by reflecting at the edges.
	PaintModeReflect PaintMode = C.CAIRO_EXTEND_REFLECT
	// Pixels outside of the pattern copy the closest pixel from the source.
	PaintModePad PaintMode = C.CAIRO_EXTEND_PAD
)

// PaintMode defines how pixels outside a pattern's space are filled in.
type PaintMode int

const (
	// FilterModeFast provides a high-performance filter, with quality similar to FilterModeNearest.
	FilterModeFast FilterMode = C.CAIRO_FILTER_FAST
	// FilterModeGood provides a reasonable-performance filter, with quality similar to
	// FilterModeBilinear.
	FilterModeGood FilterMode = C.CAIRO_FILTER_GOOD
	// FilterModeBest provides the highest quality filter available, but performance may not be
	// suitable for interactive use.
	FilterModeBest FilterMode = C.CAIRO_FILTER_BEST
	// FilterModeNearest provides a nearest-neighbor filter.
	FilterModeNearest FilterMode = C.CAIRO_FILTER_NEAREST
	// FilterModeBilinear provides linear interpolation in two dimensions.
	FilterModeBilinear FilterMode = C.CAIRO_FILTER_BILINEAR
)

// FilterMode defines the type of filtering to be used when reading pixel values.
type FilterMode int

type Paint struct {
	pattern *C.cairo_pattern_t
}

func NewColorPaint(color color.Color) Paint {
	return Paint{pattern: C.cairo_pattern_create_rgba(C.double(color.RedIntensity()), C.double(color.GreenIntensity()), C.double(color.BlueIntensity()), C.double(color.AlphaIntensity()))}
}

func NewImagePaint(img *Image) Paint {
	return Paint{pattern: C.cairo_pattern_create_for_surface(img.surface)}
}

func NewLinearGradientPaint(gradient *Gradient, sx, sy, ex, ey float64) Paint {
	pattern := C.cairo_pattern_create_linear(C.double(sx), C.double(sy), C.double(ex), C.double(ey))
	for _, one := range gradient.Stops {
		C.cairo_pattern_add_color_stop_rgba(pattern, C.double(one.Location), C.double(one.Color.RedIntensity()), C.double(one.Color.GreenIntensity()), C.double(one.Color.BlueIntensity()), C.double(one.Color.AlphaIntensity()))
	}
	return Paint{pattern: pattern}
}

func NewRadialGradientPaint(gradient *Gradient, scx, scy, startRadius, ecx, ecy, endRadius float64) Paint {
	pattern := C.cairo_pattern_create_radial(C.double(scx), C.double(scy), C.double(startRadius), C.double(ecx), C.double(ecy), C.double(endRadius))
	for _, one := range gradient.Stops {
		C.cairo_pattern_add_color_stop_rgba(pattern, C.double(one.Location), C.double(one.Color.RedIntensity()), C.double(one.Color.GreenIntensity()), C.double(one.Color.BlueIntensity()), C.double(one.Color.AlphaIntensity()))
	}
	return Paint{pattern: pattern}
}

func (p Paint) PaintMode() PaintMode {
	return PaintMode(C.cairo_pattern_get_extend(p.pattern))
}

func (p Paint) SetPaintMode(mode PaintMode) {
	C.cairo_pattern_set_extend(p.pattern, C.cairo_extend_t(mode))
}

func (p Paint) FilterMode() FilterMode {
	return FilterMode(C.cairo_pattern_get_filter(p.pattern))
}

func (p Paint) SetFilterMode(mode FilterMode) {
	C.cairo_pattern_set_filter(p.pattern, C.cairo_filter_t(mode))
}

func (p Paint) Matrix() *geom.Matrix {
	var matrix C.cairo_matrix_t
	C.cairo_pattern_get_matrix(p.pattern, &matrix)
	return fromCairoMatrix(&matrix)
}

func (p Paint) SetMatrix(matrix *geom.Matrix) {
	C.cairo_pattern_set_matrix(p.pattern, toCairoMatrix(matrix))
}

func (p Paint) Kind() PaintKind {
	return PaintKind(C.cairo_pattern_get_type(p.pattern))
}

func (p Paint) Dispose() {
	C.cairo_pattern_destroy(p.pattern)
	p.pattern = nil
}
<commit_msg>Add comments<commit_after>// Copyright (c) 2016 by Richard A. Wilkes. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with
// this file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible With Secondary Licenses", as
// defined by the Mozilla Public License, version 2.0.

package draw

import (
	"github.com/richardwilkes/geom"
	"github.com/richardwilkes/ui/color"
	// #cgo pkg-config: pangocairo
	// #include <pango/pangocairo.h>
	"C"
)

// PaintKind possibilities.
const (
	PaintKindColor          PaintKind = C.CAIRO_PATTERN_TYPE_SOLID
	PaintKindImage          PaintKind = C.CAIRO_PATTERN_TYPE_SURFACE
	PaintKindLinearGradient PaintKind = C.CAIRO_PATTERN_TYPE_LINEAR
	PaintKindRadialGradient PaintKind = C.CAIRO_PATTERN_TYPE_RADIAL
)

// PaintKind defines the possible types of Paint.
type PaintKind int

const (
	// PaintModeNone pixels outside of the pattern are fully transparent.
	PaintModeNone PaintMode = C.CAIRO_EXTEND_NONE
	// PaintModeRepeat the pattern is tiled by repeating.
	PaintModeRepeat PaintMode = C.CAIRO_EXTEND_REPEAT
	// PaintModeReflect the pattern is tiled by reflecting at the edges.
	PaintModeReflect PaintMode = C.CAIRO_EXTEND_REFLECT
	// PaintModePad pixels outside of the pattern copy the closest pixel from the source.
	PaintModePad PaintMode = C.CAIRO_EXTEND_PAD
)

// PaintMode defines how pixels outside a pattern's space are filled in.
type PaintMode int

const (
	// FilterModeFast provides a high-performance filter, with quality similar to FilterModeNearest.
	FilterModeFast FilterMode = C.CAIRO_FILTER_FAST
	// FilterModeGood provides a reasonable-performance filter, with quality similar to
	// FilterModeBilinear.
	FilterModeGood FilterMode = C.CAIRO_FILTER_GOOD
	// FilterModeBest provides the highest quality filter available, but performance may not be
	// suitable for interactive use.
	FilterModeBest FilterMode = C.CAIRO_FILTER_BEST
	// FilterModeNearest provides a nearest-neighbor filter.
	FilterModeNearest FilterMode = C.CAIRO_FILTER_NEAREST
	// FilterModeBilinear provides linear interpolation in two dimensions.
	FilterModeBilinear FilterMode = C.CAIRO_FILTER_BILINEAR
)

// FilterMode defines the type of filtering to be used when reading pixel values.
type FilterMode int

// Paint holds patterns used when filling and stroking paths.
type Paint struct {
	pattern *C.cairo_pattern_t
}

// NewColorPaint creates a new Paint from a color.
func NewColorPaint(color color.Color) Paint {
	return Paint{pattern: C.cairo_pattern_create_rgba(C.double(color.RedIntensity()), C.double(color.GreenIntensity()), C.double(color.BlueIntensity()), C.double(color.AlphaIntensity()))}
}

// NewImagePaint creates a new Paint from an image.
func NewImagePaint(img *Image) Paint {
	return Paint{pattern: C.cairo_pattern_create_for_surface(img.surface)}
}

// NewLinearGradientPaint creates a new Paint from a gradient that is spread across the specified
// line.
func NewLinearGradientPaint(gradient *Gradient, sx, sy, ex, ey float64) Paint {
	pattern := C.cairo_pattern_create_linear(C.double(sx), C.double(sy), C.double(ex), C.double(ey))
	for _, one := range gradient.Stops {
		C.cairo_pattern_add_color_stop_rgba(pattern, C.double(one.Location), C.double(one.Color.RedIntensity()), C.double(one.Color.GreenIntensity()), C.double(one.Color.BlueIntensity()), C.double(one.Color.AlphaIntensity()))
	}
	return Paint{pattern: pattern}
}

// NewRadialGradientPaint creates a new Paint from a gradient that radiates from one circle to
// another.
func NewRadialGradientPaint(gradient *Gradient, scx, scy, startRadius, ecx, ecy, endRadius float64) Paint {
	pattern := C.cairo_pattern_create_radial(C.double(scx), C.double(scy), C.double(startRadius), C.double(ecx), C.double(ecy), C.double(endRadius))
	for _, one := range gradient.Stops {
		C.cairo_pattern_add_color_stop_rgba(pattern, C.double(one.Location), C.double(one.Color.RedIntensity()), C.double(one.Color.GreenIntensity()), C.double(one.Color.BlueIntensity()), C.double(one.Color.AlphaIntensity()))
	}
	return Paint{pattern: pattern}
}

// PaintMode returns the PaintMode of this Paint.
func (p Paint) PaintMode() PaintMode {
	return PaintMode(C.cairo_pattern_get_extend(p.pattern))
}

// SetPaintMode sets the PaintMode of this Paint.
func (p Paint) SetPaintMode(mode PaintMode) {
	C.cairo_pattern_set_extend(p.pattern, C.cairo_extend_t(mode))
}

// FilterMode returns the FilterMode of this Paint.
func (p Paint) FilterMode() FilterMode {
	return FilterMode(C.cairo_pattern_get_filter(p.pattern))
}

// SetFilterMode sets the FilterMode of this Paint.
func (p Paint) SetFilterMode(mode FilterMode) {
	C.cairo_pattern_set_filter(p.pattern, C.cairo_filter_t(mode))
}

// Matrix returns the Matrix of this Paint.
func (p Paint) Matrix() *geom.Matrix {
	var matrix C.cairo_matrix_t
	C.cairo_pattern_get_matrix(p.pattern, &matrix)
	return fromCairoMatrix(&matrix)
}

// SetMatrix sets the Matrix of this Paint.
func (p Paint) SetMatrix(matrix *geom.Matrix) {
	C.cairo_pattern_set_matrix(p.pattern, toCairoMatrix(matrix))
}

// Kind returns the PaintKind of this Paint.
func (p Paint) Kind() PaintKind {
	return PaintKind(C.cairo_pattern_get_type(p.pattern))
}

// Dispose releases the underlying resources used by this Paint.
func (p Paint) Dispose() {
	C.cairo_pattern_destroy(p.pattern)
	p.pattern = nil
}
<|endoftext|>


<commit_before>package keeper

import (
	"context"

	sdk "github.com/cosmos/cosmos-sdk/types"
	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
	"github.com/zigbee-alliance/distributed-compliance-ledger/x/dclupgrade/types"
)

func (k msgServer) ApproveUpgrade(goCtx context.Context, msg *types.MsgApproveUpgrade) (*types.MsgApproveUpgradeResponse, error) {
	ctx := sdk.UnwrapSDKContext(goCtx)

	creatorAddr, err := sdk.AccAddressFromBech32(msg.Creator)
	if err != nil {
		return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid Address: (%s)", err)
	}

	// check if message creator has enough rights to approve upgrade
	if !k.dclauthKeeper.HasRole(ctx, creatorAddr, types.UpgradeApprovalRole) {
		return nil, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized,
			"MsgApproveUpgrade transaction should be signed by an account with the %s role",
			types.UpgradeApprovalRole,
		)
	}

	// check if proposed upgrade exists
	proposedUpgrade, isFound := k.GetProposedUpgrade(ctx, msg.Name)
	if !isFound {
		return nil, types.NewErrProposedUpgradeDoesNotExist(msg.Name)
	}

	// check if proposed upgrade already has approval form message creator
	if proposedUpgrade.HasApprovalFrom(creatorAddr) {
		return nil, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized,
			"Proposed upgrade with name=%v already has approval from=%v",
			msg.Name, msg.Creator,
		)
	}

	// append approval
	grant := types.Grant{
		Address: creatorAddr.String(),
		Time:    msg.Time,
		Info:    msg.Info,
	}

	proposedUpgrade.Approvals = append(proposedUpgrade.Approvals, &grant)

	// check if proposed upgrade has enough approvals
	if len(proposedUpgrade.Approvals) == k.UpgradeApprovalsCount(ctx) {
		// schedule upgrade
		err = k.upgradeKeeper.ScheduleUpgrade(ctx, proposedUpgrade.Plan)
		if err != nil {
			return nil, err
		}

		// remove proposed upgrade
		k.RemoveProposedUpgrade(ctx, proposedUpgrade.Plan.Name)

		approvedUpgrage := types.ApprovedUpgrade(proposedUpgrade)
		k.SetApprovedUpgrade(ctx, approvedUpgrage)
	} else {
		// update proposed upgrade
		k.SetProposedUpgrade(ctx, proposedUpgrade)
	}

	return &types.MsgApproveUpgradeResponse{}, nil
}
<commit_msg>Add check for has rejected already from this Trustee, who is going to approve upgrade<commit_after>package keeper

import (
	"context"

	sdk "github.com/cosmos/cosmos-sdk/types"
	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
	"github.com/zigbee-alliance/distributed-compliance-ledger/x/dclupgrade/types"
)

func (k msgServer) ApproveUpgrade(goCtx context.Context, msg *types.MsgApproveUpgrade) (*types.MsgApproveUpgradeResponse, error) {
	ctx := sdk.UnwrapSDKContext(goCtx)

	creatorAddr, err := sdk.AccAddressFromBech32(msg.Creator)
	if err != nil {
		return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid Address: (%s)", err)
	}

	// check if message creator has enough rights to approve upgrade
	if !k.dclauthKeeper.HasRole(ctx, creatorAddr, types.UpgradeApprovalRole) {
		return nil, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized,
			"MsgApproveUpgrade transaction should be signed by an account with the %s role",
			types.UpgradeApprovalRole,
		)
	}

	// check if proposed upgrade exists
	proposedUpgrade, isFound := k.GetProposedUpgrade(ctx, msg.Name)
	if !isFound {
		return nil, types.NewErrProposedUpgradeDoesNotExist(msg.Name)
	}

	// check if proposed upgrade already has reject from message creator
	if proposedUpgrade.HasRejectFrom(creatorAddr) {
		return nil, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized,
			"Proposed upgrade with name=%v already has reject from=%v",
			msg.Name, msg.Creator,
		)
	}

	// check if proposed upgrade already has approval form message creator
	if proposedUpgrade.HasApprovalFrom(creatorAddr) {
		return nil, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized,
			"Proposed upgrade with name=%v already has approval from=%v",
			msg.Name, msg.Creator,
		)
	}

	// append approval
	grant := types.Grant{
		Address: creatorAddr.String(),
		Time:    msg.Time,
		Info:    msg.Info,
	}

	proposedUpgrade.Approvals = append(proposedUpgrade.Approvals, &grant)

	// check if proposed upgrade has enough approvals
	if len(proposedUpgrade.Approvals) == k.UpgradeApprovalsCount(ctx) {
		// schedule upgrade
		err = k.upgradeKeeper.ScheduleUpgrade(ctx, proposedUpgrade.Plan)
		if err != nil {
			return nil, err
		}

		// remove proposed upgrade
		k.RemoveProposedUpgrade(ctx, proposedUpgrade.Plan.Name)

		approvedUpgrage := types.ApprovedUpgrade(proposedUpgrade)
		k.SetApprovedUpgrade(ctx, approvedUpgrage)
	} else {
		// update proposed upgrade
		k.SetProposedUpgrade(ctx, proposedUpgrade)
	}

	return &types.MsgApproveUpgradeResponse{}, nil
}
<|endoftext|>


<commit_before>// Package github implements a simple client to consume gitlab API.
package gogitlab

import (
	"bytes"
	"crypto/tls"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

const (
	dasboard_feed_path = "/dashboard.atom"
)

type Gitlab struct {
	BaseUrl      string
	ApiPath      string
	RepoFeedPath string
	Token        string
	Client       *http.Client
}

const (
	dateLayout = "2006-01-02T15:04:05-07:00"
)

func NewGitlab(baseUrl, apiPath, token string) *Gitlab {

	config := &tls.Config{InsecureSkipVerify: true}
	tr := &http.Transport{TLSClientConfig: config}
	client := &http.Client{Transport: tr}

	return &Gitlab{
		BaseUrl: baseUrl,
		ApiPath: apiPath,
		Token:   token,
		Client:  client,
	}
}

func (g *Gitlab) ResourceUrl(url string, params map[string]string) string {

	if params != nil {
		for key, val := range params {
			url = strings.Replace(url, key, val, -1)
		}
	}

	url = g.BaseUrl + g.ApiPath + url + "?private_token=" + g.Token
	return url
}

func (g *Gitlab) buildAndExecRequest(method, url string, body []byte) ([]byte, error) {

	var req *http.Request
	var err error

	if body != nil {
		reader := bytes.NewReader(body)
		req, err = http.NewRequest(method, url, reader)
	} else {
		req, err = http.NewRequest(method, url, nil)
	}
	if err != nil {
		panic("Error while building gitlab request")
	}

	resp, err := g.Client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("Client.Do error: %q", err)
	}
	defer resp.Body.Close()
	contents, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("%s", err)
	}

	if resp.StatusCode >= 400 {
		err = fmt.Errorf("*Gitlab.buildAndExecRequest failed: <%d> %s", resp.StatusCode, req.URL)
	}

	return contents, err
}

func (g *Gitlab) ResourceUrlRaw(u string, params map[string]string) (string, string) {

	if params != nil {
		for key, val := range params {
			u = strings.Replace(u, key, val, -1)
		}
	}

	path := u
	u = g.BaseUrl + g.ApiPath + path + "?private_token=" + g.Token
	p, err := url.Parse(u)
	if err != nil {
		return u, ""
	}
	opaque := "//" + p.Host + g.ApiPath + path
	return u, opaque
}

func (g *Gitlab) buildAndExecRequestRaw(method, url, opaque string, body []byte) ([]byte, error) {

	var req *http.Request
	var err error

	if body != nil {
		reader := bytes.NewReader(body)
		req, err = http.NewRequest(method, url, reader)
	} else {
		req, err = http.NewRequest(method, url, nil)
	}
	if err != nil {
		panic("Error while building gitlab request")
	}

	if len(opaque) > 0 {
		req.URL.Opaque = opaque
	}

	resp, err := g.Client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("Client.Do error: %q", err)
	}
	defer resp.Body.Close()
	contents, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("%s", err)
	}

	if resp.StatusCode >= 400 {
		err = fmt.Errorf("*Gitlab.buildAndExecRequestRaw failed: <%d> %s", resp.StatusCode, req.URL)
	}

	return contents, err
}
<commit_msg>Use cli flag to decide if client should skip certs verification<commit_after>// Package github implements a simple client to consume gitlab API.
package gogitlab

import (
	"bytes"
	"crypto/tls"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

const (
	dasboard_feed_path = "/dashboard.atom"
)

type Gitlab struct {
	BaseUrl      string
	ApiPath      string
	RepoFeedPath string
	Token        string
	Client       *http.Client
}

const (
	dateLayout = "2006-01-02T15:04:05-07:00"
)

var (
	skipCertVerify = flag.Bool("gitlab.skip-cert-check", false,
		`If set to true, gitlab client will skip certificate checking for https, possibly exposing your system to MITM attack.`)
)

func NewGitlab(baseUrl, apiPath, token string) *Gitlab {
	config := &tls.Config{InsecureSkipVerify: *skipCertVerify}
	tr := &http.Transport{TLSClientConfig: config}
	client := &http.Client{Transport: tr}

	return &Gitlab{
		BaseUrl: baseUrl,
		ApiPath: apiPath,
		Token:   token,
		Client:  client,
	}
}

func (g *Gitlab) ResourceUrl(url string, params map[string]string) string {

	if params != nil {
		for key, val := range params {
			url = strings.Replace(url, key, val, -1)
		}
	}

	url = g.BaseUrl + g.ApiPath + url + "?private_token=" + g.Token
	return url
}

func (g *Gitlab) buildAndExecRequest(method, url string, body []byte) ([]byte, error) {

	var req *http.Request
	var err error

	if body != nil {
		reader := bytes.NewReader(body)
		req, err = http.NewRequest(method, url, reader)
	} else {
		req, err = http.NewRequest(method, url, nil)
	}
	if err != nil {
		panic("Error while building gitlab request")
	}

	resp, err := g.Client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("Client.Do error: %q", err)
	}
	defer resp.Body.Close()
	contents, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("%s", err)
	}

	if resp.StatusCode >= 400 {
		err = fmt.Errorf("*Gitlab.buildAndExecRequest failed: <%d> %s", resp.StatusCode, req.URL)
	}

	return contents, err
}

func (g *Gitlab) ResourceUrlRaw(u string, params map[string]string) (string, string) {

	if params != nil {
		for key, val := range params {
			u = strings.Replace(u, key, val, -1)
		}
	}

	path := u
	u = g.BaseUrl + g.ApiPath + path + "?private_token=" + g.Token
	p, err := url.Parse(u)
	if err != nil {
		return u, ""
	}
	opaque := "//" + p.Host + g.ApiPath + path
	return u, opaque
}

func (g *Gitlab) buildAndExecRequestRaw(method, url, opaque string, body []byte) ([]byte, error) {

	var req *http.Request
	var err error

	if body != nil {
		reader := bytes.NewReader(body)
		req, err = http.NewRequest(method, url, reader)
	} else {
		req, err = http.NewRequest(method, url, nil)
	}
	if err != nil {
		panic("Error while building gitlab request")
	}

	if len(opaque) > 0 {
		req.URL.Opaque = opaque
	}

	resp, err := g.Client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("Client.Do error: %q", err)
	}
	defer resp.Body.Close()
	contents, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("%s", err)
	}

	if resp.StatusCode >= 400 {
		err = fmt.Errorf("*Gitlab.buildAndExecRequestRaw failed: <%d> %s", resp.StatusCode, req.URL)
	}

	return contents, err
}
<|endoftext|>


<commit_before>/*
 * Copyright 2016 ThoughtWorks, 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 agent

import (
	"bytes"
	"encoding/json"
	"github.com/bmatcuk/doublestar"
	"github.com/gocd-contrib/gocd-golang-agent/protocal"
	"github.com/gocd-contrib/gocd-golang-agent/stream"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"sort"
	"strings"
	"time"
)

var (
	DefaultSecretMask           = "********"
	DefaultCancelCommandTimeout = 25 * time.Second
	CancelCommandTimeout        = DefaultCancelCommandTimeout
	CancelBuildTimeout          = 30 * time.Second
)

type BuildSession struct {
	send      chan *protocal.Message
	console   io.Writer
	artifacts *Uploader
	command   *protocal.BuildCommand
	envs      map[string]string
	cancel    chan bool
	done      chan bool
	echo      *stream.SubstituteWriter
	secrets   *stream.SubstituteWriter

	buildId     string
	buildStatus string
}

func MakeBuildSession(buildId string,
	command *protocal.BuildCommand,
	console io.Writer,
	artifacts *Uploader,
	send chan *protocal.Message) *BuildSession {

	secrets := stream.NewSubstituteWriter(console)
	return &BuildSession{
		buildId:     buildId,
		buildStatus: protocal.BuildPassed,
		console:     console,
		artifacts:   artifacts,
		command:     command,
		send:        send,
		envs:        make(map[string]string),
		cancel:      make(chan bool),
		done:        make(chan bool),
		secrets:     secrets,
		echo:        stream.NewSubstituteWriter(secrets),
	}
}

func (s *BuildSession) Close() {
	close(s.cancel)
	select {
	case <-s.done:
	case <-time.After(CancelBuildTimeout):
		logger.Error.Printf("cancel build timeout(%v)", CancelBuildTimeout)
	}
}

func (s *BuildSession) isCanceled() bool {
	select {
	case <-s.cancel:
		return true
	default:
		return false
	}
}

func (s *BuildSession) Run() error {
	defer func() {
		s.send <- protocal.CompletedMessage(s.Report(""))
	}()
	return s.ProcessCommand()
}

func (s *BuildSession) ProcessCommand() error {
	defer func() {
		close(s.done)
	}()

	LogInfo("start process build command:")
	LogInfo(s.command.String())
	return s.process(s.command)
}

func (s *BuildSession) process(cmd *protocal.BuildCommand) (err error) {
	defer s.onCancel(cmd)

	if s.isCanceled() {
		LogDebug("Ignored command %v, because build is canceled", cmd.Name)
		return nil
	}

	LogDebug("procssing build command: %v\n", cmd)
	if !cmd.RunIfAny() && !cmd.RunIfMatch(s.buildStatus) {
		//skip, no failure
		return nil
	}
	if cmd.Test != nil {
		if cmd.Test.Command.Name != protocal.CommandTest {
			panic("a BuildCommand test should be test command")
		}
		_, err := s.processTestCommand(cmd.Test.Command)
		success := err == nil
		if success != cmd.Test.Expectation {
			LogDebug("test failed: %v", err)
			return nil
		}
	}

	switch cmd.Name {
	case protocal.CommandCompose:
		return s.processCompose(cmd)
	case protocal.CommandExport:
		s.processExport(cmd)
	case protocal.CommandEcho:
		s.processEcho(cmd)
	case protocal.CommandSecret:
		s.processSecret(cmd)
	case protocal.CommandReportCurrentStatus, protocal.CommandReportCompleting:
		jobState := cmd.Args["jobState"]
		s.send <- protocal.ReportMessage(cmd.Name, s.Report(jobState))
	case protocal.CommandTest:
		err = s.processTest(cmd)
	case protocal.CommandExec:
		err = s.processExec(cmd, s.secrets)
	case protocal.CommandMkdirs:
		err = s.processMkdirs(cmd)
	case protocal.CommandCleandir:
		err = s.processCleandir(cmd)
	case protocal.CommandUploadArtifact:
		err = s.processUploadArtifact(cmd)
	case protocal.CommandFail:
		err = Err(cmd.Args["0"])
	default:
		s.warn("Golang Agent does not support build comamnd '%v', which means, related GoCD feature will not be supported.", cmd.Name)
	}

	if s.isCanceled() {
		LogInfo("Build canceled")
		s.buildStatus = protocal.BuildCanceled
	} else if err != nil {
		LogInfo("Build failed: %v", err)
		s.buildStatus = protocal.BuildFailed
		s.ConsoleLog(Sprintf("%v\n", err))
	}

	return
}

func (s *BuildSession) onCancel(cmd *protocal.BuildCommand) {
	if cmd.OnCancel == nil || !s.isCanceled() {
		return
	}
	cancel := MakeBuildSession(s.buildId, cmd.OnCancel, s.console, s.artifacts, s.send)
	go func() {
		cancel.ProcessCommand()
	}()
	select {
	case <-cancel.done:
	case <-time.After(CancelCommandTimeout):
		s.warn("Kill cancel task because it did not finish in %v.", CancelCommandTimeout)
		cancel.Close()
	}
}

func (s *BuildSession) processSecret(cmd *protocal.BuildCommand) {
	value := cmd.Args["value"]
	substitution := cmd.Args["substitution"]
	if substitution == "" {
		substitution = DefaultSecretMask
	}
	s.secrets.Substitutions[value] = substitution
}

func (s *BuildSession) processCleandir(cmd *protocal.BuildCommand) (err error) {
	path := cmd.Args["path"]
	wd, err := filepath.Abs(cmd.WorkingDirectory)
	if err != nil {
		return
	}
	var allows []string
	err = json.Unmarshal([]byte(cmd.Args["allowed"]), &allows)
	if err != nil {
		return
	}
	return Cleandir(filepath.Join(wd, path), allows...)
}

func (s *BuildSession) processMkdirs(cmd *protocal.BuildCommand) error {
	path := cmd.Args["path"]
	wd, err := filepath.Abs(cmd.WorkingDirectory)
	if err != nil {
		return err
	}
	return Mkdirs(filepath.Join(wd, path))
}

func (s *BuildSession) processUploadArtifact(cmd *protocal.BuildCommand) error {
	src := cmd.Args["src"]
	destDir := cmd.Args["dest"]

	wd, err := filepath.Abs(cmd.WorkingDirectory)
	if err != nil {
		return err
	}
	absSrc := filepath.Join(wd, src)
	return s.uploadArtifacts(absSrc, strings.Replace(destDir, "\\", "/", -1))
}

func (s *BuildSession) uploadArtifacts(source, destDir string) (err error) {
	if strings.Contains(source, "*") {
		matches, err := doublestar.Glob(source)
		sort.Strings(matches)
		if err != nil {
			return err
		}
		base := BaseDirOfPathWithWildcard(source)
		baseLen := len(base)
		for _, file := range matches {
			fileDir, _ := filepath.Split(file)
			dest := Join("/", destDir, fileDir[baseLen:len(fileDir)-1])
			err = s.uploadArtifacts(file, dest)
			if err != nil {
				return err
			}
		}
		return nil
	}

	srcInfo, err := os.Stat(source)
	if err != nil {
		return
	}
	s.ConsoleLog("Uploading artifacts from %v to %v\n", source, destDescription(destDir))

	var destPath string
	if destDir != "" {
		destPath = Join("/", destDir, srcInfo.Name())
	} else {
		destPath = srcInfo.Name()
	}
	destURL := AppendUrlParam(AppendUrlPath(s.artifacts.BaseURL, destDir),
		"buildId", s.buildId)
	return s.artifacts.Upload(source, destPath, destURL)
}

func (s *BuildSession) processExec(cmd *protocal.BuildCommand, output io.Writer) error {
	args := cmd.ExtractArgList(len(cmd.Args))
	execCmd := exec.Command(args[0], args[1:]...)
	execCmd.Stdout = output
	execCmd.Stderr = output
	execCmd.Dir = cmd.WorkingDirectory
	done := make(chan error)
	go func() {
		done <- execCmd.Run()
	}()

	select {
	case <-s.cancel:
		LogDebug("received cancel signal")
		LogInfo("killing process(%v) %v", execCmd.Process, cmd.Args)
		if err := execCmd.Process.Kill(); err != nil {
			s.ConsoleLog("kill command %v failed, error: %v\n", cmd.Args, err)
		} else {
			LogInfo("Process %v is killed", execCmd.Process)
		}
		return Err("%v is canceled", cmd.Args)
	case err := <-done:
		return err
	}
}

func (s *BuildSession) processTestCommand(cmd *protocal.BuildCommand) (bytes.Buffer, error) {
	var output bytes.Buffer
	session := MakeBuildSession(s.buildId, cmd, &output, s.artifacts, s.send)
	session.cancel = s.cancel
	err := session.ProcessCommand()
	return output, err
}

func (s *BuildSession) processTest(cmd *protocal.BuildCommand) error {
	flag := cmd.Args["flag"]

	switch flag {
	case "-d":
		targetPath := cmd.Args["left"]
		info, err := os.Stat(targetPath)
		if err != nil {
			return err
		}
		if info.IsDir() {
			return nil
		} else {
			return Err("%v is not a directory", targetPath)
		}
	case "-f":
		targetPath := cmd.Args["left"]
		info, err := os.Stat(targetPath)
		if err != nil {
			return err
		}
		if info.IsDir() {
			return Err("%v is not a file", targetPath)
		} else {
			return nil
		}
	case "-eq":
		output, err := s.processTestCommand(cmd.SubCommands[0])
		if err != nil {
			LogDebug("test -eq exec command error: %v", err)
		}
		expected := strings.TrimSpace(cmd.Args["left"])
		actual := strings.TrimSpace(output.String())
		if expected != actual {
			return Err("expected '%v', but was '%v'", expected, actual)
		}
		return nil
	}

	return Err("unknown test flag")
}

func (s *BuildSession) Report(jobState string) *protocal.Report {
	return &protocal.Report{
		AgentRuntimeInfo: GetAgentRuntimeInfo(),
		BuildId:          s.buildId,
		JobState:         jobState,
		Result:           s.buildStatus,
	}
}

func (s *BuildSession) ConsoleLog(format string, a ...interface{}) {
	s.console.Write([]byte(Sprintf(format, a...)))
}

func (s *BuildSession) warn(format string, a ...interface{}) {
	s.ConsoleLog(Sprintf("WARN: %v\n", format), a...)
}

func (s *BuildSession) ReplaceEcho(name string, value interface{}) {
	s.echo.Substitutions[name] = value
}

func (s *BuildSession) processEcho(cmd *protocal.BuildCommand) {
	for _, line := range cmd.ExtractArgList(len(cmd.Args)) {
		s.echo.Write([]byte(line))
		s.echo.Write([]byte{'\n'})
	}
}

func (s *BuildSession) processExport(cmd *protocal.BuildCommand) {
	msg := "setting environment variable '%v' to value '%v'"
	name := cmd.Args["name"]
	value, ok := cmd.Args["value"]
	if !ok {
		s.ConsoleLog(msg, name, os.Getenv(name))
		s.ConsoleLog("\n")
		return
	}
	secure := cmd.Args["secure"]
	displayValue := value
	if secure == "true" {
		displayValue = DefaultSecretMask
	}
	_, override := s.envs[name]
	if override || os.Getenv(name) != "" {
		msg = "overriding environment variable '%v' with value '%v'"
	}
	s.envs[name] = value
	s.ConsoleLog(msg, name, displayValue)
	s.ConsoleLog("\n")
}

func (s *BuildSession) processCompose(cmd *protocal.BuildCommand) error {
	var err error
	for _, sub := range cmd.SubCommands {
		if err != nil {
			s.process(sub)
		} else {
			err = s.process(sub)
		}
	}
	return err
}

func destDescription(path string) string {
	if path == "" {
		return "[defaultRoot]"
	} else {
		return path
	}
}
<commit_msg>clean up consolelog \n<commit_after>/*
 * Copyright 2016 ThoughtWorks, 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 agent

import (
	"bytes"
	"encoding/json"
	"github.com/bmatcuk/doublestar"
	"github.com/gocd-contrib/gocd-golang-agent/protocal"
	"github.com/gocd-contrib/gocd-golang-agent/stream"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"sort"
	"strings"
	"time"
)

var (
	DefaultSecretMask           = "********"
	DefaultCancelCommandTimeout = 25 * time.Second
	CancelCommandTimeout        = DefaultCancelCommandTimeout
	CancelBuildTimeout          = 30 * time.Second
)

type BuildSession struct {
	send      chan *protocal.Message
	console   io.Writer
	artifacts *Uploader
	command   *protocal.BuildCommand
	envs      map[string]string
	cancel    chan bool
	done      chan bool
	echo      *stream.SubstituteWriter
	secrets   *stream.SubstituteWriter

	buildId     string
	buildStatus string
}

func MakeBuildSession(buildId string,
	command *protocal.BuildCommand,
	console io.Writer,
	artifacts *Uploader,
	send chan *protocal.Message) *BuildSession {

	secrets := stream.NewSubstituteWriter(console)
	return &BuildSession{
		buildId:     buildId,
		buildStatus: protocal.BuildPassed,
		console:     console,
		artifacts:   artifacts,
		command:     command,
		send:        send,
		envs:        make(map[string]string),
		cancel:      make(chan bool),
		done:        make(chan bool),
		secrets:     secrets,
		echo:        stream.NewSubstituteWriter(secrets),
	}
}

func (s *BuildSession) Close() {
	close(s.cancel)
	select {
	case <-s.done:
	case <-time.After(CancelBuildTimeout):
		logger.Error.Printf("cancel build timeout(%v)", CancelBuildTimeout)
	}
}

func (s *BuildSession) isCanceled() bool {
	select {
	case <-s.cancel:
		return true
	default:
		return false
	}
}

func (s *BuildSession) Run() error {
	defer func() {
		s.send <- protocal.CompletedMessage(s.Report(""))
	}()
	return s.ProcessCommand()
}

func (s *BuildSession) ProcessCommand() error {
	defer func() {
		close(s.done)
	}()

	LogInfo("start process build command:")
	LogInfo(s.command.String())
	return s.process(s.command)
}

func (s *BuildSession) process(cmd *protocal.BuildCommand) (err error) {
	defer s.onCancel(cmd)

	if s.isCanceled() {
		LogDebug("Ignored command %v, because build is canceled", cmd.Name)
		return nil
	}

	LogDebug("procssing build command: %v\n", cmd)
	if !cmd.RunIfAny() && !cmd.RunIfMatch(s.buildStatus) {
		//skip, no failure
		return nil
	}
	if cmd.Test != nil {
		if cmd.Test.Command.Name != protocal.CommandTest {
			panic("a BuildCommand test should be test command")
		}
		_, err := s.processTestCommand(cmd.Test.Command)
		success := err == nil
		if success != cmd.Test.Expectation {
			LogDebug("test failed: %v", err)
			return nil
		}
	}

	switch cmd.Name {
	case protocal.CommandCompose:
		return s.processCompose(cmd)
	case protocal.CommandExport:
		s.processExport(cmd)
	case protocal.CommandEcho:
		s.processEcho(cmd)
	case protocal.CommandSecret:
		s.processSecret(cmd)
	case protocal.CommandReportCurrentStatus, protocal.CommandReportCompleting:
		jobState := cmd.Args["jobState"]
		s.send <- protocal.ReportMessage(cmd.Name, s.Report(jobState))
	case protocal.CommandTest:
		err = s.processTest(cmd)
	case protocal.CommandExec:
		err = s.processExec(cmd, s.secrets)
	case protocal.CommandMkdirs:
		err = s.processMkdirs(cmd)
	case protocal.CommandCleandir:
		err = s.processCleandir(cmd)
	case protocal.CommandUploadArtifact:
		err = s.processUploadArtifact(cmd)
	case protocal.CommandFail:
		err = Err(cmd.Args["0"])
	default:
		s.warn("Golang Agent does not support build comamnd '%v', which means, related GoCD feature will not be supported.", cmd.Name)
	}

	if s.isCanceled() {
		LogInfo("Build canceled")
		s.buildStatus = protocal.BuildCanceled
	} else if err != nil {
		LogInfo("Build failed: %v", err)
		s.buildStatus = protocal.BuildFailed
		s.ConsoleLog(Sprintf("%v\n", err))
	}

	return
}

func (s *BuildSession) onCancel(cmd *protocal.BuildCommand) {
	if cmd.OnCancel == nil || !s.isCanceled() {
		return
	}
	cancel := MakeBuildSession(s.buildId, cmd.OnCancel, s.console, s.artifacts, s.send)
	go func() {
		cancel.ProcessCommand()
	}()
	select {
	case <-cancel.done:
	case <-time.After(CancelCommandTimeout):
		s.warn("Kill cancel task because it did not finish in %v.", CancelCommandTimeout)
		cancel.Close()
	}
}

func (s *BuildSession) processSecret(cmd *protocal.BuildCommand) {
	value := cmd.Args["value"]
	substitution := cmd.Args["substitution"]
	if substitution == "" {
		substitution = DefaultSecretMask
	}
	s.secrets.Substitutions[value] = substitution
}

func (s *BuildSession) processCleandir(cmd *protocal.BuildCommand) (err error) {
	path := cmd.Args["path"]
	wd, err := filepath.Abs(cmd.WorkingDirectory)
	if err != nil {
		return
	}
	var allows []string
	err = json.Unmarshal([]byte(cmd.Args["allowed"]), &allows)
	if err != nil {
		return
	}
	return Cleandir(filepath.Join(wd, path), allows...)
}

func (s *BuildSession) processMkdirs(cmd *protocal.BuildCommand) error {
	path := cmd.Args["path"]
	wd, err := filepath.Abs(cmd.WorkingDirectory)
	if err != nil {
		return err
	}
	return Mkdirs(filepath.Join(wd, path))
}

func (s *BuildSession) processUploadArtifact(cmd *protocal.BuildCommand) error {
	src := cmd.Args["src"]
	destDir := cmd.Args["dest"]

	wd, err := filepath.Abs(cmd.WorkingDirectory)
	if err != nil {
		return err
	}
	absSrc := filepath.Join(wd, src)
	return s.uploadArtifacts(absSrc, strings.Replace(destDir, "\\", "/", -1))
}

func (s *BuildSession) uploadArtifacts(source, destDir string) (err error) {
	if strings.Contains(source, "*") {
		matches, err := doublestar.Glob(source)
		sort.Strings(matches)
		if err != nil {
			return err
		}
		base := BaseDirOfPathWithWildcard(source)
		baseLen := len(base)
		for _, file := range matches {
			fileDir, _ := filepath.Split(file)
			dest := Join("/", destDir, fileDir[baseLen:len(fileDir)-1])
			err = s.uploadArtifacts(file, dest)
			if err != nil {
				return err
			}
		}
		return nil
	}

	srcInfo, err := os.Stat(source)
	if err != nil {
		return
	}
	s.ConsoleLog("Uploading artifacts from %v to %v\n", source, destDescription(destDir))

	var destPath string
	if destDir != "" {
		destPath = Join("/", destDir, srcInfo.Name())
	} else {
		destPath = srcInfo.Name()
	}
	destURL := AppendUrlParam(AppendUrlPath(s.artifacts.BaseURL, destDir),
		"buildId", s.buildId)
	return s.artifacts.Upload(source, destPath, destURL)
}

func (s *BuildSession) processExec(cmd *protocal.BuildCommand, output io.Writer) error {
	args := cmd.ExtractArgList(len(cmd.Args))
	execCmd := exec.Command(args[0], args[1:]...)
	execCmd.Stdout = output
	execCmd.Stderr = output
	execCmd.Dir = cmd.WorkingDirectory
	done := make(chan error)
	go func() {
		done <- execCmd.Run()
	}()

	select {
	case <-s.cancel:
		LogDebug("received cancel signal")
		LogInfo("killing process(%v) %v", execCmd.Process, cmd.Args)
		if err := execCmd.Process.Kill(); err != nil {
			s.ConsoleLog("kill command %v failed, error: %v\n", cmd.Args, err)
		} else {
			LogInfo("Process %v is killed", execCmd.Process)
		}
		return Err("%v is canceled", cmd.Args)
	case err := <-done:
		return err
	}
}

func (s *BuildSession) processTestCommand(cmd *protocal.BuildCommand) (bytes.Buffer, error) {
	var output bytes.Buffer
	session := MakeBuildSession(s.buildId, cmd, &output, s.artifacts, s.send)
	session.cancel = s.cancel
	err := session.ProcessCommand()
	return output, err
}

func (s *BuildSession) processTest(cmd *protocal.BuildCommand) error {
	flag := cmd.Args["flag"]

	switch flag {
	case "-d":
		targetPath := cmd.Args["left"]
		info, err := os.Stat(targetPath)
		if err != nil {
			return err
		}
		if info.IsDir() {
			return nil
		} else {
			return Err("%v is not a directory", targetPath)
		}
	case "-f":
		targetPath := cmd.Args["left"]
		info, err := os.Stat(targetPath)
		if err != nil {
			return err
		}
		if info.IsDir() {
			return Err("%v is not a file", targetPath)
		} else {
			return nil
		}
	case "-eq":
		output, err := s.processTestCommand(cmd.SubCommands[0])
		if err != nil {
			LogDebug("test -eq exec command error: %v", err)
		}
		expected := strings.TrimSpace(cmd.Args["left"])
		actual := strings.TrimSpace(output.String())
		if expected != actual {
			return Err("expected '%v', but was '%v'", expected, actual)
		}
		return nil
	}

	return Err("unknown test flag")
}

func (s *BuildSession) Report(jobState string) *protocal.Report {
	return &protocal.Report{
		AgentRuntimeInfo: GetAgentRuntimeInfo(),
		BuildId:          s.buildId,
		JobState:         jobState,
		Result:           s.buildStatus,
	}
}

func (s *BuildSession) ConsoleLog(format string, a ...interface{}) {
	s.console.Write([]byte(Sprintf(format, a...)))
}

func (s *BuildSession) warn(format string, a ...interface{}) {
	s.ConsoleLog(Sprintf("WARN: %v\n", format), a...)
}

func (s *BuildSession) ReplaceEcho(name string, value interface{}) {
	s.echo.Substitutions[name] = value
}

func (s *BuildSession) processEcho(cmd *protocal.BuildCommand) {
	for _, line := range cmd.ExtractArgList(len(cmd.Args)) {
		s.echo.Write([]byte(line))
		s.echo.Write([]byte{'\n'})
	}
}

func (s *BuildSession) processExport(cmd *protocal.BuildCommand) {
	msg := "setting environment variable '%v' to value '%v'\n"
	name := cmd.Args["name"]
	value, ok := cmd.Args["value"]
	if !ok {
		s.ConsoleLog(msg, name, os.Getenv(name))
		return
	}
	secure := cmd.Args["secure"]
	displayValue := value
	if secure == "true" {
		displayValue = DefaultSecretMask
	}
	_, override := s.envs[name]
	if override || os.Getenv(name) != "" {
		msg = "overriding environment variable '%v' with value '%v'\n"
	}
	s.envs[name] = value
	s.ConsoleLog(msg, name, displayValue)
}

func (s *BuildSession) processCompose(cmd *protocal.BuildCommand) error {
	var err error
	for _, sub := range cmd.SubCommands {
		if err != nil {
			s.process(sub)
		} else {
			err = s.process(sub)
		}
	}
	return err
}

func destDescription(path string) string {
	if path == "" {
		return "[defaultRoot]"
	} else {
		return path
	}
}
<|endoftext|>


<commit_before>package disk

import (
	"bytes"
	"errors"
	"io"
	"os"
	"strings"
	"testing"
)

const (
	tmpTestFile = "/tmp/cfs_disk_block_test"
)

var testFilePattern = []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g'}

func setUpTestFile(length int64, t *testing.T) *os.File {
	f, err := os.OpenFile(tmpTestFile, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0600)
	if err != nil {
		t.Fatalf("open tmp test file got error: %v", err)
		return nil
	}

	for length > 0 {
		if length < int64(len(testFilePattern)) {
			_, err = f.Write(testFilePattern[:length])
		} else {
			_, err = f.Write(testFilePattern)
		}
		if err != nil {
			t.Fatalf("write tmp test file got error: %v", err)
		}
		length = length - int64(len(testFilePattern))
	}
	return f
}

func TestPartlyReadBlock(t *testing.T) {
	f := setUpTestFile(90, t)
	p := make([]byte, 6)
	// write
	err := writeBlock(f, 8, 10, p)
	if err != nil {
		t.Errorf("error = %v", err)
	}
	rp := make([]byte, 16)
	n, err := readBlock(f, rp, 4, 20)
	if err != io.EOF {
		t.Errorf("expect error %v got %v", io.EOF, err)
	}
	if n != 6 {
		t.Errorf("expect get data length = %v got %v", 6, n)
	}
}

func TestBasicReadWriteBlock(t *testing.T) {
	tests := []struct {
		fileSize int64
		bs       int64
		index    int64
		writeLen int64
	}{
		// basic
		{20, 20, 0, 16},
		// none-zero index
		{100, 20, 2, 16},
		// write partly block
		{90, 20, 4, 16},
		// empty data
		{100, 20, 0, 0},
		// empty data with just fit block size
		{100, 4, 0, 0},
	}
	errtests := []struct {
		fileSize int64
		bs       int64
		index    int64
		writeLen int64
		err      error
	}{
		// bs < len(data + crc)
		{20, 20, 0, 40, ErrPayloadSizeTooLarge},
		// too small block size
		{20, 1, 0, 0, ErrPayloadSizeTooLarge},
		// negative index
		{20, 20, -1, 16, errors.New("invalid argument")},
	}

	for i, tt := range tests {
		f := setUpTestFile(tt.fileSize, t)
		p := make([]byte, tt.writeLen)
		for i := int64(0); i < tt.writeLen; i++ {
			p[i] = 'X'
		}

		// write
		err := writeBlock(f, tt.index, tt.bs, p)
		if err != nil {
			t.Errorf("%d: error = %v", i, err)
		}

		rp := make([]byte, tt.writeLen)
		// read
		n, err := readBlock(f, rp, tt.index, tt.bs)
		if err != nil {
			t.Errorf("%d: error = %v", i, err)
		}
		if n != tt.writeLen {
			t.Errorf("%d: expect read length %v got %v", i, tt.writeLen, n)
		}
		if !bytes.Equal(p, rp) {
			t.Errorf("%d: expect block data %v got %v", i, p, rp)
		}

		// TODO check crc
		// TODO check other bytes in file are not collapsed

		if err = f.Close(); nil != err {
			t.Fatal("can not close test file: ", err)
		}
	}

	for i, tt := range errtests {
		f := setUpTestFile(tt.fileSize, t)
		p := make([]byte, tt.writeLen)
		for i := int64(0); i < tt.writeLen; i++ {
			p[i] = 'X'
		}
		err := writeBlock(f, tt.index, tt.bs, p)
		if !strings.Contains(err.Error(), tt.err.Error()) {
			t.Errorf("error test %d: expect error %v got %v",
				i, tt.err, err)
		}

		_, err = readBlock(f, p, tt.index, tt.bs)
		if !strings.Contains(err.Error(), tt.err.Error()) {
			t.Errorf("error test %d: expect error %v got %v",
				i, tt.err, err)
		}

		if err = f.Close(); nil != err {
			t.Fatal("can not close test file: ", err)
		}
	}
}
<commit_msg>improve based on comments<commit_after>package disk

import (
	"bytes"
	"errors"
	"io"
	"os"
	"path"
	"strings"
	"testing"
)

const (
	tmpTestFile = "cfs_disk_block_test"
)

// testFilePattern is used to fill the test file, having a repeat pattern helps
// on testing writeBlock. We can check the data before/after the block we
// wrote in is not collapsed
var testFilePattern = []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g'}

func setUpTestFile(length int64, t *testing.T) *os.File {
	f, err := os.OpenFile(
		path.Join(os.TempDir(), tmpTestFile),
		os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0600)
	if err != nil {
		t.Fatalf("open tmp test file got error: %v", err)
		return nil
	}

	for length > 0 {
		if length < int64(len(testFilePattern)) {
			_, err = f.Write(testFilePattern[:length])
		} else {
			_, err = f.Write(testFilePattern)
		}
		if err != nil {
			t.Fatalf("write tmp test file got error: %v", err)
		}
		length = length - int64(len(testFilePattern))
	}
	return f
}

func TestPartlyReadBlock(t *testing.T) {
	defer os.Remove(tmpTestFile)
	// 90 bytes file, block size = 20 bytes
	f := setUpTestFile(90, t)

	// writeBlock to set a correct CRC
	p := make([]byte, 6)
	err := writeBlock(f, 4, 20, p)
	if err != nil {
		t.Errorf("error = %v", err)
	}
	// try to read out a block
	rp := make([]byte, 16)
	n, err := readBlock(f, rp, 4, 20)
	if n != 6 {
		t.Errorf("expect get data length = %v got %v", 6, n)
	}
	if err != io.EOF {
		t.Errorf("expect error %v got %v", io.EOF, err)
	}
}

func TestReadWriteBlock(t *testing.T) {
	tests := []struct {
		fileSize int64
		bs       int64
		index    int64
		writeLen int64
	}{
		// basic
		{20, 20, 0, 16},
		// none-zero index
		{100, 20, 2, 16},
		// write partly block
		{90, 20, 4, 16},
		// empty data
		{100, 20, 0, 0},
		// empty data with just fit block size
		{100, 4, 0, 0},
	}
	errtests := []struct {
		fileSize int64
		bs       int64
		index    int64
		writeLen int64
		err      error
	}{
		// bs < len(data + crc)
		{20, 20, 0, 40, ErrPayloadSizeTooLarge},
		// too small block size
		{20, 1, 0, 0, ErrPayloadSizeTooLarge},
		// negative index
		{20, 20, -1, 16, errors.New("invalid argument")},
	}

	defer os.Remove(tmpTestFile)
	for i, tt := range tests {
		f := setUpTestFile(tt.fileSize, t)
		p := make([]byte, tt.writeLen)
		for i := int64(0); i < tt.writeLen; i++ {
			p[i] = 'X'
		}

		// write
		err := writeBlock(f, tt.index, tt.bs, p)
		if err != nil {
			t.Errorf("%d: error = %v", i, err)
		}

		rp := make([]byte, tt.writeLen)
		// read
		n, err := readBlock(f, rp, tt.index, tt.bs)
		if err != nil {
			t.Errorf("%d: error = %v", i, err)
		}
		if n != tt.writeLen {
			t.Errorf("%d: expect read length %v got %v", i, tt.writeLen, n)
		}
		if !bytes.Equal(p, rp) {
			t.Errorf("%d: expect block data %v got %v", i, p, rp)
		}

		// TODO check crc
		// TODO check other bytes in file are not collapsed

		if err = f.Close(); nil != err {
			t.Fatal("can not close test file: ", err)
		}
	}

	for i, tt := range errtests {
		f := setUpTestFile(tt.fileSize, t)
		p := make([]byte, tt.writeLen)
		for i := int64(0); i < tt.writeLen; i++ {
			p[i] = 'X'
		}
		err := writeBlock(f, tt.index, tt.bs, p)
		if !strings.Contains(err.Error(), tt.err.Error()) {
			t.Errorf("error test %d: expect error %v got %v",
				i, tt.err, err)
		}

		_, err = readBlock(f, p, tt.index, tt.bs)
		if !strings.Contains(err.Error(), tt.err.Error()) {
			t.Errorf("error test %d: expect error %v got %v",
				i, tt.err, err)
		}

		if err = f.Close(); nil != err {
			t.Fatal("can not close test file: ", err)
		}
	}
}
<|endoftext|>


<commit_before><commit_msg>more testing<commit_after><|endoftext|>


<commit_before>package rdbtools

import (
	"os"
	"testing"
)

// This file contains tests for all the dumps in the dumps/ directory
// Those dumps are taken from https://github.com/sripathikrishnan/redis-rdb-tools

func mustOpen(t *testing.T, path string) *os.File {
	f, err := os.Open(path)
	if err != nil {
		t.Fatalf("Error while opening file '%s'; err=%s", path, err)
	}

	return f
}

func doParse(t *testing.T, p *Parser, path string) {
	err := p.Parse(mustOpen(t, path))
	if err != nil {
		t.Fatalf("Error while parsing '%s'; err=%s", path, err)
	}
}

func TestDumpDictionary(t *testing.T) {
	p := NewParser(ParserContext{
		HashMetadataCh: make(chan HashMetadata),
		HashDataCh:     make(chan HashEntry),
	})

	go doParse(t, p, "dumps/dictionary.rdb")

	var i, j int
	stop := false
	for !stop {
		select {
		case _, ok := <-p.ctx.HashMetadataCh:
			if !ok {
				p.ctx.HashMetadataCh = nil
				break
			}
			i++
		case _, ok := <-p.ctx.HashDataCh:
			if !ok {
				p.ctx.HashDataCh = nil
				break
			}
			j++
		}

		if p.ctx.Invalid() {
			break
		}
	}

	equals(t, 1, i)
	equals(t, 1000, j)
}

func TestDumpKeysWithExpiry(t *testing.T) {
	p := NewParser(ParserContext{
		StringObjectCh: make(chan StringObject),
	})

	go doParse(t, p, "dumps/keys_with_expiry.rdb")

	stop := false
	for !stop {
		select {
		case v, ok := <-p.ctx.StringObjectCh:
			if !ok {
				p.ctx.StringObjectCh = nil
				break
			}
			equals(t, "expires_ms_precision", DataToString(v.Key.Key))
			equals(t, "2022-12-25 10:11:12 +0000 UTC", v.Key.ExpiryTime.UTC().String())
			equals(t, "2022-12-25 10:11:12.573 UTC", DataToString(v.Value))
		}

		if p.ctx.Invalid() {
			break
		}
	}
}
<commit_msg>Close the channels if there is an error so that there's no deadlock<commit_after>package rdbtools

import (
	"os"
	"testing"
)

// This file contains tests for all the dumps in the dumps/ directory
// Those dumps are taken from https://github.com/sripathikrishnan/redis-rdb-tools

func mustOpen(t *testing.T, path string) *os.File {
	f, err := os.Open(path)
	if err != nil {
		t.Fatalf("Error while opening file '%s'; err=%s", path, err)
	}

	return f
}

func doParse(t *testing.T, p *Parser, path string) {
	err := p.Parse(mustOpen(t, path))
	if err != nil {
		p.ctx.closeChannels()
		t.Fatalf("Error while parsing '%s'; err=%s", path, err)
	}
}

func TestDumpDictionary(t *testing.T) {
	p := NewParser(ParserContext{
		HashMetadataCh: make(chan HashMetadata),
		HashDataCh:     make(chan HashEntry),
	})

	go doParse(t, p, "dumps/dictionary.rdb")

	var i, j int
	stop := false
	for !stop {
		select {
		case _, ok := <-p.ctx.HashMetadataCh:
			if !ok {
				p.ctx.HashMetadataCh = nil
				break
			}
			i++
		case _, ok := <-p.ctx.HashDataCh:
			if !ok {
				p.ctx.HashDataCh = nil
				break
			}
			j++
		}

		if p.ctx.Invalid() {
			break
		}
	}

	equals(t, 1, i)
	equals(t, 1000, j)
}

func TestDumpKeysWithExpiry(t *testing.T) {
	p := NewParser(ParserContext{
		StringObjectCh: make(chan StringObject),
	})

	go doParse(t, p, "dumps/keys_with_expiry.rdb")

	stop := false
	for !stop {
		select {
		case v, ok := <-p.ctx.StringObjectCh:
			if !ok {
				p.ctx.StringObjectCh = nil
				break
			}
			equals(t, "expires_ms_precision", DataToString(v.Key.Key))
			equals(t, "2022-12-25 10:11:12 +0000 UTC", v.Key.ExpiryTime.UTC().String())
			equals(t, "2022-12-25 10:11:12.573 UTC", DataToString(v.Value))
		}

		if p.ctx.Invalid() {
			break
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"cf"
	"cf/api"
	"cf/app"
	"cf/commands"
	"cf/configuration"
	"cf/manifest"
	"cf/net"
	"cf/requirements"
	"cf/terminal"
	"fileutils"
	"fmt"
	"github.com/codegangsta/cli"
	"os"
	"runtime/debug"
	"strings"
)

func main() {
	defer func() {
		err := recover()
		if err != nil {
			displayCrashDialog()
		}
	}()

	fileutils.SetTmpPathPrefix("cf")

	if os.Getenv("CF_COLOR") == "" {
		os.Setenv("CF_COLOR", "true")
	}

	termUI := terminal.NewUI()
	configRepo := configuration.NewConfigurationDiskRepository()
	config := loadConfig(termUI, configRepo)
	manifestRepo := manifest.NewManifestDiskRepository()
	repoLocator := api.NewRepositoryLocator(config, configRepo, map[string]net.Gateway{
		"auth":             net.NewUAAGateway(),
		"cloud-controller": net.NewCloudControllerGateway(),
		"uaa":              net.NewUAAGateway(),
	})

	cmdFactory := commands.NewFactory(termUI, config, configRepo, manifestRepo, repoLocator)
	reqFactory := requirements.NewFactory(termUI, config, repoLocator)
	cmdRunner := commands.NewRunner(cmdFactory, reqFactory)

	app, err := app.NewApp(cmdRunner)
	if err != nil {
		return
	}

	args := os.Args
	if len(args) == 2 && args[1][0] == '-' {
		args[1] = "help"
	}

	app.Run(args)
}

func init() {
	cli.AppHelpTemplate = `NAME:
   {{.Name}} - {{.Usage}}

USAGE:
   [environment variables] {{.Name}} [global options] command [arguments...] [command options]

VERSION:
   {{.Version}}

COMMANDS:
   {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Description}}
   {{end}}
GLOBAL OPTIONS:
   {{range .Flags}}{{.}}
   {{end}}
ENVIRONMENT VARIABLES:
   CF_HOME=path/to/config/ override default config directory
   CF_STAGING_TIMEOUT=15 max wait time for buildpack staging, in minutes
   CF_STARTUP_TIMEOUT=5 max wait time for app instance startup, in minutes
   CF_COLOR=false - will not colorize output
   CF_TRACE=true - print API request diagnostics to stdout
   CF_TRACE=path/to/trace.log - append API request diagnostics to a log file
   HTTP_PROXY=http://proxy.example.com:8080 - enable http proxying for API requests
`

	cli.CommandHelpTemplate = `NAME:
   {{.Name}} - {{.Description}}
{{with .ShortName}}
ALIAS:
   {{.}}
{{end}}
USAGE:
   {{.Usage}}{{with .Flags}}

OPTIONS:
   {{range .}}{{.}}
   {{end}}{{else}}
{{end}}`

}

func loadConfig(termUI terminal.UI, configRepo configuration.ConfigurationRepository) (config *configuration.Configuration) {
	config, err := configRepo.Get()
	if err != nil {
		termUI.Failed(fmt.Sprintf("Error loading config file: %s",err))
		configRepo.Delete()
		os.Exit(1)
		return
	}
	return
}

func displayCrashDialog() {
	formattedString := `

Aww shucks.

Something completely unexpected happened. This is a bug in %s.
Please file this bug : https://github.com/cloudfoundry/cli/issues
Tell us that you ran this command:

	%s

and got this stack trace:

%s
	`

	stackTrace := "\t" + strings.Replace(string(debug.Stack()), "\n", "\n\t", -1)
	println(fmt.Sprintf(formattedString, cf.Name(), strings.Join(os.Args, " "), stackTrace))
	os.Exit(1)
}
<commit_msg>Fix `cf -h` hack to permit `cf -v`<commit_after>package main

import (
	"cf"
	"cf/api"
	"cf/app"
	"cf/commands"
	"cf/configuration"
	"cf/manifest"
	"cf/net"
	"cf/requirements"
	"cf/terminal"
	"fileutils"
	"fmt"
	"github.com/codegangsta/cli"
	"os"
	"runtime/debug"
	"strings"
)

func main() {
	defer func() {
		err := recover()
		if err != nil {
			displayCrashDialog()
		}
	}()

	fileutils.SetTmpPathPrefix("cf")

	if os.Getenv("CF_COLOR") == "" {
		os.Setenv("CF_COLOR", "true")
	}

	termUI := terminal.NewUI()
	configRepo := configuration.NewConfigurationDiskRepository()
	config := loadConfig(termUI, configRepo)
	manifestRepo := manifest.NewManifestDiskRepository()
	repoLocator := api.NewRepositoryLocator(config, configRepo, map[string]net.Gateway{
		"auth":             net.NewUAAGateway(),
		"cloud-controller": net.NewCloudControllerGateway(),
		"uaa":              net.NewUAAGateway(),
	})

	cmdFactory := commands.NewFactory(termUI, config, configRepo, manifestRepo, repoLocator)
	reqFactory := requirements.NewFactory(termUI, config, repoLocator)
	cmdRunner := commands.NewRunner(cmdFactory, reqFactory)

	app, err := app.NewApp(cmdRunner)
	if err != nil {
		return
	}

	args := os.Args
	if len(args) == 2 && args[1][0] == '-' && args[1] != "-v" && args[1] != "--version" {
		args[1] = "help"
	}

	app.Run(args)
}

func init() {
	cli.AppHelpTemplate = `NAME:
   {{.Name}} - {{.Usage}}

USAGE:
   [environment variables] {{.Name}} [global options] command [arguments...] [command options]

VERSION:
   {{.Version}}

COMMANDS:
   {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Description}}
   {{end}}
GLOBAL OPTIONS:
   {{range .Flags}}{{.}}
   {{end}}
ENVIRONMENT VARIABLES:
   CF_HOME=path/to/config/ override default config directory
   CF_STAGING_TIMEOUT=15 max wait time for buildpack staging, in minutes
   CF_STARTUP_TIMEOUT=5 max wait time for app instance startup, in minutes
   CF_COLOR=false - will not colorize output
   CF_TRACE=true - print API request diagnostics to stdout
   CF_TRACE=path/to/trace.log - append API request diagnostics to a log file
   HTTP_PROXY=http://proxy.example.com:8080 - enable http proxying for API requests
`

	cli.CommandHelpTemplate = `NAME:
   {{.Name}} - {{.Description}}
{{with .ShortName}}
ALIAS:
   {{.}}
{{end}}
USAGE:
   {{.Usage}}{{with .Flags}}

OPTIONS:
   {{range .}}{{.}}
   {{end}}{{else}}
{{end}}`

}

func loadConfig(termUI terminal.UI, configRepo configuration.ConfigurationRepository) (config *configuration.Configuration) {
	config, err := configRepo.Get()
	if err != nil {
		termUI.Failed(fmt.Sprintf("Error loading config file: %s",err))
		configRepo.Delete()
		os.Exit(1)
		return
	}
	return
}

func displayCrashDialog() {
	formattedString := `

Aww shucks.

Something completely unexpected happened. This is a bug in %s.
Please file this bug : https://github.com/cloudfoundry/cli/issues
Tell us that you ran this command:

	%s

and got this stack trace:

%s
	`

	stackTrace := "\t" + strings.Replace(string(debug.Stack()), "\n", "\n\t", -1)
	println(fmt.Sprintf(formattedString, cf.Name(), strings.Join(os.Args, " "), stackTrace))
	os.Exit(1)
}
<|endoftext|>


<commit_before>// Package udp implements UDP test helpers. It lets you assert that certain
// strings must or must not be sent to a given local UDP listener.
package udp

import (
	"net"
	"runtime"
	"strings"
	"testing"
	"time"
)

var (
	addr     *string
	listener *net.UDPConn
	Timeout  time.Duration = time.Millisecond
)

type fn func()

// SetAddr sets the UDP port that will be listened on.
func SetAddr(a string) {
	addr = &a
}

func start(t *testing.T) {
	resAddr, err := net.ResolveUDPAddr("udp", *addr)
	if err != nil {
		t.Fatal(err)
	}
	listener, err = net.ListenUDP("udp", resAddr)
	if err != nil {
		t.Fatal(err)
	}
}

func stop(t *testing.T) {
	if err := listener.Close(); err != nil {
		t.Fatal(err)
	}
}

func getMessage(t *testing.T, body fn) string {
	start(t)
	defer stop(t)

	body()

	message := make([]byte, 1024*32)
	var bufLen int
	for {
		listener.SetReadDeadline(time.Now().Add(Timeout))
		n, _, _ := listener.ReadFrom(message[bufLen:])
		if n == 0 {
			break
		} else {
			bufLen += n
		}
	}

	return string(message[0:bufLen])
}

func get(t *testing.T, match string, body fn) (got string, equals bool, contains bool) {
	got = getMessage(t, body)
	equals = got == match
	contains = strings.Contains(got, match)
	return got, equals, contains
}

func printLocation(t *testing.T) {
	_, file, line, _ := runtime.Caller(2)
	t.Errorf("At: %s:%d", file, line)
}

func Write(b []byte) (n int, err error) {
	return listener.Write(b)
}

// ShouldReceiveOnly will fire a test error if the given function doesn't send
// exactly the given string over UDP.
func ShouldReceiveOnly(t *testing.T, expected string, body fn) {
	got, equals, _ := get(t, expected, body)
	if !equals {
		printLocation(t)
		t.Errorf("Expected: %#v", expected)
		t.Errorf("But got: %#v", got)
	}
}

// ShouldNotReceiveOnly will fire a test error if the given function sends
// exactly the given string over UDP.
func ShouldNotReceiveOnly(t *testing.T, notExpected string, body fn) {
	_, equals, _ := get(t, notExpected, body)
	if equals {
		printLocation(t)
		t.Errorf("Expected not to get: %#v", notExpected)
	}
}

// ShouldReceive will fire a test error if the given function doesn't send the
// given string over UDP.
func ShouldReceive(t *testing.T, expected string, body fn) {
	got, _, contains := get(t, expected, body)
	if !contains {
		printLocation(t)
		t.Errorf("Expected to find: %#v", expected)
		t.Errorf("But got: %#v", got)
	}
}

// ShouldNotReceive will fire a test error if the given function sends the
// given string over UDP.
func ShouldNotReceive(t *testing.T, expected string, body fn) {
	got, _, contains := get(t, expected, body)
	if contains {
		printLocation(t)
		t.Errorf("Expected not to find: %#v", expected)
		t.Errorf("But got: %#v", got)
	}
}

// ShouldReceiveAll will fire a test error unless all of the given strings are
// sent over UDP.
func ShouldReceiveAll(t *testing.T, expected []string, body fn) {
	got := getMessage(t, body)
	failed := false

	for _, str := range expected {
		if !strings.Contains(got, str) {
			if !failed {
				printLocation(t)
				failed = true
			}
			t.Errorf("Expected to find: %#v", str)
		}
	}

	if failed {
		t.Errorf("But got: %#v", got)
	}
}

// ShouldNotReceiveAny will fire a test error if any of the given strings are
// sent over UDP.
func ShouldNotReceiveAny(t *testing.T, unexpected []string, body fn) {
	got := getMessage(t, body)
	failed := false

	for _, str := range unexpected {
		if strings.Contains(got, str) {
			if !failed {
				printLocation(t)
				failed = true
			}
			t.Errorf("Expected not to find: %#v", str)
		}
	}

	if failed {
		t.Errorf("But got: %#v", got)
	}
}

func ShouldReceiveAllAndNotReceiveAny(t *testing.T, expected []string, unexpected []string, body fn) {
	got := getMessage(t, body)
	failed := false

	for _, str := range expected {
		if !strings.Contains(got, str) {
			if !failed {
				printLocation(t)
				failed = true
			}
			t.Errorf("Expected to find: %#v", str)
		}
	}
	for _, str := range unexpected {
		if strings.Contains(got, str) {
			if !failed {
				printLocation(t)
				failed = true
			}
			t.Errorf("Expected not to find: %#v", str)
		}
	}

	if failed {
		t.Errorf("but got: %#v", got)
	}
}

func ReceiveString(t *testing.T, body fn) string {
	return getMessage(t, body)
}
<commit_msg>update expose<commit_after>// Package udp implements UDP test helpers. It lets you assert that certain
// strings must or must not be sent to a given local UDP listener.
package udp

import (
	"net"
	"runtime"
	"strings"
	"testing"
	"time"
)

var (
	addr     *string
	listener *net.UDPConn
	Timeout  time.Duration = time.Millisecond
)

type fn func()

// SetAddr sets the UDP port that will be listened on.
func SetAddr(a string) {
	addr = &a
}

func LocalAddr() net.Addr {
	return listener.LocalAddr()
}

func RemoteAddr() net.Addr {
	return listener.RemoteAddr()
}

func Write(b []byte) (n int, err error) {
	return listener.Write(b)
}

func WriteTo(b []byte, addr net.Addr) (n int, err error) {
	return listener.WriteTo(b, addr)
}

func start(t *testing.T) {
	resAddr, err := net.ResolveUDPAddr("udp", *addr)
	if err != nil {
		t.Fatal(err)
	}
	listener, err = net.ListenUDP("udp", resAddr)
	if err != nil {
		t.Fatal(err)
	}
}

func stop(t *testing.T) {
	if err := listener.Close(); err != nil {
		t.Fatal(err)
	}
}

func getMessage(t *testing.T, body fn) string {
	start(t)
	defer stop(t)

	body()

	message := make([]byte, 1024*32)
	var bufLen int
	for {
		listener.SetReadDeadline(time.Now().Add(Timeout))
		n, _, _ := listener.ReadFrom(message[bufLen:])
		if n == 0 {
			break
		} else {
			bufLen += n
		}
	}

	return string(message[0:bufLen])
}

func get(t *testing.T, match string, body fn) (got string, equals bool, contains bool) {
	got = getMessage(t, body)
	equals = got == match
	contains = strings.Contains(got, match)
	return got, equals, contains
}

func printLocation(t *testing.T) {
	_, file, line, _ := runtime.Caller(2)
	t.Errorf("At: %s:%d", file, line)
}

// ShouldReceiveOnly will fire a test error if the given function doesn't send
// exactly the given string over UDP.
func ShouldReceiveOnly(t *testing.T, expected string, body fn) {
	got, equals, _ := get(t, expected, body)
	if !equals {
		printLocation(t)
		t.Errorf("Expected: %#v", expected)
		t.Errorf("But got: %#v", got)
	}
}

// ShouldNotReceiveOnly will fire a test error if the given function sends
// exactly the given string over UDP.
func ShouldNotReceiveOnly(t *testing.T, notExpected string, body fn) {
	_, equals, _ := get(t, notExpected, body)
	if equals {
		printLocation(t)
		t.Errorf("Expected not to get: %#v", notExpected)
	}
}

// ShouldReceive will fire a test error if the given function doesn't send the
// given string over UDP.
func ShouldReceive(t *testing.T, expected string, body fn) {
	got, _, contains := get(t, expected, body)
	if !contains {
		printLocation(t)
		t.Errorf("Expected to find: %#v", expected)
		t.Errorf("But got: %#v", got)
	}
}

// ShouldNotReceive will fire a test error if the given function sends the
// given string over UDP.
func ShouldNotReceive(t *testing.T, expected string, body fn) {
	got, _, contains := get(t, expected, body)
	if contains {
		printLocation(t)
		t.Errorf("Expected not to find: %#v", expected)
		t.Errorf("But got: %#v", got)
	}
}

// ShouldReceiveAll will fire a test error unless all of the given strings are
// sent over UDP.
func ShouldReceiveAll(t *testing.T, expected []string, body fn) {
	got := getMessage(t, body)
	failed := false

	for _, str := range expected {
		if !strings.Contains(got, str) {
			if !failed {
				printLocation(t)
				failed = true
			}
			t.Errorf("Expected to find: %#v", str)
		}
	}

	if failed {
		t.Errorf("But got: %#v", got)
	}
}

// ShouldNotReceiveAny will fire a test error if any of the given strings are
// sent over UDP.
func ShouldNotReceiveAny(t *testing.T, unexpected []string, body fn) {
	got := getMessage(t, body)
	failed := false

	for _, str := range unexpected {
		if strings.Contains(got, str) {
			if !failed {
				printLocation(t)
				failed = true
			}
			t.Errorf("Expected not to find: %#v", str)
		}
	}

	if failed {
		t.Errorf("But got: %#v", got)
	}
}

func ShouldReceiveAllAndNotReceiveAny(t *testing.T, expected []string, unexpected []string, body fn) {
	got := getMessage(t, body)
	failed := false

	for _, str := range expected {
		if !strings.Contains(got, str) {
			if !failed {
				printLocation(t)
				failed = true
			}
			t.Errorf("Expected to find: %#v", str)
		}
	}
	for _, str := range unexpected {
		if strings.Contains(got, str) {
			if !failed {
				printLocation(t)
				failed = true
			}
			t.Errorf("Expected not to find: %#v", str)
		}
	}

	if failed {
		t.Errorf("but got: %#v", got)
	}
}

func ReceiveString(t *testing.T, body fn) string {
	return getMessage(t, body)
}
<|endoftext|>


<commit_before>package debug

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
)

var debug bool

// Enable enables debug logging. After this call, all Algolia HTTP requests and
// responses will be displayed. A minor overhead is expected when debug logging
// is enabled.
func Enable() {
	debug = true
}

// Disable disables debug logging. After this call, Algolia requests and
// responses will not be logged anymore. The minor overhead introduced when
// debug logging is enabled should not happen anymore.
func Disable() {
	debug = false
}

// Display displays the given parameter on the standard output in a custom way,
// depending on the given input type. This function is internally used by the
// Algolia API client to display, for instance, HTTP requests and responses when
// debug logging is enabled.
func Display(itf interface{}) {
	if !debug {
		return
	}
	switch v := itf.(type) {
	case *http.Request:
		printRequest(v)
	case *http.Response:
		printResponse(v)
	default:
		fmt.Printf("do not know how to debug-print %#v\n", v)
	}
}

func Println(a ...interface{}) {
	Printf(fmt.Sprintln(a...))
}

func Printf(format string, a ...interface{}) {
	if !debug {
		return
	}
	msg := fmt.Sprintf(format, a...)
	fmt.Printf("> ALGOLIA DEBUG: %s", msg)
}

func copyReadCloser(r io.ReadCloser) (io.ReadCloser, string) {
	if r == nil {
		return nil, ""
	}
	data, err := ioutil.ReadAll(r)
	_ = r.Close()
	if err != nil {
		return nil, ""
	}
	return ioutil.NopCloser(bytes.NewReader(data)), string(data)
}

func prettyPrintJSON(input, prefix, indent string) string {
	var b bytes.Buffer
	err := json.Indent(&b, []byte(input), prefix, indent)
	if err != nil {
		return input
	}
	return b.String()
}

func printRequest(req *http.Request) {
	var body string
	req.Body, body = copyReadCloser(req.Body)
	body = prettyPrintJSON(body, "\t", "  ")
	fmt.Printf("> ALGOLIA DEBUG request:\n\tmethod=%q\n\turl=%q\n\tbody=\"%s\"\n", req.Method, req.URL, body)
}

func printResponse(res *http.Response) {
	var body string
	res.Body, body = copyReadCloser(res.Body)
	body = prettyPrintJSON(body, "\t", "  ")
	fmt.Printf("> ALGOLIA DEBUG response:\n\tbody=\"%s\"\n", body)
}
<commit_msg>changed: improve debug outputs<commit_after>package debug

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
)

var debug bool

// Enable enables debug logging. After this call, all Algolia HTTP requests and
// responses will be displayed. A minor overhead is expected when debug logging
// is enabled.
func Enable() {
	debug = true
}

// Disable disables debug logging. After this call, Algolia requests and
// responses will not be logged anymore. The minor overhead introduced when
// debug logging is enabled should not happen anymore.
func Disable() {
	debug = false
}

// Display displays the given parameter on the standard output in a custom way,
// depending on the given input type. This function is internally used by the
// Algolia API client to display, for instance, HTTP requests and responses when
// debug logging is enabled.
func Display(itf interface{}) {
	if !debug {
		return
	}
	switch v := itf.(type) {
	case *http.Request:
		printRequest(v)
	case *http.Response:
		printResponse(v)
	default:
		fmt.Printf("do not know how to debug-print %#v\n", v)
	}
}

func Println(a ...interface{}) {
	Printf("%s", fmt.Sprintln(a...))
}

func Printf(format string, a ...interface{}) {
	if !debug {
		return
	}
	msg := fmt.Sprintf(format, a...)
	fmt.Printf("> ALGOLIA DEBUG: %s", msg)
}

func copyReadCloser(r io.ReadCloser) (io.ReadCloser, string) {
	if r == nil {
		return nil, ""
	}
	data, err := ioutil.ReadAll(r)
	_ = r.Close()
	if err != nil {
		return nil, ""
	}
	return ioutil.NopCloser(bytes.NewReader(data)), string(data)
}

func prettyPrintJSON(input, prefix string) string {
	var b bytes.Buffer
	err := json.Indent(&b, []byte(input), prefix, "  ")
	if err != nil {
		return input
	}
	return strings.TrimSuffix(b.String(), "\n")
}

func printRequest(req *http.Request) {
	var body string
	req.Body, body = copyReadCloser(req.Body)
	body = prettyPrintJSON(body, "\t")
	fmt.Printf("> ALGOLIA DEBUG request:\n\tmethod=%q\n\turl=%q\n\tbody=\n\t%s\n", req.Method, req.URL, body)
}

func printResponse(res *http.Response) {
	var body string
	res.Body, body = copyReadCloser(res.Body)
	body = prettyPrintJSON(body, "\t")
	fmt.Printf("> ALGOLIA DEBUG response:\n\tbody=\n\t%s\n", body)
}
<|endoftext|>


<commit_before>package main

import "github.com/moxtsuan/murakumo/location"

var (
	BASE_URL = "http://www.river.go.jp/x/krd0107010.php?"
	//LON       = "lon=134.04178619384766"
	//LAT       = "lat=34.32217300445413"
	LOC       = location.Location{"134.04178919384766", "34.32217300445413", "12"}
	OPT       = "opa=0&zoom=12&leg=0&ext=0"
	SS        = "/tmp/amagumo_murakumo.png"
	TRIM      = "/tmp/trim_murakumo.png"
	SCORE     = 20000
	APP_RANGE = 3
)
<commit_msg>up score<commit_after>package main

import "github.com/moxtsuan/murakumo/location"

var (
	BASE_URL = "http://www.river.go.jp/x/krd0107010.php?"
	//LON       = "lon=134.04178619384766"
	//LAT       = "lat=34.32217300445413"
	LOC       = location.Location{"134.04178919384766", "34.32217300445413", "12"}
	OPT       = "opa=0&zoom=12&leg=0&ext=0"
	SS        = "/tmp/amagumo_murakumo.png"
	TRIM      = "/tmp/trim_murakumo.png"
	SCORE     = 30000
	APP_RANGE = 3
)
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/exec"
)

const VMRUN = "/Applications/VMware Fusion.app/Contents/Library/vmrun"

func main() {
	args := os.Args[1:]
	out, err := exec.Command(VMRUN, args...).Output()
	if err != nil {
		fmt.Printf("%s\n\n", err.Error())
	}
	fmt.Printf("%s", out)
}
<commit_msg>List VMs in User document dir<commit_after>package main

import (
	"fmt"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
)

const vmrun = "/Applications/VMware Fusion.app/Contents/Library/vmrun"

var (
	home = os.Getenv("HOME")
	vmdir = fmt.Sprintf("%s/%s", home, "Documents/Virtual Machines.localized")
)

func vmname(vmpath string) string {
	relpath := strings.TrimPrefix(vmpath, vmdir)
	vmwarevm := path.Base(path.Dir(relpath))
	return strings.TrimSuffix(vmwarevm, ".vmwarevm")
}

func list() (map[string]string) {
	glob := fmt.Sprintf("%s/**/*.vmx", vmdir)
	paths, err := filepath.Glob(glob)
	if err != nil {
		fmt.Printf("%s\n\n", err.Error())
	}

	vmx := make(map[string]string)
	for _, path := range paths {
		name := vmname(path)
		vmx[name] = path
	}

	return vmx
}

func main() {
	args := os.Args[1:]
	out, err := exec.Command(vmrun, args...).Output()
	if err != nil {
		fmt.Printf("%s\n\n", err.Error())
	}
	fmt.Printf("%s", out)

	if len(args) > 0 && args[0] == "list" {
		fmt.Printf("\nVMs in %s:\n", vmdir)
		for name, path := range list() {
			fmt.Printf("  %+20s (%s)\n", name, path)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2018 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package web

import (
	"errors"
	"net/http"
	"os"
	"os/signal"

	"github.com/issue9/web/context"
	"github.com/issue9/web/internal/server"
	"github.com/issue9/web/result"
)

var defaultApp *app

var signalChannel chan os.Signal

// Middleware 将一个 http.Handler 封装成另一个 http.Handler
type Middleware func(http.Handler) http.Handler

func grace(s ...os.Signal) {
	if signalChannel != nil {
		return
	}

	signalChannel = make(chan os.Signal)
	signal.Notify(signalChannel, s...)

	<-signalChannel
	Shutdown()
}

// Init 初始化整个应用环境
//
// configDir 表示配置文件的目录；
// m 表示应用于所有路由项的中间件；
// s 表示触发 shutdown 的信号。
// 传递给框架的信号，会触发调用 Shutdown() 操作。
func Init(configDir string, m Middleware, s ...os.Signal) error {
	if defaultApp != nil {
		return errors.New("不能重复调用 Init")
	}

	app, err := newApp(configDir, m)
	if err != nil {
		return err
	}

	defaultApp = app

	if len(s) > 0 {
		go grace(s...)
	}

	return nil
}

// IsDebug 是否处在调试模式
func IsDebug() bool {
	return defaultApp.config.Debug
}

// Run 运行路由，执行监听程序。
func Run() error {
	return defaultApp.Run()
}

// Close 立即关闭服务
func Close() error {
	return server.Close()
}

// Shutdown 关闭所有服务。
//
// 和 Close 的区别在于 Shutdown 会等待所有的服务完成之后才关闭，
// 等待时间由配置文件决定。
func Shutdown() error {
	return server.Shutdown()
}

// File 获取配置目录下的文件。
func File(path string) string {
	return defaultApp.File(path)
}

// URL 构建一条完整 URL
func URL(path string) string {
	return defaultApp.URL(path)
}

// AddModule 注册一个模块
func AddModule(m *Module) {
	defaultApp.AddModule(m)
}

// NewContext 根据当前配置，生成 context.Context 对象，若是出错则返回 nil
func NewContext(w http.ResponseWriter, r *http.Request) *context.Context {
	return defaultApp.NewContext(w, r)
}

// NewResult 生成一个 *result.Result 对象
func NewResult(code int) *result.Result {
	return result.New(code, nil)
}

// NewResultWithDetail 声明一个带详细内容的 result.Result 对象
func NewResultWithDetail(code int, fields map[string]string) *result.Result {
	return result.New(code, fields)
}
<commit_msg>精简 grace<commit_after>// Copyright 2018 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package web

import (
	"errors"
	"net/http"
	"os"
	"os/signal"

	"github.com/issue9/web/context"
	"github.com/issue9/web/internal/server"
	"github.com/issue9/web/result"
)

var defaultApp *app

// Middleware 将一个 http.Handler 封装成另一个 http.Handler
type Middleware func(http.Handler) http.Handler

func grace(s ...os.Signal) {
	signalChannel := make(chan os.Signal)
	signal.Notify(signalChannel, s...)

	<-signalChannel
	Shutdown()
}

// Init 初始化整个应用环境
//
// configDir 表示配置文件的目录；
// m 表示应用于所有路由项的中间件；
// s 表示触发 shutdown 的信号。
// 传递给框架的信号，会触发调用 Shutdown() 操作。
func Init(configDir string, m Middleware, s ...os.Signal) error {
	if defaultApp != nil {
		return errors.New("不能重复调用 Init")
	}

	app, err := newApp(configDir, m)
	if err != nil {
		return err
	}

	defaultApp = app

	if len(s) > 0 {
		go grace(s...)
	}

	return nil
}

// IsDebug 是否处在调试模式
func IsDebug() bool {
	return defaultApp.config.Debug
}

// Run 运行路由，执行监听程序。
func Run() error {
	return defaultApp.Run()
}

// Close 立即关闭服务
func Close() error {
	return server.Close()
}

// Shutdown 关闭所有服务。
//
// 和 Close 的区别在于 Shutdown 会等待所有的服务完成之后才关闭，
// 等待时间由配置文件决定。
func Shutdown() error {
	return server.Shutdown()
}

// File 获取配置目录下的文件。
func File(path string) string {
	return defaultApp.File(path)
}

// URL 构建一条完整 URL
func URL(path string) string {
	return defaultApp.URL(path)
}

// AddModule 注册一个模块
func AddModule(m *Module) {
	defaultApp.AddModule(m)
}

// NewContext 根据当前配置，生成 context.Context 对象，若是出错则返回 nil
func NewContext(w http.ResponseWriter, r *http.Request) *context.Context {
	return defaultApp.NewContext(w, r)
}

// NewResult 生成一个 *result.Result 对象
func NewResult(code int) *result.Result {
	return result.New(code, nil)
}

// NewResultWithDetail 声明一个带详细内容的 result.Result 对象
func NewResultWithDetail(code int, fields map[string]string) *result.Result {
	return result.New(code, fields)
}
<|endoftext|>