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

package ht

import (
	"fmt"
	htmltemplate "html/template"
	"io"
	"io/ioutil"
	"os"
	"path"
	"text/template"
)

// ----------------------------------------------------------------------------
// Status

// Status describes the status of a Test or a Check.
type Status int

const (
	NotRun  Status = iota // Not jet executed
	Skipped               // Omitted deliberately
	Pass                  // That's what we want
	Fail                  // One ore more checks failed
	Error                 // Request or body reading failed (not for checks).
	Bogus                 // Bogus test or check (malformd URL, bad regexp, etc.)
)

func (s Status) String() string {
	return []string{"NotRun", "Skipped", "Pass", "Fail", "Error", "Bogus"}[int(s)]
}

func (s Status) MarshalText() ([]byte, error) {
	if s < 0 || s > Bogus {
		return []byte(""), fmt.Errorf("no such status %d", s)
	}
	return []byte(s.String()), nil
}

// Stats counts the test results of sr.
func (s *Suite) Stats() (notRun int, skipped int, passed int, failed int, errored int, bogus int) {
	for _, tr := range s.AllTests() {
		switch tr.Status {
		case NotRun:
			notRun++
		case Skipped:
			skipped++
		case Pass:
			passed++
		case Fail:
			failed++
		case Error:
			errored++
		case Bogus:
			bogus++
		default:
			panic(fmt.Sprintf("No such Status %d in suite %q test %q",
				tr.Status, s.Name, tr.Name))
		}
	}
	return
}

// ----------------------------------------------------------------------------
// CheckResult

// CheckResult captures the outcom of a single check inside a test.
type CheckResult struct {
	Name     string   // Name of the check as registered.
	JSON     string   // JSON serialization of check.
	Status   Status   // Outcome of check. All status but Error
	Duration Duration // How long the check took.
	Error    error    // For a Status of Bogus or Fail.
}

// ----------------------------------------------------------------------------
// Templates to output

var defaultCheckTmpl = `{{define "CHECK"}}{{printf "%-7s %-15s %s" .Status .Name .JSON}}` +
	`{{if eq .Status 3 5}} {{.Error.Error}}{{end}}{{end}}`

var htmlCheckTmpl = `{{define "CHECK"}}

Check:
      {{ToUpper .Status.String}}
      {{.Name}} ▹

Check:
      {{ToUpper .Status.String}}
      {{.Name}} ▾

Checking took {{.Duration}}

{{.JSON}}

      {{if eq .Status 3 5}}
{{.Error.Error}}
{{end}}

{{end}}
`

var defaultTestTmpl = `{{define "TEST"}}{{ToUpper .Status.String}}: {{.Name}}{{if gt .Tries 1}}
  {{printf "(after %d tries)" .Tries}}{{end}}
  Started: {{.Started}}   Duration: {{.FullDuration}}   Request: {{.Duration}}{{if .Error}}
  Error: {{.Error}}{{end}}
{{if eq .Status 2 3 4 5}}
  {{if .CheckResults}}Checks:
{{range $i, $c := .CheckResults}}{{printf "    %2d. " $i}}{{template "CHECK" .}}
{{end}}{{end}}{{end}}{{end}}`

var htmlTestTmpl = `{{define "TEST"}}

{{.SeqNo}}:
      {{ToUpper .Status.String}}
      "{{.Name}}"
      ({{.FullDuration}}) ▹

{{.SeqNo}}:
      {{ToUpper .Status.String}}
      "{{.Name}}"
      ({{.FullDuration}}) ▾

{{.Description}}

	Started: {{.Started}}

	Full Duration: {{.FullDuration}}

        Number of tries: {{.Tries}}

        Request Duration: {{.Duration}}
        {{if .Error}}
Error: {{.Error}}{{end}}

      {{if eq .Status 2 3 4 5}}{{if .CheckResults}}

          {{range $i, $c := .CheckResults}}{{template "CHECK" .}}{{end}}

      {{end}}{{end}}
      {{if .Request.Request}}{{template "REQUEST" .}}{{end}}
      {{if .Response.Response}}{{template "RESPONSE" .}}{{end}}

{{end}}`

var htmlHeaderTmpl = `{{define "HEADER"}}

  {{range $h, $v := .}}
    {{range $v}}
      {{printf "%25s: " $h}} {{.}}

    {{end}}
  {{end}}

{{end}}`

var htmlResponseTmpl = `{{define "RESPONSE"}}

HTTP Response ▾

      {{if .Response.Response}}
        {{template "HEADER" .Response.Response.Header}}
      {{end}}
      {{if .Response.BodyErr}}Error reading body: {{.Response.BodyErr.Error}}
      {{else}}
        Response Body
      {{end}}

HTTP Response ▹

{{end}}
`

var htmlRequestTmpl = `{{define "REQUEST"}}

HTTP Request ▾

      {{.Request.Request.Method}} {{.Request.Request.URL.String}}
      {{template "HEADER" .Request.Request.Header}}

{{.Request.SentBody}}

HTTP Request ▹

{{end}}
`

var defaultSuiteTmpl = `{{Box (printf "%s: %s" (ToUpper .Status.String) .Name) ""}}{{if .Error}}
Error: {{.Error}}{{end}}
Started: {{.Started}}   Duration: {{.Duration}}
Individual tests:
{{range .Setup}}{{template "TEST" .}}{{end}}
{{range .Tests}}{{template "TEST" .}}{{end}}
{{range .Teardown}}{{template "TEST" .}}{{end}}
`

var htmlStyleTmpl = `{{define "STYLE"}}

{{end}}`

var htmlJavascriptTmpl = `{{define "JAVASCRIPT"}}

{{end}}`

var htmlSuiteTmpl = `<!DOCTYPE html>

  <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
  {{template "STYLE"}}
  <title>Suite {{.Name}}</title>

Results of Suite {{.Name}}

{{.Description}}

  Status: {{ToUpper .Status.String}}

  Started: {{.Started}}

  Full Duration: {{.Duration}}

{{range .AllTests}}{{template "TEST" .}}{{end}}

{{template "JAVASCRIPT"}}

`

var (
	TestTmpl      *template.Template
	SuiteTmpl     *template.Template
	HtmlSuiteTmpl *htmltemplate.Template
)

func init() {
	fm := make(template.FuncMap)
	fm["Underline"] = Underline
	fm["Box"] = Box
	fm["ToUpper"] = ToUpper

	TestTmpl = template.New("TEST")
	TestTmpl.Funcs(fm)
	TestTmpl = template.Must(TestTmpl.Parse(defaultTestTmpl))
	TestTmpl = template.Must(TestTmpl.Parse(defaultCheckTmpl))

	SuiteTmpl = template.New("SUITE")
	SuiteTmpl.Funcs(fm)
	SuiteTmpl = template.Must(SuiteTmpl.Parse(defaultSuiteTmpl))
	SuiteTmpl = template.Must(SuiteTmpl.Parse(defaultTestTmpl))
	SuiteTmpl = template.Must(SuiteTmpl.Parse(defaultCheckTmpl))

	HtmlSuiteTmpl = htmltemplate.New("SUITE")
	HtmlSuiteTmpl.Funcs(htmltemplate.FuncMap{"ToUpper": ToUpper})
	HtmlSuiteTmpl = htmltemplate.Must(HtmlSuiteTmpl.Parse(htmlSuiteTmpl))
	HtmlSuiteTmpl = htmltemplate.Must(HtmlSuiteTmpl.Parse(htmlTestTmpl))
	HtmlSuiteTmpl = htmltemplate.Must(HtmlSuiteTmpl.Parse(htmlCheckTmpl))
	HtmlSuiteTmpl = htmltemplate.Must(HtmlSuiteTmpl.Parse(htmlResponseTmpl))
	HtmlSuiteTmpl = htmltemplate.Must(HtmlSuiteTmpl.Parse(htmlRequestTmpl))
	HtmlSuiteTmpl = htmltemplate.Must(HtmlSuiteTmpl.Parse(htmlHeaderTmpl))
	HtmlSuiteTmpl = htmltemplate.Must(HtmlSuiteTmpl.Parse(htmlStyleTmpl))
	HtmlSuiteTmpl = htmltemplate.Must(HtmlSuiteTmpl.Parse(htmlJavascriptTmpl))
}

func (t Test) PrintReport(w io.Writer) error {
	return TestTmpl.Execute(os.Stdout, t)
}

func (r Suite) PrintReport(w io.Writer) error {
	return SuiteTmpl.Execute(os.Stdout, r)
}

func (s Suite) HTMLReport(dir string) error {
	report, err := os.Create(path.Join(dir, "Report.html"))
	if err != nil {
		return err
	}
	err = HtmlSuiteTmpl.Execute(report, s)
	if err != nil {
		return err
	}
	for _, tr := range s.AllTests() {
		body := tr.Response.BodyBytes
		err = ioutil.WriteFile(path.Join(dir, tr.SeqNo+".ResponseBody"), body, 0666)
		if err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>ht: beautify text reports of suites<commit_after>// Copyright 2014 Volker Dobler.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ht

import (
	"fmt"
	htmltemplate "html/template"
	"io"
	"io/ioutil"
	"os"
	"path"
	"text/template"
)

// ----------------------------------------------------------------------------
// Status

// Status describes the status of a Test or a Check.
type Status int

const (
	NotRun  Status = iota // Not jet executed
	Skipped               // Omitted deliberately
	Pass                  // That's what we want
	Fail                  // One ore more checks failed
	Error                 // Request or body reading failed (not for checks).
	Bogus                 // Bogus test or check (malformd URL, bad regexp, etc.)
)

func (s Status) String() string {
	return []string{"NotRun", "Skipped", "Pass", "Fail", "Error", "Bogus"}[int(s)]
}

func (s Status) MarshalText() ([]byte, error) {
	if s < 0 || s > Bogus {
		return []byte(""), fmt.Errorf("no such status %d", s)
	}
	return []byte(s.String()), nil
}

// Stats counts the test results of sr.
func (s *Suite) Stats() (notRun int, skipped int, passed int, failed int, errored int, bogus int) {
	for _, tr := range s.AllTests() {
		switch tr.Status {
		case NotRun:
			notRun++
		case Skipped:
			skipped++
		case Pass:
			passed++
		case Fail:
			failed++
		case Error:
			errored++
		case Bogus:
			bogus++
		default:
			panic(fmt.Sprintf("No such Status %d in suite %q test %q",
				tr.Status, s.Name, tr.Name))
		}
	}
	return
}

// ----------------------------------------------------------------------------
// CheckResult

// CheckResult captures the outcom of a single check inside a test.
type CheckResult struct {
	Name     string   // Name of the check as registered.
	JSON     string   // JSON serialization of check.
	Status   Status   // Outcome of check. All status but Error
	Duration Duration // How long the check took.
	Error    error    // For a Status of Bogus or Fail.
}

// ----------------------------------------------------------------------------
// Templates to output

var defaultCheckTmpl = `{{define "CHECK"}}{{printf "%-7s %-15s %s" .Status .Name .JSON}}` +
	`{{if eq .Status 3 5}} {{.Error.Error}}{{end}}{{end}}`

var htmlCheckTmpl = `{{define "CHECK"}}

Check:
      {{ToUpper .Status.String}}
      {{.Name}} ▹

Check:
      {{ToUpper .Status.String}}
      {{.Name}} ▾

Checking took {{.Duration}}

{{.JSON}}

      {{if eq .Status 3 5}}
{{.Error.Error}}
{{end}}

{{end}}
`

var defaultTestTmpl = `{{define "TEST"}}{{ToUpper .Status.String}}: {{.Name}}{{if gt .Tries 1}}
  {{printf "(after %d tries)" .Tries}}{{end}}
  Started: {{.Started}}   Duration: {{.FullDuration}}   Request: {{.Duration}}{{if .Error}}
  Error: {{.Error}}{{end}}
{{if eq .Status 2 3 4 5}}  {{if .CheckResults}}Checks:
{{range $i, $c := .CheckResults}}{{printf "    %2d. " $i}}{{template "CHECK" .}}
{{end}}{{end}}{{end}}{{end}}`

var htmlTestTmpl = `{{define "TEST"}}

{{.SeqNo}}:
      {{ToUpper .Status.String}}
      "{{.Name}}"
      ({{.FullDuration}}) ▹

{{.SeqNo}}:
      {{ToUpper .Status.String}}
      "{{.Name}}"
      ({{.FullDuration}}) ▾

{{.Description}}

	Started: {{.Started}}

	Full Duration: {{.FullDuration}}

        Number of tries: {{.Tries}}

        Request Duration: {{.Duration}}
        {{if .Error}}
Error: {{.Error}}{{end}}

      {{if eq .Status 2 3 4 5}}{{if .CheckResults}}

          {{range $i, $c := .CheckResults}}{{template "CHECK" .}}{{end}}

      {{end}}{{end}}
      {{if .Request.Request}}{{template "REQUEST" .}}{{end}}
      {{if .Response.Response}}{{template "RESPONSE" .}}{{end}}

{{end}}`

var htmlHeaderTmpl = `{{define "HEADER"}}

  {{range $h, $v := .}}
    {{range $v}}
      {{printf "%25s: " $h}} {{.}}

    {{end}}
  {{end}}

{{end}}`

var htmlResponseTmpl = `{{define "RESPONSE"}}

HTTP Response ▾

      {{if .Response.Response}}
        {{template "HEADER" .Response.Response.Header}}
      {{end}}
      {{if .Response.BodyErr}}Error reading body: {{.Response.BodyErr.Error}}
      {{else}}
        Response Body
      {{end}}

HTTP Response ▹

{{end}}
`

var htmlRequestTmpl = `{{define "REQUEST"}}

HTTP Request ▾

      {{.Request.Request.Method}} {{.Request.Request.URL.String}}
      {{template "HEADER" .Request.Request.Header}}

{{.Request.SentBody}}

HTTP Request ▹

{{end}}
`

var defaultSuiteTmpl = `{{Box (printf "%s: %s" (ToUpper .Status.String) .Name) ""}}{{if .Error}}
Error: {{.Error}}{{end}}
Started: {{.Started}}   Duration: {{.Duration}}

{{range .Setup}}{{template "TEST" .}}
{{end}}
{{range .Tests}}{{template "TEST" .}}
{{end}}
{{range .Teardown}}{{template "TEST" .}}
{{end}}
`

var htmlStyleTmpl = `{{define "STYLE"}}

{{end}}`

var htmlJavascriptTmpl = `{{define "JAVASCRIPT"}}

{{end}}`

var htmlSuiteTmpl = `<!DOCTYPE html>

  <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
  {{template "STYLE"}}
  <title>Suite {{.Name}}</title>

Results of Suite {{.Name}}

{{.Description}}

  Status: {{ToUpper .Status.String}}

  Started: {{.Started}}

  Full Duration: {{.Duration}}

{{range .AllTests}}{{template "TEST" .}}{{end}}

{{template "JAVASCRIPT"}}

`

var (
	TestTmpl      *template.Template
	SuiteTmpl     *template.Template
	HtmlSuiteTmpl *htmltemplate.Template
)

func init() {
	fm := make(template.FuncMap)
	fm["Underline"] = Underline
	fm["Box"] = Box
	fm["ToUpper"] = ToUpper

	TestTmpl = template.New("TEST")
	TestTmpl.Funcs(fm)
	TestTmpl = template.Must(TestTmpl.Parse(defaultTestTmpl))
	TestTmpl = template.Must(TestTmpl.Parse(defaultCheckTmpl))

	SuiteTmpl = template.New("SUITE")
	SuiteTmpl.Funcs(fm)
	SuiteTmpl = template.Must(SuiteTmpl.Parse(defaultSuiteTmpl))
	SuiteTmpl = template.Must(SuiteTmpl.Parse(defaultTestTmpl))
	SuiteTmpl = template.Must(SuiteTmpl.Parse(defaultCheckTmpl))

	HtmlSuiteTmpl = htmltemplate.New("SUITE")
	HtmlSuiteTmpl.Funcs(htmltemplate.FuncMap{"ToUpper": ToUpper})
	HtmlSuiteTmpl = htmltemplate.Must(HtmlSuiteTmpl.Parse(htmlSuiteTmpl))
	HtmlSuiteTmpl = htmltemplate.Must(HtmlSuiteTmpl.Parse(htmlTestTmpl))
	HtmlSuiteTmpl = htmltemplate.Must(HtmlSuiteTmpl.Parse(htmlCheckTmpl))
	HtmlSuiteTmpl = htmltemplate.Must(HtmlSuiteTmpl.Parse(htmlResponseTmpl))
	HtmlSuiteTmpl = htmltemplate.Must(HtmlSuiteTmpl.Parse(htmlRequestTmpl))
	HtmlSuiteTmpl = htmltemplate.Must(HtmlSuiteTmpl.Parse(htmlHeaderTmpl))
	HtmlSuiteTmpl = htmltemplate.Must(HtmlSuiteTmpl.Parse(htmlStyleTmpl))
	HtmlSuiteTmpl = htmltemplate.Must(HtmlSuiteTmpl.Parse(htmlJavascriptTmpl))
}

func (t Test) PrintReport(w io.Writer) error {
	return TestTmpl.Execute(os.Stdout, t)
}

func (r Suite) PrintReport(w io.Writer) error {
	return SuiteTmpl.Execute(os.Stdout, r)
}

func (s Suite) HTMLReport(dir string) error {
	report, err := os.Create(path.Join(dir, "Report.html"))
	if err != nil {
		return err
	}
	err = HtmlSuiteTmpl.Execute(report, s)
	if err != nil {
		return err
	}
	for _, tr := range s.AllTests() {
		body := tr.Response.BodyBytes
		err = ioutil.WriteFile(path.Join(dir, tr.SeqNo+".ResponseBody"), body, 0666)
		if err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package html

import (
	"go/ast"
	"go/parser"
	"go/printer"
	"go/token"
	"os"

	"github.com/PieterD/agoge/internal/build"
)

func Incorporate(pkg string, outfile string, infile ...string) error {
	fset := token.NewFileSet()
	file := build.NewFile(
		pkg,
		build.ImportList(
			build.Import("", "html/template"),
		),
		&ast.FuncDecl{
			Name: &ast.Ident{
				Name: "init",
			},
			Type: &ast.FuncType{
				Params: &ast.FieldList{
					List: []*ast.Field{},
				},
			},
			Body: &ast.BlockStmt{
				List: []ast.Stmt{
					buildInit(infile),
				},
			},
		},
	)
	printer.Fprint(os.Stdout, fset, file)
	return nil
}

func buildInit(infiles []string) []ast.Stmt {
	parser.ParseExpr("tmpl.New(\"style.css\")")
	return nil
}
<commit_msg>Ok, works now.<commit_after>package html

import (
	"go/ast"
	"go/parser"
	"go/printer"
	"go/token"
	"os"

	"github.com/PieterD/agoge/internal/build"
)

func Incorporate(pkg string, outfile string, infile ...string) error {
	fset := token.NewFileSet()
	file := build.NewFile(
		pkg,
		build.ImportList(
			build.Import("", "html/template"),
		),
		&ast.FuncDecl{
			Name: &ast.Ident{
				Name: "init",
			},
			Type: &ast.FuncType{
				Params: &ast.FieldList{
					List: []*ast.Field{},
				},
			},
			Body: &ast.BlockStmt{
				List: buildInit(infile),
			},
		},
	)
	printer.Fprint(os.Stdout, fset, file)
	return nil
}

func buildInit(infiles []string) []ast.Stmt {
	expr, err := parser.ParseExpr("tmpl.New(\"style.css\").Parse(``)")
	if err != nil {
		panic(err)
	}
	return []ast.Stmt{
		&ast.ExprStmt{
			X: expr,
		},
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"html/template"
	"log"
	"net/http"
	"time"

	"golang.org/x/net/context"

	"github.com/skypies/util/date"
	"github.com/skypies/util/widget"

	fdbui "github.com/skypies/flightdb/ui"

	"github.com/skypies/complaints/complaintdb"
	"github.com/skypies/complaints/complaintdb/types"
	"github.com/skypies/complaints/config"
	"github.com/skypies/complaints/flightid"
	"github.com/skypies/complaints/login"
	"github.com/skypies/complaints/ui"
)

var(
	templates *template.Template

	// Whenever a handler is required to have a session, but doesn't have one, it will
	// invoke this handler instead.
	fallbackHandler = landingPageHandler
)

func init() {
	templates = ui.LoadTemplates("app/frontend/web/templates")
	ui.InitSessionStore(config.Get("sessions.key"), config.Get("sessions.prevkey"))

	login.OnSuccessCallback = func(w http.ResponseWriter, r *http.Request, email string) error {
		ui.CreateSession(r.Context(), w, r, ui.UserSession{Email:email})
		return nil
	}
	//login.Host                  = "https://frontend-dot-serfr0-1000.appspot.com"
	login.Host                  = "https://stop.jetnoise.net"
	login.RedirectUrlStem       = "/login" // oauth2 callbacks will register  under here
	login.AfterLoginRelativeUrl = "/" // where the user finally ends up, after being logged in
	login.Init()

	http.HandleFunc("/",                      ui.WithCtxTlsSession(rootHandler, fallbackHandler))
	http.HandleFunc("/masq",                  ui.WithCtxTlsAdmin(masqueradeHandler))
	http.HandleFunc("/logout",                ui.WithCtx(logoutHandler))
	http.HandleFunc("/faq",                   faqHandler)
	http.HandleFunc("/intro",                 gettingStartedHandler)
	http.HandleFunc("/down",                  flatPageHandler)

	http.HandleFunc("/cdb/list",              ui.WithCtxTlsAdmin(listUsersComplaintsHandler))
	http.HandleFunc("/cdb/airspace",          ui.HasAdmin(flightid.AirspaceHandler))
	http.HandleFunc("/cdb/comp/debug",        ui.HasAdmin(complaintdb.ComplaintDebugHandler))

	http.HandleFunc("/download-complaints",   ui.WithCtxTlsSession(DownloadHandler,fallbackHandler))
	http.HandleFunc("/personal-report",       ui.WithCtxTlsSession(personalReportHandler,fallbackHandler))
	http.HandleFunc("/personal-report/results", makeRedirectHandler("/personal-report"))

	http.HandleFunc("/profile",               ui.WithCtxTlsSession(profileFormHandler,fallbackHandler))
	http.HandleFunc("/profile-update",        ui.WithCtxTlsSession(profileUpdateHandler,fallbackHandler))
	http.HandleFunc("/profile-buttons",       ui.WithCtxTlsSession(profileButtonsHandler,fallbackHandler))
	http.HandleFunc("/profile-button-add",    ui.WithCtxTlsSession(profileButtonAddHandler,fallbackHandler))
	http.HandleFunc("/profile-button-delete", ui.WithCtxTlsSession(profileButtonDeleteHandler,fallbackHandler))

	http.HandleFunc("/button",                buttonHandler)
	http.HandleFunc("/add-complaint",         ui.WithCtxTlsSession(addComplaintHandler, fallbackHandler))
	http.HandleFunc("/add-historical-complaint", ui.WithCtxTlsSession(addHistoricalComplaintHandler,fallbackHandler))
	http.HandleFunc("/update-complaint",      ui.WithCtxTlsSession(updateComplaintHandler,fallbackHandler))
	http.HandleFunc("/delete-complaints",     ui.WithCtxTlsSession(deleteComplaintsHandler,fallbackHandler))
	http.HandleFunc("/view-complaint",        ui.WithCtxTlsSession(viewComplaintHandler,fallbackHandler))
	http.HandleFunc("/complaint-updateform",  ui.WithCtxTlsSession(complaintUpdateFormHandler,fallbackHandler))

	http.HandleFunc("/heatmap",               heatmapHandler)
	http.HandleFunc("/aws-iot",               awsIotHandler)
	http.HandleFunc("/stats",                 statsHandler)
	http.HandleFunc("/complaints-for",        complaintsForFlightHandler)

	http.HandleFunc("/map",                   widget.WithCtxTmpl(req2ctx, templates, fdbui.MapHandler))
}

// {{{ HintedComplaints

// A complaint, plus hints about how to render it
type HintedComplaint struct {
	C types.Complaint
	BestIdent string
	Notes []string
	Omit bool
}

func hintComplaints(in []types.Complaint, isSuperHinter bool) []HintedComplaint {
	out := []HintedComplaint{}

	for _,c := range in {
		hc := HintedComplaint{C: c}

		if c.AircraftOverhead.FlightNumber != "" {
			hc.BestIdent = c.AircraftOverhead.BestIdent()
		}

		if c.Description != "" {
				hc.Notes = append(hc.Notes,fmt.Sprintf("Your notes: %s", c.Description))
		}
		if c.Version >= 2 {
			if c.HeardSpeedbreaks {hc.Notes = append(hc.Notes, "Flight used speedbrakes")}
			if c.Loudness == 2 {hc.Notes = append(hc.Notes, "Flight was LOUD")}
			if c.Loudness == 3 {hc.Notes = append(hc.Notes, "Flight was INSANELY LOUD")}
			if c.Activity != "" {
				hc.Notes = append(hc.Notes,fmt.Sprintf("Activity disturbed: %s", c.Activity))
			}
		}

		out = append(out, hc)
	}

	return out
}

// }}}

// {{{ landingPageHandler

func landingPageHandler (ctx context.Context, w http.ResponseWriter, r *http.Request) {
	var params = map[string]interface{}{
		"google": login.Goauth2.GetLoginUrl(w,r),
		"googlefromscratch": login.Goauth2.GetLogoutUrl(w,r),
		"facebook": login.Fboauth2.GetLoginUrl(w,r),
	}

	if err := templates.ExecuteTemplate(w, "landing", params); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// }}}
// {{{ rootHandler

func rootHandler (ctx context.Context, w http.ResponseWriter, r *http.Request) {
	if r.URL.Scheme == "http" {
		safeUrl := r.URL
		safeUrl.Scheme = "https"
		http.Redirect(w, r, safeUrl.String(), http.StatusFound)
		return
	}

	cdb := complaintdb.NewDB(ctx)
	sesh,_ := ui.GetUserSession(ctx)

	if sesh.Email == "" {
		// "this should never happen", 'cos WithSession takes care of it all
		http.Error(w, "newRoot: invoked, but no sesh.Email", http.StatusInternalServerError)
		return
	}

	cdb.Debugf("root_001", "session obtained: tstamp=%s, age=%s", sesh.CreatedAt, time.Since(sesh.CreatedAt))

	modes := map[string]bool{}

	// The rootHandler is the URL wildcard. Except Fragments, which are broken.
	if r.URL.Path == "/full" {
		modes["expanded"] = true
	} else if r.URL.Path == "/edit" {
		modes["edit"] = true
	} else if r.URL.Path == "/debug" {
		modes["debug"] = true
	} else if r.URL.Path != "/" {
		// This is a request for apple_icon or somesuch junk. Just say no.
		http.NotFound(w, r)
		return
	}

	cdb.Debugf("root_004", "about get cdb.GetAllByEmailAddress")
	cap, err := cdb.GetAllByEmailAddress(sesh.Email, modes["expanded"])
	if cap==nil && err==nil {
		// No profile exists; daisy-chain into profile page
		http.Redirect(w, r, "/profile", http.StatusFound)
		return
	} else if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	cdb.Debugf("root_005", "cdb.GetAllByEmailAddress done")

	// FIXME: how to check if complaints user is admin user /
	//modes["admin"] = user.Current(ctx)!=nil && user.Current(ctx).Admin
	//modes["superuser"] = modes["admin"]

	// Default to "", unless we had a complaint in the past hour.
	lastActivity := ""
	if len(cap.Complaints) > 0 && time.Since(cap.Complaints[0].Timestamp) < time.Hour {
		lastActivity = cap.Complaints[0].Activity
	}

	var complaintDefaults = map[string]interface{}{
		"ActivityList": kActivities,  // lives in add-complaint
		"DefaultActivity": lastActivity,
		"DefaultLoudness": 1,
		"NewForm": true,
	}

	message := ""
	disableReporting := false
	if cap.Profile.FullName == "" {
		message += "
We don't have your full name
"
		disableReporting = true
	}
	if cap.Profile.StructuredAddress.Zip == "" {
		message += "
We don't have an accurate address
"
		disableReporting = true
	}
	if message != "" {
		message = fmt.Sprintf("
We've found some problems with your profile:

%s
"+
			"
 Without this data, your complaints won't be counted, so please "+
			"update your profile before submitting any more complaints !
", message)
	}

	var params = map[string]interface{}{
		//"Message": template.HTML("Hi!"),
		"Cap": *cap,
		"Complaints": hintComplaints(cap.Complaints, modes["superuser"]),
		"Now": date.NowInPdt(),
		"Modes": modes,
		"ComplaintDefaults": complaintDefaults,
		"Message": template.HTML(message),
		//"Info": template.HTML("Hi!"),
		"DisableReporting": disableReporting,
	}

	if err := templates.ExecuteTemplate(w, "main", params); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// }}}
// {{{ logoutHandler

func logoutHandler (ctx context.Context, w http.ResponseWriter, r *http.Request) {
	ui.OverwriteSessionToNil(ctx, w, r)
	http.Redirect(w, r, "/", http.StatusFound)
}

// }}}
// {{{ masqueradeHandler

func masqueradeHandler (ctx context.Context, w http.ResponseWriter, r *http.Request) {
	email := r.FormValue("e")
	if email == "" {
		http.Error(w, "masq needs 'e'", http.StatusInternalServerError)
		return
	}

	log.Printf("masq into [%s]", email)

	ui.CreateSession(ctx, w, r, ui.UserSession{Email:email})

	http.Redirect(w, r, "/", http.StatusFound)
}

// }}}

// {{{ downHandler

func downHandler (w http.ResponseWriter, r *http.Request) {
	http.Redirect(w, r, "/down", http.StatusFound)
}

// }}}
// {{{ redirects

func makeRedirectHandler(target string) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, target, http.StatusFound)
	}
}

func faqHandler (w http.ResponseWriter, r *http.Request) {
	http.Redirect(w, r, "https://sites.google.com/a/jetnoise.net/how-to/faq", http.StatusFound)
}

func gettingStartedHandler (w http.ResponseWriter, r *http.Request) {
	http.Redirect(w, r, "https://sites.google.com/a/jetnoise.net/how-to/", http.StatusFound)
}

// }}}

// {{{ -------------------------={ E N D }=----------------------------------

// Local variables:
// folded-file: t
// end:

// }}}
<commit_msg>Final tidy<commit_after>package main

import (
	"fmt"
	"html/template"
	"log"
	"net/http"
	"time"

	"golang.org/x/net/context"

	"github.com/skypies/util/date"
	"github.com/skypies/util/widget"

	fdbui "github.com/skypies/flightdb/ui"

	"github.com/skypies/complaints/complaintdb"
	"github.com/skypies/complaints/complaintdb/types"
	"github.com/skypies/complaints/config"
	"github.com/skypies/complaints/flightid"
	"github.com/skypies/complaints/login"
	"github.com/skypies/complaints/ui"
)

var(
	templates *template.Template

	// Whenever a handler is required to have a session, but doesn't have one, it will
	// invoke this handler instead.
	fallbackHandler = landingPageHandler
)

func init() {
	templates = ui.LoadTemplates("app/frontend/web/templates") // for appengine golang, relative to git module root
	ui.InitSessionStore(config.Get("sessions.key"), config.Get("sessions.prevkey"))

	login.OnSuccessCallback = func(w http.ResponseWriter, r *http.Request, email string) error {
		ui.CreateSession(r.Context(), w, r, ui.UserSession{Email:email})
		return nil
	}
	login.Host                  = "https://stop.jetnoise.net"
	login.RedirectUrlStem       = "/login" // oauth2 callbacks will register  under here
	login.AfterLoginRelativeUrl = "/" // where the user finally ends up, after being logged in
	login.Init()

	http.HandleFunc("/",                      ui.WithCtxTlsSession(rootHandler, fallbackHandler))
	http.HandleFunc("/masq",                  ui.WithCtxTlsAdmin(masqueradeHandler))
	http.HandleFunc("/logout",                ui.WithCtx(logoutHandler))
	http.HandleFunc("/faq",                   faqHandler)
	http.HandleFunc("/intro",                 gettingStartedHandler)
	http.HandleFunc("/down",                  flatPageHandler)

	http.HandleFunc("/cdb/list",              ui.WithCtxTlsAdmin(listUsersComplaintsHandler))
	http.HandleFunc("/cdb/airspace",          ui.HasAdmin(flightid.AirspaceHandler))
	http.HandleFunc("/cdb/comp/debug",        ui.HasAdmin(complaintdb.ComplaintDebugHandler))

	http.HandleFunc("/download-complaints",   ui.WithCtxTlsSession(DownloadHandler,fallbackHandler))
	http.HandleFunc("/personal-report",       ui.WithCtxTlsSession(personalReportHandler,fallbackHandler))
	http.HandleFunc("/personal-report/results", makeRedirectHandler("/personal-report"))

	http.HandleFunc("/profile",               ui.WithCtxTlsSession(profileFormHandler,fallbackHandler))
	http.HandleFunc("/profile-update",        ui.WithCtxTlsSession(profileUpdateHandler,fallbackHandler))
	http.HandleFunc("/profile-buttons",       ui.WithCtxTlsSession(profileButtonsHandler,fallbackHandler))
	http.HandleFunc("/profile-button-add",    ui.WithCtxTlsSession(profileButtonAddHandler,fallbackHandler))
	http.HandleFunc("/profile-button-delete", ui.WithCtxTlsSession(profileButtonDeleteHandler,fallbackHandler))

	http.HandleFunc("/button",                buttonHandler)
	http.HandleFunc("/add-complaint",         ui.WithCtxTlsSession(addComplaintHandler, fallbackHandler))
	http.HandleFunc("/add-historical-complaint", ui.WithCtxTlsSession(addHistoricalComplaintHandler,fallbackHandler))
	http.HandleFunc("/update-complaint",      ui.WithCtxTlsSession(updateComplaintHandler,fallbackHandler))
	http.HandleFunc("/delete-complaints",     ui.WithCtxTlsSession(deleteComplaintsHandler,fallbackHandler))
	http.HandleFunc("/view-complaint",        ui.WithCtxTlsSession(viewComplaintHandler,fallbackHandler))
	http.HandleFunc("/complaint-updateform",  ui.WithCtxTlsSession(complaintUpdateFormHandler,fallbackHandler))

	http.HandleFunc("/heatmap",               heatmapHandler)
	http.HandleFunc("/aws-iot",               awsIotHandler)
	http.HandleFunc("/stats",                 statsHandler)
	http.HandleFunc("/complaints-for",        complaintsForFlightHandler)

	http.HandleFunc("/map",                   widget.WithCtxTmpl(req2ctx, templates, fdbui.MapHandler))
}

// {{{ HintedComplaints

// A complaint, plus hints about how to render it
type HintedComplaint struct {
	C types.Complaint
	BestIdent string
	Notes []string
	Omit bool
}

func hintComplaints(in []types.Complaint, isSuperHinter bool) []HintedComplaint {
	out := []HintedComplaint{}

	for _,c := range in {
		hc := HintedComplaint{C: c}

		if c.AircraftOverhead.FlightNumber != "" {
			hc.BestIdent = c.AircraftOverhead.BestIdent()
		}

		if c.Description != "" {
				hc.Notes = append(hc.Notes,fmt.Sprintf("Your notes: %s", c.Description))
		}
		if c.Version >= 2 {
			if c.HeardSpeedbreaks {hc.Notes = append(hc.Notes, "Flight used speedbrakes")}
			if c.Loudness == 2 {hc.Notes = append(hc.Notes, "Flight was LOUD")}
			if c.Loudness == 3 {hc.Notes = append(hc.Notes, "Flight was INSANELY LOUD")}
			if c.Activity != "" {
				hc.Notes = append(hc.Notes,fmt.Sprintf("Activity disturbed: %s", c.Activity))
			}
		}

		out = append(out, hc)
	}

	return out
}

// }}}

// {{{ landingPageHandler

func landingPageHandler (ctx context.Context, w http.ResponseWriter, r *http.Request) {
	var params = map[string]interface{}{
		"google": login.Goauth2.GetLoginUrl(w,r),
		"googlefromscratch": login.Goauth2.GetLogoutUrl(w,r),
		"facebook": login.Fboauth2.GetLoginUrl(w,r),
	}

	if err := templates.ExecuteTemplate(w, "landing", params); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// }}}
// {{{ rootHandler

func rootHandler (ctx context.Context, w http.ResponseWriter, r *http.Request) {
	if r.URL.Scheme == "http" {
		safeUrl := r.URL
		safeUrl.Scheme = "https"
		http.Redirect(w, r, safeUrl.String(), http.StatusFound)
		return
	}

	cdb := complaintdb.NewDB(ctx)
	sesh,_ := ui.GetUserSession(ctx)

	if sesh.Email == "" {
		// "this should never happen", 'cos WithSession takes care of it all
		http.Error(w, "newRoot: invoked, but no sesh.Email", http.StatusInternalServerError)
		return
	}

	cdb.Debugf("root_001", "session obtained: tstamp=%s, age=%s", sesh.CreatedAt, time.Since(sesh.CreatedAt))

	modes := map[string]bool{}

	// The rootHandler is the URL wildcard. Except Fragments, which are broken.
	if r.URL.Path == "/full" {
		modes["expanded"] = true
	} else if r.URL.Path == "/edit" {
		modes["edit"] = true
	} else if r.URL.Path == "/debug" {
		modes["debug"] = true
	} else if r.URL.Path != "/" {
		// This is a request for apple_icon or somesuch junk. Just say no.
		http.NotFound(w, r)
		return
	}

	cdb.Debugf("root_004", "about get cdb.GetAllByEmailAddress")
	cap, err := cdb.GetAllByEmailAddress(sesh.Email, modes["expanded"])
	if cap==nil && err==nil {
		// No profile exists; daisy-chain into profile page
		http.Redirect(w, r, "/profile", http.StatusFound)
		return
	} else if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	cdb.Debugf("root_005", "cdb.GetAllByEmailAddress done")

	// FIXME: how to check if complaints user is admin user /
	//modes["admin"] = user.Current(ctx)!=nil && user.Current(ctx).Admin
	//modes["superuser"] = modes["admin"]

	// Default to "", unless we had a complaint in the past hour.
	lastActivity := ""
	if len(cap.Complaints) > 0 && time.Since(cap.Complaints[0].Timestamp) < time.Hour {
		lastActivity = cap.Complaints[0].Activity
	}

	var complaintDefaults = map[string]interface{}{
		"ActivityList": kActivities,  // lives in add-complaint
		"DefaultActivity": lastActivity,
		"DefaultLoudness": 1,
		"NewForm": true,
	}

	message := ""
	disableReporting := false
	if cap.Profile.FullName == "" {
		message += "
We don't have your full name
"
		disableReporting = true
	}
	if cap.Profile.StructuredAddress.Zip == "" {
		message += "
We don't have an accurate address
"
		disableReporting = true
	}
	if message != "" {
		message = fmt.Sprintf("
We've found some problems with your profile:

%s
"+
			"
 Without this data, your complaints won't be counted, so please "+
			"update your profile before submitting any more complaints !
", message)
	}

	var params = map[string]interface{}{
		//"Message": template.HTML("Hi!"),
		"Cap": *cap,
		"Complaints": hintComplaints(cap.Complaints, modes["superuser"]),
		"Now": date.NowInPdt(),
		"Modes": modes,
		"ComplaintDefaults": complaintDefaults,
		"Message": template.HTML(message),
		//"Info": template.HTML("Hi!"),
		"DisableReporting": disableReporting,
	}

	if err := templates.ExecuteTemplate(w, "main", params); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// }}}
// {{{ logoutHandler

func logoutHandler (ctx context.Context, w http.ResponseWriter, r *http.Request) {
	ui.OverwriteSessionToNil(ctx, w, r)
	http.Redirect(w, r, "/", http.StatusFound)
}

// }}}
// {{{ masqueradeHandler

func masqueradeHandler (ctx context.Context, w http.ResponseWriter, r *http.Request) {
	email := r.FormValue("e")
	if email == "" {
		http.Error(w, "masq needs 'e'", http.StatusInternalServerError)
		return
	}

	log.Printf("masq into [%s]", email)

	ui.CreateSession(ctx, w, r, ui.UserSession{Email:email})

	http.Redirect(w, r, "/", http.StatusFound)
}

// }}}

// {{{ downHandler

func downHandler (w http.ResponseWriter, r *http.Request) {
	http.Redirect(w, r, "/down", http.StatusFound)
}

// }}}
// {{{ redirects

func makeRedirectHandler(target string) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, target, http.StatusFound)
	}
}

func faqHandler (w http.ResponseWriter, r *http.Request) {
	http.Redirect(w, r, "https://sites.google.com/a/jetnoise.net/how-to/faq", http.StatusFound)
}

func gettingStartedHandler (w http.ResponseWriter, r *http.Request) {
	http.Redirect(w, r, "https://sites.google.com/a/jetnoise.net/how-to/", http.StatusFound)
}

// }}}

// {{{ -------------------------={ E N D }=----------------------------------

// Local variables:
// folded-file: t
// end:

// }}}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"strconv"
	"strings"
	"testing"
	"time"
)

var server *Server

func init() {
	server = RunServer()
}

func RunServer() *Server {
	server, err := NewServer("", "", "")
	if err != nil {
		log.Fatal(err)
	}

	listener, err := net.Listen("tcp", ":8080")
	if err != nil {
		log.Fatal(err)
	}
	mux := http.NewServeMux()
	mux.HandleFunc("/runLambda/", server.RunLambda)
	s := &http.Server{Addr: ":8080", Handler: mux}
	go func() {
		log.Fatal(s.Serve(listener))
	}()

	return server
}

func testReq(lambda_name string, post string) (string, error) {
	url := "http://localhost:8080/runLambda/" + lambda_name
	req, err := http.NewRequest("POST", url, strings.NewReader(post))
	if err != nil {
		return "", err
	}
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	return string(body), nil
}

func TestHello(t *testing.T) {
	recv, err := testReq("hello", "{}")
	if err != nil {
		t.Fatal(err)
	}
	expected := "\"hello\""
	if recv != expected {
		t.Fatalf("Expected '%v' from hello but got back '%v'\n", expected, recv)
	}
}

func TestEcho(t *testing.T) {
	values := []string{
		"{}",
		"{\"one\": 1}",
		"1",
		"\"test\"",
	}
	for _, send := range values {
		recv, err := testReq("echo", send)
		if err != nil {
			t.Fatal(err)
		}
		if recv != send {
			t.Fatalf("Sent '%v' to echo but got back '%v'\n", send, recv)
		}
	}
}

// TODO(tyler): this test needs fixing.  It passes even if the Docker
// image is not available.
func TestPull(t *testing.T) {
	_, err := testReq("pausable-start-timer", "{}")
	if err != nil {
		t.Fatal(err)
	}
}

// thread_counter starts a backup thread that runs forever,
// incrementing a counter between 10ms sleeps.  If pausing works, the
// counter won't tick many times between requests, even if wait
// between them.
func TestThreadPausing(t *testing.T) {
	img := "thread_counter"
	before_str, _ := testReq(img, "null")
	time.Sleep(100 * time.Millisecond)
	after_str, _ := testReq(img, "null")
	before, _ := strconv.Atoi(before_str)
	after, _ := strconv.Atoi(after_str)
	if after-before > 2 {
		t.Errorf("Background thread run between requests, ticking %v times\n", (after - before))
	}
}
<commit_msg>add echo benchmark. Run every go test<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"strconv"
	"strings"
	"testing"
	"time"
)

var server *Server

func init() {
	server = RunServer()
}

func RunServer() *Server {
	server, err := NewServer("", "", "")
	if err != nil {
		log.Fatal(err)
	}

	listener, err := net.Listen("tcp", ":8080")
	if err != nil {
		log.Fatal(err)
	}
	mux := http.NewServeMux()
	mux.HandleFunc("/runLambda/", server.RunLambda)
	s := &http.Server{Addr: ":8080", Handler: mux}
	go func() {
		log.Fatal(s.Serve(listener))
	}()

	return server
}

func testReq(lambda_name string, post string) (string, error) {
	url := "http://localhost:8080/runLambda/" + lambda_name
	req, err := http.NewRequest("POST", url, strings.NewReader(post))
	if err != nil {
		return "", err
	}
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	return string(body), nil
}

func TestHello(t *testing.T) {
	recv, err := testReq("hello", "{}")
	if err != nil {
		t.Fatal(err)
	}
	expected := "\"hello\""
	if recv != expected {
		t.Fatalf("Expected '%v' from hello but got back '%v'\n", expected, recv)
	}
}

func TestEcho(t *testing.T) {
	values := []string{
		"{}",
		"{\"one\": 1}",
		"1",
		"\"test\"",
	}
	for _, send := range values {
		recv, err := testReq("echo", send)
		if err != nil {
			t.Fatal(err)
		}
		if recv != send {
			t.Fatalf("Sent '%v' to echo but got back '%v'\n", send, recv)
		}
	}
}

// TODO(tyler): this test needs fixing.  It passes even if the Docker
// image is not available.
func TestPull(t *testing.T) {
	_, err := testReq("pausable-start-timer", "{}")
	if err != nil {
		t.Fatal(err)
	}
}

// thread_counter starts a backup thread that runs forever,
// incrementing a counter between 10ms sleeps.  If pausing works, the
// counter won't tick many times between requests, even if wait
// between them.
func TestThreadPausing(t *testing.T) {
	img := "thread_counter"
	before_str, _ := testReq(img, "null")
	time.Sleep(100 * time.Millisecond)
	after_str, _ := testReq(img, "null")
	before, _ := strconv.Atoi(before_str)
	after, _ := strconv.Atoi(after_str)
	if after-before > 2 {
		t.Errorf("Background thread run between requests, ticking %v times\n", (after - before))
	}
}

func BenchmarkEcho(b *testing.B) {
	values := []string{
		"{\"one\": 1}",
	}
	for i := 0; i < b.N; i++ {
		recv, err := testReq("echo", values[0])
		if err != nil {
			b.Fatal(err)
		}
		if recv != values[0] {
			b.Fatalf("Sent '%v' to echo but got back '%v'\n", values[0], recv)
		}
	}
}

// Run benchmark at each test, and print nicely
func TestFancyBenchmark(t *testing.T) {
	br := testing.Benchmark(BenchmarkEcho)
	us := br.NsPerOp() / (1000)
	fmt.Printf("\t--- Echo Benchmark Report ---\n")
	fmt.Printf("\tTiming: %vus per lambda req/rsp\n", us)
	fmt.Printf("\tMemory: %v\n", br.MemString())
}
<|endoftext|>


<commit_before>/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package nwo

const DefaultCoreTemplate = `---
logging:
  format: '%{color}%{time:2006-01-02 15:04:05.000 MST} [%{module}] %{shortfunc} -> %{level:.4s} %{id:03x}%{color:reset} %{message}'

peer:
  id: {{ Peer.ID }}
  networkId: {{ .NetworkID }}
  address: 127.0.0.1:{{ .PeerPort Peer "Listen" }}
  addressAutoDetect: true
  listenAddress: 127.0.0.1:{{ .PeerPort Peer "Listen" }}
  chaincodeListenAddress: 0.0.0.0:{{ .PeerPort Peer "Chaincode" }}
  keepalive:
    minInterval: 60s
    client:
      interval: 60s
      timeout: 20s
    deliveryClient:
      interval: 60s
      timeout: 20s
  gossip:
    bootstrap: 127.0.0.1:{{ .PeerPort Peer "Listen" }}
    endpoint: 127.0.0.1:{{ .PeerPort Peer "Listen" }}
    externalEndpoint: 127.0.0.1:{{ .PeerPort Peer "Listen" }}
    useLeaderElection: false
    orgLeader: true
    membershipTrackerInterval: 5s
    maxBlockCountToStore: 10
    maxPropagationBurstLatency: 10ms
    maxPropagationBurstSize: 10
    propagateIterations: 1
    propagatePeerNum: 3
    pullInterval: 4s
    pullPeerNum: 3
    requestStateInfoInterval: 4s
    publishStateInfoInterval: 4s
    stateInfoRetentionInterval:
    publishCertPeriod: 10s
    dialTimeout: 3s
    connTimeout: 2s
    recvBuffSize: 20
    sendBuffSize: 200
    digestWaitTime: 1s
    requestWaitTime: 1500ms
    responseWaitTime: 2s
    aliveTimeInterval: 5s
    aliveExpirationTimeout: 25s
    reconnectInterval: 25s
    election:
      startupGracePeriod: 15s
      membershipSampleInterval: 1s
      leaderAliveThreshold: 10s
      leaderElectionDuration: 5s
    pvtData:
      pullRetryThreshold: 7s
      transientstoreMaxBlockRetention: 1000
      pushAckTimeout: 3s
      btlPullMargin: 10
      reconcileBatchSize: 10
      reconcileSleepInterval: 10s
      reconciliationEnabled: true
      skipPullingInvalidTransactionsDuringCommit: false
      implicitCollectionDisseminationPolicy:
        requiredPeerCount: 0
        maxPeerCount: 1
    state:
       enabled: false
       checkInterval: 10s
       responseTimeout: 3s
       batchSize: 10
       blockBufferSize: 20
       maxRetries: 3
  events:
    address: 127.0.0.1:{{ .PeerPort Peer "Events" }}
    buffersize: 100
    timeout: 10ms
    timewindow: 15m
    keepalive:
      minInterval: 60s
  tls:
    enabled:  true
    clientAuthRequired: {{ .ClientAuthRequired }}
    cert:
      file: {{ .PeerLocalTLSDir Peer }}/server.crt
    key:
      file: {{ .PeerLocalTLSDir Peer }}/server.key
    clientCert:
      file: {{ .PeerLocalTLSDir Peer }}/server.crt
    clientKey:
      file: {{ .PeerLocalTLSDir Peer }}/server.key
    rootcert:
      file: {{ .PeerLocalTLSDir Peer }}/ca.crt
    clientRootCAs:
      files:
      - {{ .PeerLocalTLSDir Peer }}/ca.crt
  authentication:
    timewindow: 15m
  fileSystemPath: filesystem
  BCCSP:
    Default: SW
    SW:
      Hash: SHA2
      Security: 256
      FileKeyStore:
        KeyStore:
  mspConfigPath: {{ .PeerLocalMSPDir Peer }}
  localMspId: {{ (.Organization Peer.Organization).MSPID }}
  deliveryclient:
    reconnectTotalTimeThreshold: 3600s
  localMspType: bccsp
  profile:
    enabled:     false
    listenAddress: 127.0.0.1:{{ .PeerPort Peer "ProfilePort" }}
  handlers:
    authFilters:
    - name: DefaultAuth
    - name: ExpirationCheck
    decorators:
    - name: DefaultDecorator
    endorsers:
      escc:
        name: DefaultEndorsement
    validators:
      vscc:
        name: DefaultValidation
  validatorPoolSize:
  discovery:
    enabled: true
    authCacheEnabled: true
    authCacheMaxSize: 1000
    authCachePurgeRetentionRatio: 0.75
    orgMembersAllowedAccess: false
  limits:
    concurrency:
      endorserService: 100
      deliverService: 100

vm:
  endpoint: unix:///var/run/docker.sock
  docker:
    tls:
      enabled: false
      ca:
        file: docker/ca.crt
      cert:
        file: docker/tls.crt
      key:
        file: docker/tls.key
    attachStdout: true
    hostConfig:
      NetworkMode: host
      LogConfig:
        Type: json-file
        Config:
          max-size: "50m"
          max-file: "5"
      Memory: 2147483648

chaincode:
  builder: $(DOCKER_NS)/fabric-ccenv:$(PROJECT_VERSION)
  pull: false
  golang:
    runtime: $(DOCKER_NS)/fabric-baseos:$(PROJECT_VERSION)
    dynamicLink: false
  car:
    runtime: $(DOCKER_NS)/fabric-baseos:$(PROJECT_VERSION)
  java:
    runtime: $(DOCKER_NS)/fabric-javaenv:latest
  node:
    runtime: $(DOCKER_NS)/fabric-nodeenv:latest
  installTimeout: 300s
  startuptimeout: 300s
  executetimeout: 30s
  mode: net
  keepalive: 0
  system:
    _lifecycle: enable
    cscc:       enable
    lscc:       enable
    qscc:       enable
  logging:
    level:  info
    shim:   warning
    format: '%{color}%{time:2006-01-02 15:04:05.000 MST} [%{module}] %{shortfunc} -> %{level:.4s} %{id:03x}%{color:reset} %{message}'
  externalBuilders: {{ range .ExternalBuilders }}
    - path: {{ .Path }}
      name: {{ .Name }}
      propagateEnvironment: {{ range .PropagateEnvironment }}
         - {{ . }}
      {{- end }}
  {{- end }}

ledger:
  blockchain:
  state:
    stateDatabase: goleveldb
    couchDBConfig:
      couchDBAddress: 127.0.0.1:5984
      username:
      password:
      maxRetries: 3
      maxRetriesOnStartup: 10
      requestTimeout: 35s
      queryLimit: 10000
      maxBatchUpdateSize: 1000
      warmIndexesAfterNBlocks: 1
  history:
    enableHistoryDatabase: true

operations:
  listenAddress: 127.0.0.1:{{ .PeerPort Peer "Operations" }}
  tls:
    enabled: true
    cert:
      file: {{ .PeerLocalTLSDir Peer }}/server.crt
    key:
      file: {{ .PeerLocalTLSDir Peer }}/server.key
    clientAuthRequired: {{ .ClientAuthRequired }}
    clientRootCAs:
      files:
      - {{ .PeerLocalTLSDir Peer }}/ca.crt
metrics:
  provider: {{ .MetricsProvider }}
  statsd:
    network: udp
    address: {{ if .StatsdEndpoint }}{{ .StatsdEndpoint }}{{ else }}127.0.0.1:8125{{ end }}
    writeInterval: 5s
    prefix: {{ ReplaceAll (ToLower Peer.ID) "." "_" }}
`
<commit_msg>Remove stale car.runtime from core template<commit_after>/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package nwo

const DefaultCoreTemplate = `---
logging:
  format: '%{color}%{time:2006-01-02 15:04:05.000 MST} [%{module}] %{shortfunc} -> %{level:.4s} %{id:03x}%{color:reset} %{message}'

peer:
  id: {{ Peer.ID }}
  networkId: {{ .NetworkID }}
  address: 127.0.0.1:{{ .PeerPort Peer "Listen" }}
  addressAutoDetect: true
  listenAddress: 127.0.0.1:{{ .PeerPort Peer "Listen" }}
  chaincodeListenAddress: 0.0.0.0:{{ .PeerPort Peer "Chaincode" }}
  keepalive:
    minInterval: 60s
    client:
      interval: 60s
      timeout: 20s
    deliveryClient:
      interval: 60s
      timeout: 20s
  gossip:
    bootstrap: 127.0.0.1:{{ .PeerPort Peer "Listen" }}
    endpoint: 127.0.0.1:{{ .PeerPort Peer "Listen" }}
    externalEndpoint: 127.0.0.1:{{ .PeerPort Peer "Listen" }}
    useLeaderElection: false
    orgLeader: true
    membershipTrackerInterval: 5s
    maxBlockCountToStore: 10
    maxPropagationBurstLatency: 10ms
    maxPropagationBurstSize: 10
    propagateIterations: 1
    propagatePeerNum: 3
    pullInterval: 4s
    pullPeerNum: 3
    requestStateInfoInterval: 4s
    publishStateInfoInterval: 4s
    stateInfoRetentionInterval:
    publishCertPeriod: 10s
    dialTimeout: 3s
    connTimeout: 2s
    recvBuffSize: 20
    sendBuffSize: 200
    digestWaitTime: 1s
    requestWaitTime: 1500ms
    responseWaitTime: 2s
    aliveTimeInterval: 5s
    aliveExpirationTimeout: 25s
    reconnectInterval: 25s
    election:
      startupGracePeriod: 15s
      membershipSampleInterval: 1s
      leaderAliveThreshold: 10s
      leaderElectionDuration: 5s
    pvtData:
      pullRetryThreshold: 7s
      transientstoreMaxBlockRetention: 1000
      pushAckTimeout: 3s
      btlPullMargin: 10
      reconcileBatchSize: 10
      reconcileSleepInterval: 10s
      reconciliationEnabled: true
      skipPullingInvalidTransactionsDuringCommit: false
      implicitCollectionDisseminationPolicy:
        requiredPeerCount: 0
        maxPeerCount: 1
    state:
       enabled: false
       checkInterval: 10s
       responseTimeout: 3s
       batchSize: 10
       blockBufferSize: 20
       maxRetries: 3
  events:
    address: 127.0.0.1:{{ .PeerPort Peer "Events" }}
    buffersize: 100
    timeout: 10ms
    timewindow: 15m
    keepalive:
      minInterval: 60s
  tls:
    enabled:  true
    clientAuthRequired: {{ .ClientAuthRequired }}
    cert:
      file: {{ .PeerLocalTLSDir Peer }}/server.crt
    key:
      file: {{ .PeerLocalTLSDir Peer }}/server.key
    clientCert:
      file: {{ .PeerLocalTLSDir Peer }}/server.crt
    clientKey:
      file: {{ .PeerLocalTLSDir Peer }}/server.key
    rootcert:
      file: {{ .PeerLocalTLSDir Peer }}/ca.crt
    clientRootCAs:
      files:
      - {{ .PeerLocalTLSDir Peer }}/ca.crt
  authentication:
    timewindow: 15m
  fileSystemPath: filesystem
  BCCSP:
    Default: SW
    SW:
      Hash: SHA2
      Security: 256
      FileKeyStore:
        KeyStore:
  mspConfigPath: {{ .PeerLocalMSPDir Peer }}
  localMspId: {{ (.Organization Peer.Organization).MSPID }}
  deliveryclient:
    reconnectTotalTimeThreshold: 3600s
  localMspType: bccsp
  profile:
    enabled:     false
    listenAddress: 127.0.0.1:{{ .PeerPort Peer "ProfilePort" }}
  handlers:
    authFilters:
    - name: DefaultAuth
    - name: ExpirationCheck
    decorators:
    - name: DefaultDecorator
    endorsers:
      escc:
        name: DefaultEndorsement
    validators:
      vscc:
        name: DefaultValidation
  validatorPoolSize:
  discovery:
    enabled: true
    authCacheEnabled: true
    authCacheMaxSize: 1000
    authCachePurgeRetentionRatio: 0.75
    orgMembersAllowedAccess: false
  limits:
    concurrency:
      endorserService: 100
      deliverService: 100

vm:
  endpoint: unix:///var/run/docker.sock
  docker:
    tls:
      enabled: false
      ca:
        file: docker/ca.crt
      cert:
        file: docker/tls.crt
      key:
        file: docker/tls.key
    attachStdout: true
    hostConfig:
      NetworkMode: host
      LogConfig:
        Type: json-file
        Config:
          max-size: "50m"
          max-file: "5"
      Memory: 2147483648

chaincode:
  builder: $(DOCKER_NS)/fabric-ccenv:$(PROJECT_VERSION)
  pull: false
  golang:
    runtime: $(DOCKER_NS)/fabric-baseos:$(PROJECT_VERSION)
    dynamicLink: false
  java:
    runtime: $(DOCKER_NS)/fabric-javaenv:latest
  node:
    runtime: $(DOCKER_NS)/fabric-nodeenv:latest
  installTimeout: 300s
  startuptimeout: 300s
  executetimeout: 30s
  mode: net
  keepalive: 0
  system:
    _lifecycle: enable
    cscc:       enable
    lscc:       enable
    qscc:       enable
  logging:
    level:  info
    shim:   warning
    format: '%{color}%{time:2006-01-02 15:04:05.000 MST} [%{module}] %{shortfunc} -> %{level:.4s} %{id:03x}%{color:reset} %{message}'
  externalBuilders: {{ range .ExternalBuilders }}
    - path: {{ .Path }}
      name: {{ .Name }}
      propagateEnvironment: {{ range .PropagateEnvironment }}
         - {{ . }}
      {{- end }}
  {{- end }}

ledger:
  blockchain:
  state:
    stateDatabase: goleveldb
    couchDBConfig:
      couchDBAddress: 127.0.0.1:5984
      username:
      password:
      maxRetries: 3
      maxRetriesOnStartup: 10
      requestTimeout: 35s
      queryLimit: 10000
      maxBatchUpdateSize: 1000
      warmIndexesAfterNBlocks: 1
  history:
    enableHistoryDatabase: true

operations:
  listenAddress: 127.0.0.1:{{ .PeerPort Peer "Operations" }}
  tls:
    enabled: true
    cert:
      file: {{ .PeerLocalTLSDir Peer }}/server.crt
    key:
      file: {{ .PeerLocalTLSDir Peer }}/server.key
    clientAuthRequired: {{ .ClientAuthRequired }}
    clientRootCAs:
      files:
      - {{ .PeerLocalTLSDir Peer }}/ca.crt
metrics:
  provider: {{ .MetricsProvider }}
  statsd:
    network: udp
    address: {{ if .StatsdEndpoint }}{{ .StatsdEndpoint }}{{ else }}127.0.0.1:8125{{ end }}
    writeInterval: 5s
    prefix: {{ ReplaceAll (ToLower Peer.ID) "." "_" }}
`
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"

	"cloud.google.com/go/pubsub"
	"code.cloudfoundry.org/clock"
	"code.cloudfoundry.org/lager"
	flags "github.com/jessevdk/go-flags"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/grouper"
	"github.com/tedsuo/ifrit/http_server"
	"github.com/tedsuo/ifrit/sigmon"
	"golang.org/x/net/context"

	"cred-alert/config"
	"cred-alert/crypto"
	"cred-alert/ingestor"
	"cred-alert/metrics"
	"cred-alert/queue"
	"cred-alert/revok"
)

func main() {
	var cfg *config.IngestorConfig
	var flagOpts config.IngestorOpts

	logger := lager.NewLogger("revok-ingestor")
	logger.RegisterSink(lager.NewWriterSink(os.Stdout, lager.INFO))

	logger.Debug("starting")

	_, err := flags.Parse(&flagOpts)
	if err != nil {
		os.Exit(1)
	}

	bs, err := ioutil.ReadFile(string(flagOpts.ConfigFile))
	if err != nil {
		logger.Error("failed-opening-config-file", err)
		os.Exit(1)
	}

	cfg, err = config.LoadIngestorConfig(bs)

	errs := cfg.Validate()
	if errs != nil {
		for _, err := range errs {
			fmt.Println(err.Error())
		}
		os.Exit(1)
	}

	if cfg.IsSentryConfigured() {
		logger.RegisterSink(revok.NewSentrySink(cfg.Metrics.SentryDSN, cfg.Metrics.Environment))
	}

	emitter := metrics.BuildEmitter(cfg.Metrics.DatadogAPIKey, cfg.Metrics.Environment)

	pubSubClient, err := pubsub.NewClient(context.Background(), cfg.PubSub.ProjectName)
	if err != nil {
		logger.Fatal("failed", err)
		os.Exit(1)
	}
	topic := pubSubClient.Topic(cfg.PubSub.Topic)
	defer topic.Stop()

	privateKey, err := crypto.ReadRSAPrivateKey(string(cfg.PubSub.PrivateKeyPath))
	if err != nil {
		logger.Fatal("failed", err)
		os.Exit(1)
	}
	signer := crypto.NewRSASigner(privateKey)
	enqueuer := queue.NewPubSubEnqueuer(logger, topic, signer)
	in := ingestor.NewIngestor(enqueuer, emitter)

	clk := clock.NewClock()

	router := http.NewServeMux()
	router.Handle("/webhook", ingestor.NewHandler(logger, in, clk, emitter, cfg.GitHub.WebhookSecretTokens))
	router.Handle("/healthcheck", revok.NewObliviousHealthCheck())

	certificate, err := config.LoadCertificate(
		cfg.Identity.CertificatePath,
		cfg.Identity.PrivateKeyPath,
		cfg.Identity.PrivateKeyPassphrase,
	)
	if err != nil {
		log.Fatalln(err)
	}

	caCertPool, err := config.LoadCertificatePool(cfg.Identity.CACertificatePath)
	if err != nil {
		log.Fatalln(err)
	}

	tlsConfig := &tls.Config{
		Certificates: []tls.Certificate{certificate},
		RootCAs:      caCertPool,
	}

	apiServer := http_server.NewTLSServer(fmt.Sprintf(":%d", cfg.Port), router, tlsConfig)

	members := []grouper.Member{
		{"api", apiServer},
	}

	runner := sigmon.New(grouper.NewParallel(os.Interrupt, members))

	serverLogger := logger.Session("server", lager.Data{
		"port": cfg.Port,
	})
	serverLogger.Info("starting")
	err = <-ifrit.Invoke(runner).Wait()
	if err != nil {
		serverLogger.Error("failed", err)
	}
}
<commit_msg>Handle err on failure loading ingestor config<commit_after>package main

import (
	"crypto/tls"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"

	"cloud.google.com/go/pubsub"
	"code.cloudfoundry.org/clock"
	"code.cloudfoundry.org/lager"
	flags "github.com/jessevdk/go-flags"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/grouper"
	"github.com/tedsuo/ifrit/http_server"
	"github.com/tedsuo/ifrit/sigmon"
	"golang.org/x/net/context"

	"cred-alert/config"
	"cred-alert/crypto"
	"cred-alert/ingestor"
	"cred-alert/metrics"
	"cred-alert/queue"
	"cred-alert/revok"
)

func main() {
	var cfg *config.IngestorConfig
	var flagOpts config.IngestorOpts

	logger := lager.NewLogger("revok-ingestor")
	logger.RegisterSink(lager.NewWriterSink(os.Stdout, lager.INFO))

	logger.Debug("starting")

	_, err := flags.Parse(&flagOpts)
	if err != nil {
		os.Exit(1)
	}

	bs, err := ioutil.ReadFile(string(flagOpts.ConfigFile))
	if err != nil {
		logger.Error("failed-opening-config-file", err)
		os.Exit(1)
	}

	cfg, err = config.LoadIngestorConfig(bs)
	if err != nil {
		logger.Error("failed-loading-config", err)
		os.Exit(1)
	}

	errs := cfg.Validate()
	if errs != nil {
		for _, err := range errs {
			fmt.Println(err.Error())
		}
		os.Exit(1)
	}

	if cfg.IsSentryConfigured() {
		logger.RegisterSink(revok.NewSentrySink(cfg.Metrics.SentryDSN, cfg.Metrics.Environment))
	}

	emitter := metrics.BuildEmitter(cfg.Metrics.DatadogAPIKey, cfg.Metrics.Environment)

	pubSubClient, err := pubsub.NewClient(context.Background(), cfg.PubSub.ProjectName)
	if err != nil {
		logger.Fatal("failed", err)
		os.Exit(1)
	}
	topic := pubSubClient.Topic(cfg.PubSub.Topic)
	defer topic.Stop()

	privateKey, err := crypto.ReadRSAPrivateKey(string(cfg.PubSub.PrivateKeyPath))
	if err != nil {
		logger.Fatal("failed", err)
		os.Exit(1)
	}
	signer := crypto.NewRSASigner(privateKey)
	enqueuer := queue.NewPubSubEnqueuer(logger, topic, signer)
	in := ingestor.NewIngestor(enqueuer, emitter)

	clk := clock.NewClock()

	router := http.NewServeMux()
	router.Handle("/webhook", ingestor.NewHandler(logger, in, clk, emitter, cfg.GitHub.WebhookSecretTokens))
	router.Handle("/healthcheck", revok.NewObliviousHealthCheck())

	certificate, err := config.LoadCertificate(
		cfg.Identity.CertificatePath,
		cfg.Identity.PrivateKeyPath,
		cfg.Identity.PrivateKeyPassphrase,
	)
	if err != nil {
		log.Fatalln(err)
	}

	caCertPool, err := config.LoadCertificatePool(cfg.Identity.CACertificatePath)
	if err != nil {
		log.Fatalln(err)
	}

	tlsConfig := &tls.Config{
		Certificates: []tls.Certificate{certificate},
		RootCAs:      caCertPool,
	}

	apiServer := http_server.NewTLSServer(fmt.Sprintf(":%d", cfg.Port), router, tlsConfig)

	members := []grouper.Member{
		{"api", apiServer},
	}

	runner := sigmon.New(grouper.NewParallel(os.Interrupt, members))

	serverLogger := logger.Session("server", lager.Data{
		"port": cfg.Port,
	})
	serverLogger.Info("starting")
	err = <-ifrit.Invoke(runner).Wait()
	if err != nil {
		serverLogger.Error("failed", err)
	}
}
<|endoftext|>


<commit_before>package cli

import (
	"os"
	"os/exec"

	"gopkg.in/alecthomas/kingpin.v2"
"fmt"
)

type AutomountConfig struct {
	BaseConfig

	MountRoot       string
	PathToAdbfs     string
	AllowAnyAdbfs   bool
	OnMountHandlers []string
	OnUnmountHandlers []string
}

const (
	MountRootFlag      = "root"
	PathToAdbfsFlag    = "adbfs"
	AllowAnyAdbfsFlag  = "disable-adbfs-verify"
	OnMountHandlerFlag = "on-mount"
	OnUnmountHandlerFlag = "on-unmount"
)

func RegisterAutomountFlags(config *AutomountConfig) {
	registerBaseFlags(&config.BaseConfig)

	kingpin.Flag(MountRootFlag,
		"Directory in which to mount devices.").Short('r').PlaceHolder("/mnt").ExistingDirVar(&config.MountRoot)
	kingpin.Flag("adbfs",
		"Path to adbfs executable. If not specified, PATH is searched.").PlaceHolder("/usr/bin/adbfs").ExistingFileVar(&config.PathToAdbfs)
	kingpin.Flag(AllowAnyAdbfsFlag,
		"If true, the build SHA of adbfs won't be required to match that of this executable.").Hidden().BoolVar(&config.AllowAnyAdbfs)
	kingpin.Flag(OnMountHandlerFlag,
		`Command(s) to run after a device is mounted. May be repeated.
The following environment variables will be defined:
`+describeHandlerVars()).PlaceHolder(fmt.Sprintf(`"open $%s"`, PathHandlerVar)).StringsVar(&config.OnMountHandlers)
	kingpin.Flag(OnUnmountHandlerFlag,
		`Command(s) to run after a device has been unmounted. May be repeated.
The following environment variables will be defined:
`+describeHandlerVars()).PlaceHolder(fmt.Sprintf(`"say unmounted $%s"`, ModelHandlerVar)).StringsVar(&config.OnUnmountHandlers)
}

func (c *AutomountConfig) InitializePaths() {
	c.initializeMountRoot()
	c.initializeAdbfs()
}

func (c *AutomountConfig) initializeMountRoot() {
	if c.MountRoot == "" {
		Log.Debug("no mount root specified, falling back to default…")
		c.MountRoot = FindDefaultMountRoot()
	}

	if c.MountRoot == "" {
		Log.Fatalln("no mount root specified.")
	}

	info, err := os.Stat(c.MountRoot)
	if err != nil {
		Log.Fatalf("could not read mount root %s: %s", c.MountRoot, err)
	}
	if !info.IsDir() {
		Log.Fatalln(c.MountRoot, "is not a directory")
	}
}

func (c *AutomountConfig) initializeAdbfs() {
	if c.PathToAdbfs == "" {
		var err error
		c.PathToAdbfs, err = exec.LookPath("adbfs")
		if err != nil {
			Log.Fatalln("couldn't find adbfs executable in PATH:", err)
		}
	}

	var expectedVersion string
	if c.AllowAnyAdbfs {
		expectedVersion = ""
	} else {
		expectedVersion = BuildSHA()
	}

	err := CheckExecutableVersionMatches(c.PathToAdbfs, "adbfs", expectedVersion)
	if err != nil {
		Log.Fatal(err)
	}
}
<commit_msg>Fix formatting.<commit_after>package cli

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

	"gopkg.in/alecthomas/kingpin.v2"
)

type AutomountConfig struct {
	BaseConfig

	MountRoot         string
	PathToAdbfs       string
	AllowAnyAdbfs     bool
	OnMountHandlers   []string
	OnUnmountHandlers []string
}

const (
	MountRootFlag        = "root"
	PathToAdbfsFlag      = "adbfs"
	AllowAnyAdbfsFlag    = "disable-adbfs-verify"
	OnMountHandlerFlag   = "on-mount"
	OnUnmountHandlerFlag = "on-unmount"
)

func RegisterAutomountFlags(config *AutomountConfig) {
	registerBaseFlags(&config.BaseConfig)

	kingpin.Flag(MountRootFlag,
		"Directory in which to mount devices.").Short('r').PlaceHolder("/mnt").ExistingDirVar(&config.MountRoot)
	kingpin.Flag("adbfs",
		"Path to adbfs executable. If not specified, PATH is searched.").PlaceHolder("/usr/bin/adbfs").ExistingFileVar(&config.PathToAdbfs)
	kingpin.Flag(AllowAnyAdbfsFlag,
		"If true, the build SHA of adbfs won't be required to match that of this executable.").Hidden().BoolVar(&config.AllowAnyAdbfs)
	kingpin.Flag(OnMountHandlerFlag,
		`Command(s) to run after a device is mounted. May be repeated.
The following environment variables will be defined:
`+describeHandlerVars()).PlaceHolder(fmt.Sprintf(`"open $%s"`, PathHandlerVar)).StringsVar(&config.OnMountHandlers)
	kingpin.Flag(OnUnmountHandlerFlag,
		`Command(s) to run after a device has been unmounted. May be repeated.
The following environment variables will be defined:
`+describeHandlerVars()).PlaceHolder(fmt.Sprintf(`"say unmounted $%s"`, ModelHandlerVar)).StringsVar(&config.OnUnmountHandlers)
}

func (c *AutomountConfig) InitializePaths() {
	c.initializeMountRoot()
	c.initializeAdbfs()
}

func (c *AutomountConfig) initializeMountRoot() {
	if c.MountRoot == "" {
		Log.Debug("no mount root specified, falling back to default…")
		c.MountRoot = FindDefaultMountRoot()
	}

	if c.MountRoot == "" {
		Log.Fatalln("no mount root specified.")
	}

	info, err := os.Stat(c.MountRoot)
	if err != nil {
		Log.Fatalf("could not read mount root %s: %s", c.MountRoot, err)
	}
	if !info.IsDir() {
		Log.Fatalln(c.MountRoot, "is not a directory")
	}
}

func (c *AutomountConfig) initializeAdbfs() {
	if c.PathToAdbfs == "" {
		var err error
		c.PathToAdbfs, err = exec.LookPath("adbfs")
		if err != nil {
			Log.Fatalln("couldn't find adbfs executable in PATH:", err)
		}
	}

	var expectedVersion string
	if c.AllowAnyAdbfs {
		expectedVersion = ""
	} else {
		expectedVersion = BuildSHA()
	}

	err := CheckExecutableVersionMatches(c.PathToAdbfs, "adbfs", expectedVersion)
	if err != nil {
		Log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2020 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 source

import (
	"context"
	"go/ast"
	"go/token"
	"go/types"
	"path/filepath"
	"regexp"
	"strings"

	"golang.org/x/tools/internal/lsp/protocol"
	"golang.org/x/tools/internal/span"
)

type LensFunc func(context.Context, Snapshot, FileHandle) ([]protocol.CodeLens, error)

// LensFuncs returns the supported lensFuncs for Go files.
func LensFuncs() map[string]LensFunc {
	return map[string]LensFunc{
		CommandGenerate.Name:      goGenerateCodeLens,
		CommandTest.Name:          runTestCodeLens,
		CommandRegenerateCgo.Name: regenerateCgoLens,
		CommandToggleDetails.Name: toggleDetailsCodeLens,
	}
}

var (
	testRe      = regexp.MustCompile("^Test[^a-z]")
	benchmarkRe = regexp.MustCompile("^Benchmark[^a-z]")
)

func runTestCodeLens(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]protocol.CodeLens, error) {
	codeLens := make([]protocol.CodeLens, 0)

	fns, err := TestsAndBenchmarks(ctx, snapshot, fh)
	if err != nil {
		return nil, err
	}
	for _, fn := range fns.Tests {
		jsonArgs, err := MarshalArgs(fh.URI(), []string{fn.Name}, nil)
		if err != nil {
			return nil, err
		}
		codeLens = append(codeLens, protocol.CodeLens{
			Range: protocol.Range{Start: fn.Rng.Start, End: fn.Rng.Start},
			Command: protocol.Command{
				Title:     "run test",
				Command:   CommandTest.ID(),
				Arguments: jsonArgs,
			},
		})
	}

	for _, fn := range fns.Benchmarks {
		jsonArgs, err := MarshalArgs(fh.URI(), nil, []string{fn.Name})
		if err != nil {
			return nil, err
		}
		codeLens = append(codeLens, protocol.CodeLens{
			Range: protocol.Range{Start: fn.Rng.Start, End: fn.Rng.Start},
			Command: protocol.Command{
				Title:     "run benchmark",
				Command:   CommandTest.ID(),
				Arguments: jsonArgs,
			},
		})
	}

	_, pgf, err := GetParsedFile(ctx, snapshot, fh, WidestPackage)
	if err != nil {
		return nil, err
	}
	// add a code lens to the top of the file which runs all benchmarks in the file
	rng, err := NewMappedRange(snapshot.FileSet(), pgf.Mapper, pgf.File.Package, pgf.File.Package).Range()
	if err != nil {
		return nil, err
	}
	args, err := MarshalArgs(fh.URI(), []string{}, fns.Benchmarks)
	if err != nil {
		return nil, err
	}
	codeLens = append(codeLens, protocol.CodeLens{
		Range: rng,
		Command: protocol.Command{
			Title:     "run file benchmarks",
			Command:   CommandTest.ID(),
			Arguments: args,
		},
	})
	return codeLens, nil
}

type testFn struct {
	Name string
	Rng  protocol.Range
}

type testFns struct {
	Tests      []testFn
	Benchmarks []testFn
}

func TestsAndBenchmarks(ctx context.Context, snapshot Snapshot, fh FileHandle) (testFns, error) {
	var out testFns

	if !strings.HasSuffix(fh.URI().Filename(), "_test.go") {
		return out, nil
	}
	pkg, pgf, err := GetParsedFile(ctx, snapshot, fh, WidestPackage)
	if err != nil {
		return out, err
	}

	for _, d := range pgf.File.Decls {
		fn, ok := d.(*ast.FuncDecl)
		if !ok {
			continue
		}

		rng, err := NewMappedRange(snapshot.FileSet(), pgf.Mapper, d.Pos(), fn.End()).Range()
		if err != nil {
			return out, err
		}

		if matchTestFunc(fn, pkg, testRe, "T") {
			out.Tests = append(out.Tests, testFn{fn.Name.Name, rng})
		}

		if matchTestFunc(fn, pkg, benchmarkRe, "B") {
			out.Benchmarks = append(out.Benchmarks, testFn{fn.Name.Name, rng})
		}
	}

	return out, nil
}

func matchTestFunc(fn *ast.FuncDecl, pkg Package, nameRe *regexp.Regexp, paramID string) bool {
	// Make sure that the function name matches a test function.
	if !nameRe.MatchString(fn.Name.Name) {
		return false
	}
	info := pkg.GetTypesInfo()
	if info == nil {
		return false
	}
	obj := info.ObjectOf(fn.Name)
	if obj == nil {
		return false
	}
	sig, ok := obj.Type().(*types.Signature)
	if !ok {
		return false
	}
	// Test functions should have only one parameter.
	if sig.Params().Len() != 1 {
		return false
	}

	// Check the type of the only parameter
	paramTyp, ok := sig.Params().At(0).Type().(*types.Pointer)
	if !ok {
		return false
	}
	named, ok := paramTyp.Elem().(*types.Named)
	if !ok {
		return false
	}
	namedObj := named.Obj()
	if namedObj.Pkg().Path() != "testing" {
		return false
	}
	return namedObj.Id() == paramID
}

func goGenerateCodeLens(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]protocol.CodeLens, error) {
	pgf, err := snapshot.ParseGo(ctx, fh, ParseFull)
	if err != nil {
		return nil, err
	}
	const ggDirective = "//go:generate"
	for _, c := range pgf.File.Comments {
		for _, l := range c.List {
			if !strings.HasPrefix(l.Text, ggDirective) {
				continue
			}
			rng, err := NewMappedRange(snapshot.FileSet(), pgf.Mapper, l.Pos(), l.Pos()+token.Pos(len(ggDirective))).Range()
			if err != nil {
				return nil, err
			}
			dir := span.URIFromPath(filepath.Dir(fh.URI().Filename()))
			nonRecursiveArgs, err := MarshalArgs(dir, false)
			if err != nil {
				return nil, err
			}
			recursiveArgs, err := MarshalArgs(dir, true)
			if err != nil {
				return nil, err
			}
			return []protocol.CodeLens{
				{
					Range: rng,
					Command: protocol.Command{
						Title:     "run go generate",
						Command:   CommandGenerate.ID(),
						Arguments: nonRecursiveArgs,
					},
				},
				{
					Range: rng,
					Command: protocol.Command{
						Title:     "run go generate ./...",
						Command:   CommandGenerate.ID(),
						Arguments: recursiveArgs,
					},
				},
			}, nil

		}
	}
	return nil, nil
}

func regenerateCgoLens(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]protocol.CodeLens, error) {
	pgf, err := snapshot.ParseGo(ctx, fh, ParseFull)
	if err != nil {
		return nil, err
	}
	var c *ast.ImportSpec
	for _, imp := range pgf.File.Imports {
		if imp.Path.Value == `"C"` {
			c = imp
		}
	}
	if c == nil {
		return nil, nil
	}
	rng, err := NewMappedRange(snapshot.FileSet(), pgf.Mapper, c.Pos(), c.EndPos).Range()
	if err != nil {
		return nil, err
	}
	jsonArgs, err := MarshalArgs(fh.URI())
	if err != nil {
		return nil, err
	}
	return []protocol.CodeLens{
		{
			Range: rng,
			Command: protocol.Command{
				Title:     "regenerate cgo definitions",
				Command:   CommandRegenerateCgo.ID(),
				Arguments: jsonArgs,
			},
		},
	}, nil
}

func toggleDetailsCodeLens(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]protocol.CodeLens, error) {
	_, pgf, err := GetParsedFile(ctx, snapshot, fh, WidestPackage)
	if err != nil {
		return nil, err
	}
	rng, err := NewMappedRange(snapshot.FileSet(), pgf.Mapper, pgf.File.Package, pgf.File.Package).Range()
	if err != nil {
		return nil, err
	}
	jsonArgs, err := MarshalArgs(fh.URI())
	if err != nil {
		return nil, err
	}
	return []protocol.CodeLens{{
		Range: rng,
		Command: protocol.Command{
			Title:     "Toggle gc annotation details",
			Command:   CommandToggleDetails.ID(),
			Arguments: jsonArgs,
		},
	}}, nil
}
<commit_msg>internal/lsp/source: only show "run file benchmarks" if available<commit_after>// Copyright 2020 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 source

import (
	"context"
	"go/ast"
	"go/token"
	"go/types"
	"path/filepath"
	"regexp"
	"strings"

	"golang.org/x/tools/internal/lsp/protocol"
	"golang.org/x/tools/internal/span"
)

type LensFunc func(context.Context, Snapshot, FileHandle) ([]protocol.CodeLens, error)

// LensFuncs returns the supported lensFuncs for Go files.
func LensFuncs() map[string]LensFunc {
	return map[string]LensFunc{
		CommandGenerate.Name:      goGenerateCodeLens,
		CommandTest.Name:          runTestCodeLens,
		CommandRegenerateCgo.Name: regenerateCgoLens,
		CommandToggleDetails.Name: toggleDetailsCodeLens,
	}
}

var (
	testRe      = regexp.MustCompile("^Test[^a-z]")
	benchmarkRe = regexp.MustCompile("^Benchmark[^a-z]")
)

func runTestCodeLens(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]protocol.CodeLens, error) {
	codeLens := make([]protocol.CodeLens, 0)

	fns, err := TestsAndBenchmarks(ctx, snapshot, fh)
	if err != nil {
		return nil, err
	}
	for _, fn := range fns.Tests {
		jsonArgs, err := MarshalArgs(fh.URI(), []string{fn.Name}, nil)
		if err != nil {
			return nil, err
		}
		codeLens = append(codeLens, protocol.CodeLens{
			Range: protocol.Range{Start: fn.Rng.Start, End: fn.Rng.Start},
			Command: protocol.Command{
				Title:     "run test",
				Command:   CommandTest.ID(),
				Arguments: jsonArgs,
			},
		})
	}

	for _, fn := range fns.Benchmarks {
		jsonArgs, err := MarshalArgs(fh.URI(), nil, []string{fn.Name})
		if err != nil {
			return nil, err
		}
		codeLens = append(codeLens, protocol.CodeLens{
			Range: protocol.Range{Start: fn.Rng.Start, End: fn.Rng.Start},
			Command: protocol.Command{
				Title:     "run benchmark",
				Command:   CommandTest.ID(),
				Arguments: jsonArgs,
			},
		})
	}

	if len(fns.Benchmarks) > 0 {
		_, pgf, err := GetParsedFile(ctx, snapshot, fh, WidestPackage)
		if err != nil {
			return nil, err
		}
		// add a code lens to the top of the file which runs all benchmarks in the file
		rng, err := NewMappedRange(snapshot.FileSet(), pgf.Mapper, pgf.File.Package, pgf.File.Package).Range()
		if err != nil {
			return nil, err
		}
		args, err := MarshalArgs(fh.URI(), []string{}, fns.Benchmarks)
		if err != nil {
			return nil, err
		}
		codeLens = append(codeLens, protocol.CodeLens{
			Range: rng,
			Command: protocol.Command{
				Title:     "run file benchmarks",
				Command:   CommandTest.ID(),
				Arguments: args,
			},
		})
	}
	return codeLens, nil
}

type testFn struct {
	Name string
	Rng  protocol.Range
}

type testFns struct {
	Tests      []testFn
	Benchmarks []testFn
}

func TestsAndBenchmarks(ctx context.Context, snapshot Snapshot, fh FileHandle) (testFns, error) {
	var out testFns

	if !strings.HasSuffix(fh.URI().Filename(), "_test.go") {
		return out, nil
	}
	pkg, pgf, err := GetParsedFile(ctx, snapshot, fh, WidestPackage)
	if err != nil {
		return out, err
	}

	for _, d := range pgf.File.Decls {
		fn, ok := d.(*ast.FuncDecl)
		if !ok {
			continue
		}

		rng, err := NewMappedRange(snapshot.FileSet(), pgf.Mapper, d.Pos(), fn.End()).Range()
		if err != nil {
			return out, err
		}

		if matchTestFunc(fn, pkg, testRe, "T") {
			out.Tests = append(out.Tests, testFn{fn.Name.Name, rng})
		}

		if matchTestFunc(fn, pkg, benchmarkRe, "B") {
			out.Benchmarks = append(out.Benchmarks, testFn{fn.Name.Name, rng})
		}
	}

	return out, nil
}

func matchTestFunc(fn *ast.FuncDecl, pkg Package, nameRe *regexp.Regexp, paramID string) bool {
	// Make sure that the function name matches a test function.
	if !nameRe.MatchString(fn.Name.Name) {
		return false
	}
	info := pkg.GetTypesInfo()
	if info == nil {
		return false
	}
	obj := info.ObjectOf(fn.Name)
	if obj == nil {
		return false
	}
	sig, ok := obj.Type().(*types.Signature)
	if !ok {
		return false
	}
	// Test functions should have only one parameter.
	if sig.Params().Len() != 1 {
		return false
	}

	// Check the type of the only parameter
	paramTyp, ok := sig.Params().At(0).Type().(*types.Pointer)
	if !ok {
		return false
	}
	named, ok := paramTyp.Elem().(*types.Named)
	if !ok {
		return false
	}
	namedObj := named.Obj()
	if namedObj.Pkg().Path() != "testing" {
		return false
	}
	return namedObj.Id() == paramID
}

func goGenerateCodeLens(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]protocol.CodeLens, error) {
	pgf, err := snapshot.ParseGo(ctx, fh, ParseFull)
	if err != nil {
		return nil, err
	}
	const ggDirective = "//go:generate"
	for _, c := range pgf.File.Comments {
		for _, l := range c.List {
			if !strings.HasPrefix(l.Text, ggDirective) {
				continue
			}
			rng, err := NewMappedRange(snapshot.FileSet(), pgf.Mapper, l.Pos(), l.Pos()+token.Pos(len(ggDirective))).Range()
			if err != nil {
				return nil, err
			}
			dir := span.URIFromPath(filepath.Dir(fh.URI().Filename()))
			nonRecursiveArgs, err := MarshalArgs(dir, false)
			if err != nil {
				return nil, err
			}
			recursiveArgs, err := MarshalArgs(dir, true)
			if err != nil {
				return nil, err
			}
			return []protocol.CodeLens{
				{
					Range: rng,
					Command: protocol.Command{
						Title:     "run go generate",
						Command:   CommandGenerate.ID(),
						Arguments: nonRecursiveArgs,
					},
				},
				{
					Range: rng,
					Command: protocol.Command{
						Title:     "run go generate ./...",
						Command:   CommandGenerate.ID(),
						Arguments: recursiveArgs,
					},
				},
			}, nil

		}
	}
	return nil, nil
}

func regenerateCgoLens(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]protocol.CodeLens, error) {
	pgf, err := snapshot.ParseGo(ctx, fh, ParseFull)
	if err != nil {
		return nil, err
	}
	var c *ast.ImportSpec
	for _, imp := range pgf.File.Imports {
		if imp.Path.Value == `"C"` {
			c = imp
		}
	}
	if c == nil {
		return nil, nil
	}
	rng, err := NewMappedRange(snapshot.FileSet(), pgf.Mapper, c.Pos(), c.EndPos).Range()
	if err != nil {
		return nil, err
	}
	jsonArgs, err := MarshalArgs(fh.URI())
	if err != nil {
		return nil, err
	}
	return []protocol.CodeLens{
		{
			Range: rng,
			Command: protocol.Command{
				Title:     "regenerate cgo definitions",
				Command:   CommandRegenerateCgo.ID(),
				Arguments: jsonArgs,
			},
		},
	}, nil
}

func toggleDetailsCodeLens(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]protocol.CodeLens, error) {
	_, pgf, err := GetParsedFile(ctx, snapshot, fh, WidestPackage)
	if err != nil {
		return nil, err
	}
	rng, err := NewMappedRange(snapshot.FileSet(), pgf.Mapper, pgf.File.Package, pgf.File.Package).Range()
	if err != nil {
		return nil, err
	}
	jsonArgs, err := MarshalArgs(fh.URI())
	if err != nil {
		return nil, err
	}
	return []protocol.CodeLens{{
		Range: rng,
		Command: protocol.Command{
			Title:     "Toggle gc annotation details",
			Command:   CommandToggleDetails.ID(),
			Arguments: jsonArgs,
		},
	}}, nil
}
<|endoftext|>


<commit_before>package docker

import (
	"strings"

	"github.com/apex/log"
	"github.com/goreleaser/goreleaser/internal/artifact"
	"github.com/goreleaser/goreleaser/internal/pipe"
	"github.com/goreleaser/goreleaser/internal/semerrgroup"
	"github.com/goreleaser/goreleaser/internal/tmpl"
	"github.com/goreleaser/goreleaser/pkg/config"
	"github.com/goreleaser/goreleaser/pkg/context"
)

// ManifestPipe is beta implementation of for the docker manifest feature,
// allowing to publish multi-arch docker images.
type ManifestPipe struct{}

func (ManifestPipe) String() string {
	return "docker manifests"
}

// Publish the docker manifests.
func (ManifestPipe) Publish(ctx *context.Context) error {
	if ctx.SkipPublish {
		return pipe.ErrSkipPublishEnabled
	}
	g := semerrgroup.NewSkipAware(semerrgroup.New(1))
	for _, manifest := range ctx.Config.DockerManifests {
		manifest := manifest
		g.Go(func() error {
			if strings.TrimSpace(manifest.SkipPush) == "true" {
				return pipe.Skip("docker_manifest.skip_push is set")
			}

			if strings.TrimSpace(manifest.SkipPush) == "auto" && ctx.Semver.Prerelease != "" {
				return pipe.Skip("prerelease detected with 'auto' push, skipping docker manifest")
			}

			name, err := manifestName(ctx, manifest)
			if err != nil {
				return err
			}

			images, err := manifestImages(ctx, manifest)
			if err != nil {
				return err
			}

			manifester := newManifester(manifest)

			log.WithField("manifest", manifest).WithField("images", images).Info("creating docker manifest")
			if err := manifester.Create(ctx, name, images, manifest.CreateFlags); err != nil {
				return err
			}
			ctx.Artifacts.Add(&artifact.Artifact{
				Type: artifact.DockerManifest,
				Name: name,
				Path: name,
			})

			log.WithField("manifest", manifest).Info("pushing docker manifest")
			return manifester.Push(ctx, name, manifest.PushFlags)
		})
	}
	return g.Wait()
}

func manifestName(ctx *context.Context, manifest config.DockerManifest) (string, error) {
	name, err := tmpl.New(ctx).Apply(manifest.NameTemplate)
	if err != nil {
		return name, err
	}
	if strings.TrimSpace(name) == "" {
		return name, pipe.Skip("manifest name is empty")
	}
	return name, nil
}

func manifestImages(ctx *context.Context, manifest config.DockerManifest) ([]string, error) {
	imgs := make([]string, 0, len(manifest.ImageTemplates))
	for _, img := range manifest.ImageTemplates {
		str, err := tmpl.New(ctx).Apply(img)
		if err != nil {
			return []string{}, err
		}
		imgs = append(imgs, str)
	}
	if strings.TrimSpace(strings.Join(manifest.ImageTemplates, "")) == "" {
		return imgs, pipe.Skip("manifest has no images")
	}
	return imgs, nil
}
<commit_msg>fix(docker_manifest): improve logs<commit_after>package docker

import (
	"strings"

	"github.com/apex/log"
	"github.com/goreleaser/goreleaser/internal/artifact"
	"github.com/goreleaser/goreleaser/internal/pipe"
	"github.com/goreleaser/goreleaser/internal/semerrgroup"
	"github.com/goreleaser/goreleaser/internal/tmpl"
	"github.com/goreleaser/goreleaser/pkg/config"
	"github.com/goreleaser/goreleaser/pkg/context"
)

// ManifestPipe is beta implementation of for the docker manifest feature,
// allowing to publish multi-arch docker images.
type ManifestPipe struct{}

func (ManifestPipe) String() string {
	return "docker manifests"
}

// Publish the docker manifests.
func (ManifestPipe) Publish(ctx *context.Context) error {
	if ctx.SkipPublish {
		return pipe.ErrSkipPublishEnabled
	}
	g := semerrgroup.NewSkipAware(semerrgroup.New(1))
	for _, manifest := range ctx.Config.DockerManifests {
		manifest := manifest
		g.Go(func() error {
			if strings.TrimSpace(manifest.SkipPush) == "true" {
				return pipe.Skip("docker_manifest.skip_push is set")
			}

			if strings.TrimSpace(manifest.SkipPush) == "auto" && ctx.Semver.Prerelease != "" {
				return pipe.Skip("prerelease detected with 'auto' push, skipping docker manifest")
			}

			name, err := manifestName(ctx, manifest)
			if err != nil {
				return err
			}

			images, err := manifestImages(ctx, manifest)
			if err != nil {
				return err
			}

			manifester := newManifester(manifest)

			log.WithField("manifest", name).WithField("images", images).Info("creating docker manifest")
			if err := manifester.Create(ctx, name, images, manifest.CreateFlags); err != nil {
				return err
			}
			ctx.Artifacts.Add(&artifact.Artifact{
				Type: artifact.DockerManifest,
				Name: name,
				Path: name,
			})

			log.WithField("manifest", name).Info("pushing docker manifest")
			return manifester.Push(ctx, name, manifest.PushFlags)
		})
	}
	return g.Wait()
}

func manifestName(ctx *context.Context, manifest config.DockerManifest) (string, error) {
	name, err := tmpl.New(ctx).Apply(manifest.NameTemplate)
	if err != nil {
		return name, err
	}
	if strings.TrimSpace(name) == "" {
		return name, pipe.Skip("manifest name is empty")
	}
	return name, nil
}

func manifestImages(ctx *context.Context, manifest config.DockerManifest) ([]string, error) {
	imgs := make([]string, 0, len(manifest.ImageTemplates))
	for _, img := range manifest.ImageTemplates {
		str, err := tmpl.New(ctx).Apply(img)
		if err != nil {
			return []string{}, err
		}
		imgs = append(imgs, str)
	}
	if strings.TrimSpace(strings.Join(manifest.ImageTemplates, "")) == "" {
		return imgs, pipe.Skip("manifest has no images")
	}
	return imgs, nil
}
<|endoftext|>


<commit_before>package release

import (
	"os"

	"github.com/Masterminds/semver"
	"github.com/apex/log"
	"github.com/goreleaser/goreleaser/internal/artifact"
	"github.com/goreleaser/goreleaser/internal/client"
	"github.com/goreleaser/goreleaser/internal/pipe"
	"github.com/goreleaser/goreleaser/internal/semerrgroup"
	"github.com/goreleaser/goreleaser/pkg/context"
	"github.com/pkg/errors"
)

// Pipe for github release
type Pipe struct{}

func (Pipe) String() string {
	return "GitHub Releases"
}

// Default sets the pipe defaults
func (Pipe) Default(ctx *context.Context) error {
	if ctx.Config.Release.NameTemplate == "" {
		ctx.Config.Release.NameTemplate = "{{.Tag}}"
	}
	if ctx.Config.Release.GitHub.Name != "" {
		return nil
	}
	repo, err := remoteRepo()
	if err != nil && !ctx.Snapshot {
		return err
	}
	ctx.Config.Release.GitHub = repo

	ctx.PreRelease = false
	// Check if we have to check the git tag for an indicator to mark as pre release
	switch ctx.Config.Release.Prerelease {
	case "auto":
		sv, err := semver.NewVersion(ctx.Git.CurrentTag)
		if err != nil {
			return errors.Wrapf(err, "Failed to parse tag %s as semver", ctx.Git.CurrentTag)
		}

		if sv.Prerelease() != "" {
			ctx.PreRelease = true
		}
		log.Debugf("Pre-Release was detected for tag %s: %v", ctx.Git.CurrentTag, ctx.PreRelease)
	case "true":
		ctx.PreRelease = true
	case "false":
		ctx.PreRelease = false
	default:
		log.Warnf("Invalid value %s for prerelease. Should be auto, true or false")
	}

	return nil
}

// Publish github release
func (Pipe) Publish(ctx *context.Context) error {
	c, err := client.NewGitHub(ctx)
	if err != nil {
		return err
	}
	return doPublish(ctx, c)
}

func doPublish(ctx *context.Context, c client.Client) error {
	if ctx.Config.Release.Disable {
		return pipe.Skip("release pipe is disabled")
	}
	log.WithField("tag", ctx.Git.CurrentTag).
		WithField("repo", ctx.Config.Release.GitHub.String()).
		Info("creating or updating release")
	body, err := describeBody(ctx)
	if err != nil {
		return err
	}
	releaseID, err := c.CreateRelease(ctx, body.String())
	if err != nil {
		return err
	}
	var g = semerrgroup.New(ctx.Parallelism)
	for _, artifact := range ctx.Artifacts.Filter(
		artifact.Or(
			artifact.ByType(artifact.UploadableArchive),
			artifact.ByType(artifact.UploadableBinary),
			artifact.ByType(artifact.Checksum),
			artifact.ByType(artifact.Signature),
			artifact.ByType(artifact.LinuxPackage),
		),
	).List() {
		artifact := artifact
		g.Go(func() error {
			return upload(ctx, c, releaseID, artifact)
		})
	}
	return g.Wait()
}

func upload(ctx *context.Context, c client.Client, releaseID int64, artifact artifact.Artifact) error {
	file, err := os.Open(artifact.Path)
	if err != nil {
		return err
	}
	defer file.Close() // nolint: errcheck
	log.WithField("file", file.Name()).WithField("name", artifact.Name).Info("uploading to release")
	return c.Upload(ctx, releaseID, artifact.Name, file)
}
<commit_msg>fix: pass missing arg to log.Warnf (#886)<commit_after>package release

import (
	"os"

	"github.com/Masterminds/semver"
	"github.com/apex/log"
	"github.com/goreleaser/goreleaser/internal/artifact"
	"github.com/goreleaser/goreleaser/internal/client"
	"github.com/goreleaser/goreleaser/internal/pipe"
	"github.com/goreleaser/goreleaser/internal/semerrgroup"
	"github.com/goreleaser/goreleaser/pkg/context"
	"github.com/pkg/errors"
)

// Pipe for github release
type Pipe struct{}

func (Pipe) String() string {
	return "GitHub Releases"
}

// Default sets the pipe defaults
func (Pipe) Default(ctx *context.Context) error {
	if ctx.Config.Release.NameTemplate == "" {
		ctx.Config.Release.NameTemplate = "{{.Tag}}"
	}
	if ctx.Config.Release.GitHub.Name != "" {
		return nil
	}
	repo, err := remoteRepo()
	if err != nil && !ctx.Snapshot {
		return err
	}
	ctx.Config.Release.GitHub = repo

	ctx.PreRelease = false
	// Check if we have to check the git tag for an indicator to mark as pre release
	switch ctx.Config.Release.Prerelease {
	case "auto":
		sv, err := semver.NewVersion(ctx.Git.CurrentTag)
		if err != nil {
			return errors.Wrapf(err, "Failed to parse tag %s as semver", ctx.Git.CurrentTag)
		}

		if sv.Prerelease() != "" {
			ctx.PreRelease = true
		}
		log.Debugf("Pre-Release was detected for tag %s: %v", ctx.Git.CurrentTag, ctx.PreRelease)
	case "true":
		ctx.PreRelease = true
	case "false":
		ctx.PreRelease = false
	default:
		log.Warnf("Invalid value %s for prerelease. Should be auto, true or false", ctx.Config.Release.Prerelease)
	}

	return nil
}

// Publish github release
func (Pipe) Publish(ctx *context.Context) error {
	c, err := client.NewGitHub(ctx)
	if err != nil {
		return err
	}
	return doPublish(ctx, c)
}

func doPublish(ctx *context.Context, c client.Client) error {
	if ctx.Config.Release.Disable {
		return pipe.Skip("release pipe is disabled")
	}
	log.WithField("tag", ctx.Git.CurrentTag).
		WithField("repo", ctx.Config.Release.GitHub.String()).
		Info("creating or updating release")
	body, err := describeBody(ctx)
	if err != nil {
		return err
	}
	releaseID, err := c.CreateRelease(ctx, body.String())
	if err != nil {
		return err
	}
	var g = semerrgroup.New(ctx.Parallelism)
	for _, artifact := range ctx.Artifacts.Filter(
		artifact.Or(
			artifact.ByType(artifact.UploadableArchive),
			artifact.ByType(artifact.UploadableBinary),
			artifact.ByType(artifact.Checksum),
			artifact.ByType(artifact.Signature),
			artifact.ByType(artifact.LinuxPackage),
		),
	).List() {
		artifact := artifact
		g.Go(func() error {
			return upload(ctx, c, releaseID, artifact)
		})
	}
	return g.Wait()
}

func upload(ctx *context.Context, c client.Client, releaseID int64, artifact artifact.Artifact) error {
	file, err := os.Open(artifact.Path)
	if err != nil {
		return err
	}
	defer file.Close() // nolint: errcheck
	log.WithField("file", file.Name()).WithField("name", artifact.Name).Info("uploading to release")
	return c.Upload(ctx, releaseID, artifact.Name, file)
}
<|endoftext|>