<commit_before>package cloudcontroller_test

import (
	"fmt"
	"net/http"
	"strings"

	. "code.cloudfoundry.org/cli/api/cloudcontroller"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/ghttp"
)

type DummyResponse struct {
	Val1 string `json:"val1"`
	Val2 int    `json:"val2"`
}

var _ = Describe("Cloud Controller Connection", func() {
	var connection *CloudControllerConnection

	BeforeEach(func() {
		connection = NewConnection(Config{SkipSSLValidation: true})
	})

	Describe("Make", func() {
		Describe("Data Unmarshalling", func() {
			var request *http.Request

			BeforeEach(func() {
				response := `{
					"val1":"2.59.0",
					"val2":2
				}`
				server.AppendHandlers(
					CombineHandlers(
						VerifyRequest(http.MethodGet, "/v2/foo", ""),
						RespondWith(http.StatusOK, response),
					),
				)

				var err error
				request, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v2/foo", server.URL()), nil)
				Expect(err).ToNot(HaveOccurred())
			})

			Context("when passed a response with a result set", func() {
				It("unmarshals the data into a struct", func() {
					var body DummyResponse
					response := Response{
						Result: &body,
					}

					err := connection.Make(request, &response)
					Expect(err).NotTo(HaveOccurred())

					Expect(body.Val1).To(Equal("2.59.0"))
					Expect(body.Val2).To(Equal(2))
				})
			})

			Context("when passed an empty response", func() {
				It("skips the unmarshalling step", func() {
					var response Response
					err := connection.Make(request, &response)
					Expect(err).NotTo(HaveOccurred())
					Expect(response.Result).To(BeNil())
				})
			})
		})

		Describe("HTTP Response", func() {
			var request *http.Request

			BeforeEach(func() {
				response := `{}`
				server.AppendHandlers(
					CombineHandlers(
						VerifyRequest(http.MethodGet, "/v2/foo", ""),
						RespondWith(http.StatusOK, response),
					),
				)

				var err error
				request, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v2/foo", server.URL()), nil)
				Expect(err).ToNot(HaveOccurred())
			})

			It("returns the status", func() {
				response := Response{}

				err := connection.Make(request, &response)
				Expect(err).NotTo(HaveOccurred())

				Expect(response.HTTPResponse.Status).To(Equal("200 OK"))
			})
		})

		Describe("Response Headers", func() {
			Describe("X-Cf-Warnings", func() {
				BeforeEach(func() {
					server.AppendHandlers(
						CombineHandlers(
							VerifyRequest(http.MethodGet, "/v2/foo"),
							RespondWith(http.StatusOK, "{}", http.Header{"X-Cf-Warnings": {"42, Ed McMann, the 1942 doggers"}}),
						),
					)
				})

				It("returns them in Response", func() {
					request, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v2/foo", server.URL()), nil)
					Expect(err).ToNot(HaveOccurred())

					var response Response
					err = connection.Make(request, &response)
					Expect(err).NotTo(HaveOccurred())

					Expect(server.ReceivedRequests()).To(HaveLen(1))

					warnings := response.Warnings
					Expect(warnings).ToNot(BeNil())
					Expect(warnings).To(HaveLen(3))
					Expect(warnings).To(ContainElement("42"))
					Expect(warnings).To(ContainElement("Ed McMann"))
					Expect(warnings).To(ContainElement("the 1942 doggers"))
				})
			})
		})

		Describe("Errors", func() {
			Context("when the server does not exist", func() {
				BeforeEach(func() {
					connection = NewConnection(Config{})
				})

				It("returns a RequestError", func() {
					request, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v2/foo", "http://garbledyguk.com"), nil)
					Expect(err).ToNot(HaveOccurred())

					var response Response
					err = connection.Make(request, &response)
					Expect(err).To(HaveOccurred())

					requestErr, ok := err.(RequestError)
					Expect(ok).To(BeTrue())
					Expect(requestErr.Error()).To(MatchRegexp(".*http://garbledyguk.com/v2/foo.*[nN]o such host"))
				})
			})

			Context("when the server does not have a verified certificate", func() {
				Context("skipSSLValidation is false", func() {
					BeforeEach(func() {
						server.AppendHandlers(
							CombineHandlers(
								VerifyRequest(http.MethodGet, "/v2/foo"),
							),
						)

						connection = NewConnection(Config{})
					})

					It("returns a UnverifiedServerError", func() {
						request, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s", server.URL()), nil)
						Expect(err).ToNot(HaveOccurred())

						var response Response
						err = connection.Make(request, &response)
						Expect(err).To(MatchError(UnverifiedServerError{URL: server.URL()}))
					})
				})
			})

			Context("when the server's certificate does not match the hostname", func() {
				Context("skipSSLValidation is false", func() {
					BeforeEach(func() {
						server.AppendHandlers(
							CombineHandlers(
								VerifyRequest(http.MethodGet, "/"),
							),
						)

						connection = NewConnection(Config{})
					})

					It("returns a SSLValidationHostnameError", func() {
						altHostURL := strings.Replace(server.URL(), "127.0.0.1", "127.0.0.1.xip.io", -1)
						request, err := http.NewRequest(http.MethodGet, altHostURL, nil)
						Expect(err).ToNot(HaveOccurred())

						var response Response
						err = connection.Make(request, &response)
						Expect(err).To(MatchError(SSLValidationHostnameError{
							Message: "x509: certificate is valid for example.com, not 127.0.0.1.xip.io",
						}))
					})
				})
			})

			Describe("RawHTTPStatusError", func() {
				var ccResponse string
				BeforeEach(func() {
					ccResponse = `{
						"code": 90004,
						"description": "The service binding could not be found: some-guid",
						"error_code": "CF-ServiceBindingNotFound"
					}`

					server.AppendHandlers(
						CombineHandlers(
							VerifyRequest(http.MethodGet, "/v2/foo"),
							RespondWith(http.StatusNotFound, ccResponse),
						),
					)
				})

				It("returns a CCRawResponse", func() {
					request, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v2/foo", server.URL()), nil)
					Expect(err).ToNot(HaveOccurred())

					var response Response
					err = connection.Make(request, &response)
					Expect(err).To(MatchError(RawHTTPStatusError{
						StatusCode:  http.StatusNotFound,
						RawResponse: []byte(ccResponse),
					}))

					Expect(server.ReceivedRequests()).To(HaveLen(1))
				})
			})
		})
	})
})
<commit_msg>skipping in windows<commit_after>package cloudcontroller_test

import (
	"fmt"
	"net/http"
	"runtime"
	"strings"

	. "code.cloudfoundry.org/cli/api/cloudcontroller"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/ghttp"
)

type DummyResponse struct {
	Val1 string `json:"val1"`
	Val2 int    `json:"val2"`
}

var _ = Describe("Cloud Controller Connection", func() {
	var connection *CloudControllerConnection

	BeforeEach(func() {
		connection = NewConnection(Config{SkipSSLValidation: true})
	})

	Describe("Make", func() {
		Describe("Data Unmarshalling", func() {
			var request *http.Request

			BeforeEach(func() {
				response := `{
					"val1":"2.59.0",
					"val2":2
				}`
				server.AppendHandlers(
					CombineHandlers(
						VerifyRequest(http.MethodGet, "/v2/foo", ""),
						RespondWith(http.StatusOK, response),
					),
				)

				var err error
				request, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v2/foo", server.URL()), nil)
				Expect(err).ToNot(HaveOccurred())
			})

			Context("when passed a response with a result set", func() {
				It("unmarshals the data into a struct", func() {
					var body DummyResponse
					response := Response{
						Result: &body,
					}

					err := connection.Make(request, &response)
					Expect(err).NotTo(HaveOccurred())

					Expect(body.Val1).To(Equal("2.59.0"))
					Expect(body.Val2).To(Equal(2))
				})
			})

			Context("when passed an empty response", func() {
				It("skips the unmarshalling step", func() {
					var response Response
					err := connection.Make(request, &response)
					Expect(err).NotTo(HaveOccurred())
					Expect(response.Result).To(BeNil())
				})
			})
		})

		Describe("HTTP Response", func() {
			var request *http.Request

			BeforeEach(func() {
				response := `{}`
				server.AppendHandlers(
					CombineHandlers(
						VerifyRequest(http.MethodGet, "/v2/foo", ""),
						RespondWith(http.StatusOK, response),
					),
				)

				var err error
				request, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v2/foo", server.URL()), nil)
				Expect(err).ToNot(HaveOccurred())
			})

			It("returns the status", func() {
				response := Response{}

				err := connection.Make(request, &response)
				Expect(err).NotTo(HaveOccurred())

				Expect(response.HTTPResponse.Status).To(Equal("200 OK"))
			})
		})

		Describe("Response Headers", func() {
			Describe("X-Cf-Warnings", func() {
				BeforeEach(func() {
					server.AppendHandlers(
						CombineHandlers(
							VerifyRequest(http.MethodGet, "/v2/foo"),
							RespondWith(http.StatusOK, "{}", http.Header{"X-Cf-Warnings": {"42, Ed McMann, the 1942 doggers"}}),
						),
					)
				})

				It("returns them in Response", func() {
					request, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v2/foo", server.URL()), nil)
					Expect(err).ToNot(HaveOccurred())

					var response Response
					err = connection.Make(request, &response)
					Expect(err).NotTo(HaveOccurred())

					Expect(server.ReceivedRequests()).To(HaveLen(1))

					warnings := response.Warnings
					Expect(warnings).ToNot(BeNil())
					Expect(warnings).To(HaveLen(3))
					Expect(warnings).To(ContainElement("42"))
					Expect(warnings).To(ContainElement("Ed McMann"))
					Expect(warnings).To(ContainElement("the 1942 doggers"))
				})
			})
		})

		Describe("Errors", func() {
			Context("when the server does not exist", func() {
				BeforeEach(func() {
					connection = NewConnection(Config{})
				})

				It("returns a RequestError", func() {
					request, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v2/foo", "http://garbledyguk.com"), nil)
					Expect(err).ToNot(HaveOccurred())

					var response Response
					err = connection.Make(request, &response)
					Expect(err).To(HaveOccurred())

					requestErr, ok := err.(RequestError)
					Expect(ok).To(BeTrue())
					Expect(requestErr.Error()).To(MatchRegexp(".*http://garbledyguk.com/v2/foo.*[nN]o such host"))
				})
			})

			Context("when the server does not have a verified certificate", func() {
				Context("skipSSLValidation is false", func() {
					BeforeEach(func() {
						server.AppendHandlers(
							CombineHandlers(
								VerifyRequest(http.MethodGet, "/v2/foo"),
							),
						)

						connection = NewConnection(Config{})
					})

					It("returns a UnverifiedServerError", func() {
						request, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s", server.URL()), nil)
						Expect(err).ToNot(HaveOccurred())

						var response Response
						err = connection.Make(request, &response)
						Expect(err).To(MatchError(UnverifiedServerError{URL: server.URL()}))
					})
				})
			})

			Context("when the server's certificate does not match the hostname", func() {
				Context("skipSSLValidation is false", func() {
					BeforeEach(func() {
						if runtime.GOOS == "windows" {
							Skip("ssl validation has a different order on windows, will not be returned properly")
						}
						server.AppendHandlers(
							CombineHandlers(
								VerifyRequest(http.MethodGet, "/"),
							),
						)

						connection = NewConnection(Config{})
					})

					It("returns a SSLValidationHostnameError", func() {
						altHostURL := strings.Replace(server.URL(), "127.0.0.1", "127.0.0.1.xip.io", -1)
						request, err := http.NewRequest(http.MethodGet, altHostURL, nil)
						Expect(err).ToNot(HaveOccurred())

						var response Response
						err = connection.Make(request, &response)
						Expect(err).To(MatchError(SSLValidationHostnameError{
							Message: "x509: certificate is valid for example.com, not 127.0.0.1.xip.io",
						}))
					})
				})
			})

			Describe("RawHTTPStatusError", func() {
				var ccResponse string
				BeforeEach(func() {
					ccResponse = `{
						"code": 90004,
						"description": "The service binding could not be found: some-guid",
						"error_code": "CF-ServiceBindingNotFound"
					}`

					server.AppendHandlers(
						CombineHandlers(
							VerifyRequest(http.MethodGet, "/v2/foo"),
							RespondWith(http.StatusNotFound, ccResponse),
						),
					)
				})

				It("returns a CCRawResponse", func() {
					request, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v2/foo", server.URL()), nil)
					Expect(err).ToNot(HaveOccurred())

					var response Response
					err = connection.Make(request, &response)
					Expect(err).To(MatchError(RawHTTPStatusError{
						StatusCode:  http.StatusNotFound,
						RawResponse: []byte(ccResponse),
					}))

					Expect(server.ReceivedRequests()).To(HaveLen(1))
				})
			})
		})
	})
})
<|endoftext|>


<commit_before>package backend

type Message struct {
	ID string
	Order int
	ConversationID string
	Subject string
	IsRead int
	Type int
	SenderAddress string
	SenderName string
	Sender *Email
	ToList []*Email
	CCList []*Email
	BCCList []*Email
	Time int64
	Size int
	NumAttachments int
	IsEncrypted int
	ExpirationTime int
	IsReplied int
	IsRepliedAll int
	IsForwarded int
	AddressID string
	Body string
	Header string
	ReplyTo *Email
	Attachments []*Attachment
	Starred int
	Location int
	LabelIDs []string
}

const (
	DraftType int = 1
	SentType = 2
	SentToMyselfType = 3
)

type Attachment struct {} // TODO

type MessagePackage struct {
	Address string
	Type int
	Body string
	KeyPackets []interface{} // TODO
}

type MessagesFilter struct {
	Limit int
	Page int
	Label string
	Keyword string
	Address string // Address ID
	Attachments bool
	From string
	To string
	Begin int // Timestamp
	End int // Timestamp
	Sort string
	Desc bool
}

type MessageUpdate struct {
	Message *Message
	ToList bool
	CCList bool
	BCCList bool
	Subject bool
	IsRead bool
	Type bool
	AddressID bool
	Body bool
	Time bool
	LabelIDs LabelsOperation
}

type LabelsOperation int

const (
	KeepLabels LabelsOperation = iota
	ReplaceLabels
	AddLabels
	RemoveLabels
)
<commit_msg>Adds encrypted message types constants<commit_after>package backend

type Message struct {
	ID string
	Order int
	ConversationID string
	Subject string
	IsRead int
	Type int
	SenderAddress string
	SenderName string
	Sender *Email
	ToList []*Email
	CCList []*Email
	BCCList []*Email
	Time int64
	Size int
	NumAttachments int
	IsEncrypted int
	ExpirationTime int
	IsReplied int
	IsRepliedAll int
	IsForwarded int
	AddressID string
	Body string
	Header string
	ReplyTo *Email
	Attachments []*Attachment
	Starred int
	Location int
	LabelIDs []string
}

const (
	DraftType int = 1
	SentType = 2
	SentToMyselfType = 3
)

const (
	Unencrypted int = 0
	EndToEndEncryptedInternal = 1
	EncryptedExternal = 2
	EndToEndEncryptedExternal = 3
	StoredEncryptedExternal = 4
	StoredEncrypted = 5
	EndToEndEncryptedExternalReply = 6
	EncryptedPgp = 7
	EncryptedPgpMime = 8
)

type Attachment struct {} // TODO

type MessagePackage struct {
	Address string
	Type int
	Body string
	KeyPackets []interface{} // TODO
}

type MessagesFilter struct {
	Limit int
	Page int
	Label string
	Keyword string
	Address string // Address ID
	Attachments bool
	From string
	To string
	Begin int // Timestamp
	End int // Timestamp
	Sort string
	Desc bool
}

type MessageUpdate struct {
	Message *Message
	ToList bool
	CCList bool
	BCCList bool
	Subject bool
	IsRead bool
	Type bool
	AddressID bool
	Body bool
	Time bool
	LabelIDs LabelsOperation
}

type LabelsOperation int

const (
	KeepLabels LabelsOperation = iota
	ReplaceLabels
	AddLabels
	RemoveLabels
)
<|endoftext|>


<commit_before>package main

import "flag"
import "strings"
import "bufio"
import "os"
import "io"

func konverti(de string, iksen bool) string {
	returnstring := de
	a := 0
	b := 1
	if iksen {
		a, b = 1, 0
	}
	tabelo := [18][2]string{
		{"cx", "ĉ"},
		{"gx", "ĝ"},
		{"hx", "ĥ"},
		{"jx", "ĵ"},
		{"sx", "ŝ"},
		{"ux", "ŭ"},
		{"Cx", "Ĉ"},
		{"Gx", "Ĝ"},
		{"Hx", "Ĥ"},
		{"Jx", "Ĵ"},
		{"Sx", "Ŝ"},
		{"Ux", "Ŭ"},
		{"CX", "Ĉ"},
		{"GX", "Ĝ"},
		{"HX", "Ĥ"},
		{"JX", "Ĵ"},
		{"SX", "Ŝ"},
		{"UX", "Ŭ"},
	}
	for i := 0; i<18; i++ {
		returnstring = strings.Replace(returnstring,
				tabelo[i][a], tabelo[i][b], -1)
	}
	return returnstring
}

func konvertifluon(fluo *bufio.Reader, kien io.Writer, iksen bool) {
	for i, err:=fluo.ReadString('\n'); err == nil; i, err=fluo.ReadString('\n'){
		io.WriteString(kien, konverti(i, iksen))
	}
}

func main() {
	direkto := flag.Bool("iksen", false, "Traduki al iksoj. Defaŭlte tradukiĝas al veraj ĉapeloj.")
	flag.Parse()

	enigo := flag.Arg(0)

	dosiero, err := os.Open(enigo)
	if err != nil {
		dosiero = os.Stdin
	}
	konvertifluon(bufio.NewReader(dosiero), os.Stdout, *direkto)
}
<commit_msg>Clean up visual aspects: table uses less screen space and help text is bilingual now<commit_after>package main

import "flag"
import "strings"
import "bufio"
import "os"
import "io"

func konverti(de string, iksen bool) string {
	a := 0
	b := 1
	if iksen {
		a, b = 1, 0
	}
	tabelo := [18][2]string{
		{"cx", "ĉ"}, {"gx", "ĝ"}, {"hx", "ĥ"},
		{"jx", "ĵ"}, {"sx", "ŝ"}, {"ux", "ŭ"},

		{"Cx", "Ĉ"}, {"Gx", "Ĝ"}, {"Hx", "Ĥ"},
		{"Jx", "Ĵ"}, {"Sx", "Ŝ"}, {"Ux", "Ŭ"},

		{"CX", "Ĉ"}, {"GX", "Ĝ"}, {"HX", "Ĥ"},
		{"JX", "Ĵ"}, {"SX", "Ŝ"}, {"UX", "Ŭ"},
	}
	for i := 0; i<18; i++ {
		de = strings.Replace(de, tabelo[i][a], tabelo[i][b], -1)
	}
	return de
}

func konvertifluon(fluo *bufio.Reader, kien io.Writer, iksen bool) {
	for i, err:=fluo.ReadString('\n'); err == nil; i, err=fluo.ReadString('\n'){
		io.WriteString(kien, konverti(i, iksen))
	}
}

func main() {
	direkto := flag.Bool("x", false, "Traduki al iksoj. Convert to x-system.)")
	flag.Parse()

	enigo := flag.Arg(0)

	dosiero, err := os.Open(enigo)
	if err != nil {
		dosiero = os.Stdin
	}
	konvertifluon(bufio.NewReader(dosiero), os.Stdout, *direkto)
}
<|endoftext|>


<commit_before>package xkcd

import (
	"image"
	_ "image/gif"
	_ "image/jpeg"
	_ "image/png"
	"io"
	"net/http"
	"path"
)

// Image represents an xkcd comic image.
type Image struct {
	image.Image

	sourceURL    string
	sourceFormat string
}

// NewImage takes an io.Reader and returns an Image struct.
func NewImage(r io.Reader) (*Image, error) {
	var img Image
	var err error

	img.Image, img.sourceFormat, err = image.Decode(r)

	return &img, err
}

// GetImage is a convenience function to download a comic's metadata and
// then download the comic's image. If you already have the comic
// metadata, use Comic's Image() method.
func GetImage(n int) (*Image, error) {
	c, err := Get(n)
	if err != nil {
		return nil, err
	}
	return c.Image()
}

func getImageFromURL(url string) (*Image, error) {
	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	img, err := NewImage(resp.Body)
	if err != nil {
		return nil, err
	}

	img.sourceURL = url

	return img, nil
}

// SourceURL is URL from which the comic image was retrieved. If image
// wasn't retrieved from a URL (e.g. when it is created by calling
// NewImage directly), an empty string will be returned.
func (img *Image) SourceURL() string {
	return img.sourceURL
}

// SourceName is the original file name of the comic image. If the Image
// wasn't retrieved from a URL (e.g. when it is created by calling
// NewImage directly), an empty string will be returned.
func (img *Image) SourceName() string {
	url := img.SourceURL()
	if url == "" {
		return ""
	}
	return path.Base(url)
}

// SourceFormat is the file format that the image was decoded from.
func (img *Image) SourceFormat() string {
	return img.sourceFormat
}
<commit_msg>Add comments to blank imports of gif, jpeg, and png.<commit_after>package xkcd

import (
	"image"
	// Some xkcd comics are in gif format.
	_ "image/gif"
	// Some xkcd comics are in jpeg format.
	_ "image/jpeg"
	// Some xkcd comics are in png format.
	_ "image/png"
	"io"
	"net/http"
	"path"
)

// Image represents an xkcd comic image.
type Image struct {
	image.Image

	sourceURL    string
	sourceFormat string
}

// NewImage takes an io.Reader and returns an Image struct.
func NewImage(r io.Reader) (*Image, error) {
	var img Image
	var err error

	img.Image, img.sourceFormat, err = image.Decode(r)

	return &img, err
}

// GetImage is a convenience function to download a comic's metadata and
// then download the comic's image. If you already have the comic
// metadata, use Comic's Image() method.
func GetImage(n int) (*Image, error) {
	c, err := Get(n)
	if err != nil {
		return nil, err
	}
	return c.Image()
}

func getImageFromURL(url string) (*Image, error) {
	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	img, err := NewImage(resp.Body)
	if err != nil {
		return nil, err
	}

	img.sourceURL = url

	return img, nil
}

// SourceURL is URL from which the comic image was retrieved. If image
// wasn't retrieved from a URL (e.g. when it is created by calling
// NewImage directly), an empty string will be returned.
func (img *Image) SourceURL() string {
	return img.sourceURL
}

// SourceName is the original file name of the comic image. If the Image
// wasn't retrieved from a URL (e.g. when it is created by calling
// NewImage directly), an empty string will be returned.
func (img *Image) SourceName() string {
	url := img.SourceURL()
	if url == "" {
		return ""
	}
	return path.Base(url)
}

// SourceFormat is the file format that the image was decoded from.
func (img *Image) SourceFormat() string {
	return img.sourceFormat
}
<|endoftext|>


<commit_before>/*
Copyright 2019 Google Inc. All rights reserved.

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 banner

import (
	"bytes"
	"context"
	"net/http"
	"net/url"
	"strings"
	"text/template"
	"time"
)

const (
	acceptHeader             = "Accept"
	cacheControlHeader       = "Cache-Control"
	contentDispositionHeader = "Content-Disposition"
	contentEncodingHeader    = "Content-Encoding"
	contentTypeHeader        = "Content-Type"
	dateHeader               = "Date"
	expiresHeader            = "Expires"
	refererHeader            = "Referer"
	pragmaHeader             = "Pragma"
	secFetchDestHeader       = "Sec-Fetch-Dest"
	secFetchModeHeader       = "Sec-Fetch-Mode"
	xFrameOptionsHeader      = "X-Frame-Options"

	frameWrapperTemplate = `

    <meta http-equiv="cache-control" content="no-cache" />
    {{.FavIconLink}}

      {{.Banner}}

`
	favIconLinkTemplate = `<link rel="icon" type="image/png" href="{{.FavIconURL}}">`
)

var frameWrapperTmpl = template.Must(template.New("frame-wrapper").Parse(frameWrapperTemplate))
var favIconLinkTmpl = template.Must(template.New("fav-icon").Parse(favIconLinkTemplate))

func isHTMLRequest(r *http.Request) bool {
	// We want to err on the side of not injecting a banner in case that might
	// interfere with the semantics of the app. Since we can't know the expected
	// semantics for the response to a POST reqest, we play it safe and only
	// inject the banner in responses to GET requests.
	if r.Method != http.MethodGet {
		return false
	}
	accept := r.Header.Get(acceptHeader)
	// Our injected response will be HTML, so we don't want to inject it unless
	// the client explicitly stated it will accept HTML responses.
	return strings.Contains(accept, "text/html")
}

func isFrameableHTMLResponse(statusCode int, responseHeader http.Header) bool {
	if statusCode != http.StatusOK {
		return false
	}
	for _, contentDisposition := range responseHeader.Values(contentDispositionHeader) {
		if strings.Contains(contentDisposition, "attachment") {
			return false
		}
	}
	for _, contentType := range responseHeader.Values(contentTypeHeader) {
		if strings.Contains(contentType, "text/html") || strings.Contains(contentType, "application/xhtml+xml") {
			return true
		}
	}
	return false
}

func isAlreadyFramed(r *http.Request) bool {
	if r.Header.Get(secFetchModeHeader) == "nested-navigate" || r.Header.Get(secFetchDestHeader) == "iframe" {
		// If the browser told us the page is already framed, then believe it.
		return true
	}
	if referer := r.Header.Get(refererHeader); referer != "" {
		refererURL, err := url.Parse(referer)
		if err == nil && refererURL.Host == r.Host && refererURL.Path == r.URL.Path {
			return true
		}
	}
	return false
}

type bannerResponseWriter struct {
	wrapped      http.ResponseWriter
	bannerHTML   string
	bannerHeight string
	targetURL    *url.URL
	favIconURL   string

	wroteHeader     bool
	writeBytes      bool
	isAlreadyFramed bool
}

func (w *bannerResponseWriter) Header() http.Header {
	return w.wrapped.Header()
}

func setNotCacheable(h http.Header) {
	h.Set(cacheControlHeader, "no-cache, no-store, max-age=0, must-revalidate")
	h.Set(dateHeader, time.Now().UTC().Format(http.TimeFormat))
	h.Set(expiresHeader, time.Time{}.UTC().Format(http.TimeFormat))
	h.Set(pragmaHeader, "no-cache")
}

func setXFrameOptionsSameOrigin(h http.Header) {
	h.Del(xFrameOptionsHeader)
	h.Set(xFrameOptionsHeader, "sameorigin")
}

func (w *bannerResponseWriter) getFavIconLink() (string, error) {
	if w.favIconURL == "" {
		return "", nil
	}
	var favIconLinkBuf bytes.Buffer
	templateVals := &struct {
		FavIconUrl string
	}{
		FavIconUrl: w.favIconURL,
	}
	if err := favIconLinkTmpl.Execute(&favIconLinkBuf, templateVals); err != nil {
		return "", err
	}
	return favIconLinkBuf.String(), nil
}

func (w *bannerResponseWriter) getBanner(favIconLink string) ([]byte, error) {
	var templateBuf bytes.Buffer
	templateVals := &struct {
		TargetURL    string
		Banner       string
		BannerHeight string
		FavIconLink  string
	}{
		TargetURL:    w.targetURL.String(),
		Banner:       w.bannerHTML,
		BannerHeight: w.bannerHeight,
		FavIconLink:  favIconLink,
	}
	if err := frameWrapperTmpl.Execute(&templateBuf, templateVals); err != nil {
		return []byte{}, err
	}
	return templateBuf.Bytes(), nil
}

func (w *bannerResponseWriter) WriteHeader(statusCode int) {
	if w.wroteHeader {
		return
	}
	w.wroteHeader = true
	if !isFrameableHTMLResponse(statusCode, w.Header()) {
		w.wrapped.WriteHeader(statusCode)
		w.writeBytes = true
		return
	}
	setNotCacheable(w.Header())
	setXFrameOptionsSameOrigin(w.Header())
	if w.isAlreadyFramed {
		w.wrapped.WriteHeader(statusCode)
		w.writeBytes = true
		return
	} else {
		w.Header().Del(contentEncodingHeader)
	}
	favIconLink, err := w.getFavIconLink()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	banner, e := w.getBanner(favIconLink)
	if e != nil {
		http.Error(w, e.Error(), http.StatusInternalServerError)
		return
	}

	w.wrapped.WriteHeader(statusCode)
	w.wrapped.Write(banner)
}

func (w *bannerResponseWriter) Write(bs []byte) (int, error) {
	if !w.wroteHeader {
		w.WriteHeader(http.StatusOK)
	}
	if !w.writeBytes {
		return len(bs), nil
	}
	return w.wrapped.Write(bs)
}

// Proxy builds an HTTP handler that proxies to a wrapped handler but injects the given HTML banner into every HTML response.
func Proxy(ctx context.Context, wrapped http.Handler, bannerHTML, bannerHeight, favIconURL string) (http.Handler, error) {
	mux := http.NewServeMux()
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if !isHTMLRequest(r) {
			wrapped.ServeHTTP(w, r)
			return
		}
		w = &bannerResponseWriter{
			wrapped:         w,
			bannerHTML:      bannerHTML,
			bannerHeight:    bannerHeight,
			targetURL:       r.URL,
			isAlreadyFramed: isAlreadyFramed(r),
			favIconURL:      favIconURL,
		}
		wrapped.ServeHTTP(w, r)
	})
	return mux, nil
}
<commit_msg>agent: Switch the banner logic to not use 1.14-only features.<commit_after>/*
Copyright 2019 Google Inc. All rights reserved.

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 banner

import (
	"bytes"
	"context"
	"net/http"
	"net/url"
	"strings"
	"text/template"
	"time"
)

const (
	acceptHeader             = "Accept"
	cacheControlHeader       = "Cache-Control"
	contentDispositionHeader = "Content-Disposition"
	contentEncodingHeader    = "Content-Encoding"
	contentTypeHeader        = "Content-Type"
	dateHeader               = "Date"
	expiresHeader            = "Expires"
	refererHeader            = "Referer"
	pragmaHeader             = "Pragma"
	secFetchDestHeader       = "Sec-Fetch-Dest"
	secFetchModeHeader       = "Sec-Fetch-Mode"
	xFrameOptionsHeader      = "X-Frame-Options"

	frameWrapperTemplate = `

    <meta http-equiv="cache-control" content="no-cache" />
    {{.FavIconLink}}

      {{.Banner}}

`
	favIconLinkTemplate = `<link rel="icon" type="image/png" href="{{.FavIconURL}}">`
)

var frameWrapperTmpl = template.Must(template.New("frame-wrapper").Parse(frameWrapperTemplate))
var favIconLinkTmpl = template.Must(template.New("fav-icon").Parse(favIconLinkTemplate))

func isHTMLRequest(r *http.Request) bool {
	// We want to err on the side of not injecting a banner in case that might
	// interfere with the semantics of the app. Since we can't know the expected
	// semantics for the response to a POST reqest, we play it safe and only
	// inject the banner in responses to GET requests.
	if r.Method != http.MethodGet {
		return false
	}
	accept := r.Header.Get(acceptHeader)
	// Our injected response will be HTML, so we don't want to inject it unless
	// the client explicitly stated it will accept HTML responses.
	return strings.Contains(accept, "text/html")
}

func isFrameableHTMLResponse(statusCode int, responseHeader http.Header) bool {
	if statusCode != http.StatusOK {
		return false
	}
	for _, contentDisposition := range responseHeader[contentDispositionHeader] {
		if strings.Contains(contentDisposition, "attachment") {
			return false
		}
	}
	for _, contentType := range responseHeader[contentTypeHeader] {
		if strings.Contains(contentType, "text/html") || strings.Contains(contentType, "application/xhtml+xml") {
			return true
		}
	}
	return false
}

func isAlreadyFramed(r *http.Request) bool {
	if r.Header.Get(secFetchModeHeader) == "nested-navigate" || r.Header.Get(secFetchDestHeader) == "iframe" {
		// If the browser told us the page is already framed, then believe it.
		return true
	}
	if referer := r.Header.Get(refererHeader); referer != "" {
		refererURL, err := url.Parse(referer)
		if err == nil && refererURL.Host == r.Host && refererURL.Path == r.URL.Path {
			return true
		}
	}
	return false
}

type bannerResponseWriter struct {
	wrapped      http.ResponseWriter
	bannerHTML   string
	bannerHeight string
	targetURL    *url.URL
	favIconURL   string

	wroteHeader     bool
	writeBytes      bool
	isAlreadyFramed bool
}

func (w *bannerResponseWriter) Header() http.Header {
	return w.wrapped.Header()
}

func setNotCacheable(h http.Header) {
	h.Set(cacheControlHeader, "no-cache, no-store, max-age=0, must-revalidate")
	h.Set(dateHeader, time.Now().UTC().Format(http.TimeFormat))
	h.Set(expiresHeader, time.Time{}.UTC().Format(http.TimeFormat))
	h.Set(pragmaHeader, "no-cache")
}

func setXFrameOptionsSameOrigin(h http.Header) {
	h.Del(xFrameOptionsHeader)
	h.Set(xFrameOptionsHeader, "sameorigin")
}

func (w *bannerResponseWriter) getFavIconLink() (string, error) {
	if w.favIconURL == "" {
		return "", nil
	}
	var favIconLinkBuf bytes.Buffer
	templateVals := &struct {
		FavIconUrl string
	}{
		FavIconUrl: w.favIconURL,
	}
	if err := favIconLinkTmpl.Execute(&favIconLinkBuf, templateVals); err != nil {
		return "", err
	}
	return favIconLinkBuf.String(), nil
}

func (w *bannerResponseWriter) getBanner(favIconLink string) ([]byte, error) {
	var templateBuf bytes.Buffer
	templateVals := &struct {
		TargetURL    string
		Banner       string
		BannerHeight string
		FavIconLink  string
	}{
		TargetURL:    w.targetURL.String(),
		Banner:       w.bannerHTML,
		BannerHeight: w.bannerHeight,
		FavIconLink:  favIconLink,
	}
	if err := frameWrapperTmpl.Execute(&templateBuf, templateVals); err != nil {
		return []byte{}, err
	}
	return templateBuf.Bytes(), nil
}

func (w *bannerResponseWriter) WriteHeader(statusCode int) {
	if w.wroteHeader {
		return
	}
	w.wroteHeader = true
	if !isFrameableHTMLResponse(statusCode, w.Header()) {
		w.wrapped.WriteHeader(statusCode)
		w.writeBytes = true
		return
	}
	setNotCacheable(w.Header())
	setXFrameOptionsSameOrigin(w.Header())
	if w.isAlreadyFramed {
		w.wrapped.WriteHeader(statusCode)
		w.writeBytes = true
		return
	} else {
		w.Header().Del(contentEncodingHeader)
	}
	favIconLink, err := w.getFavIconLink()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	banner, e := w.getBanner(favIconLink)
	if e != nil {
		http.Error(w, e.Error(), http.StatusInternalServerError)
		return
	}

	w.wrapped.WriteHeader(statusCode)
	w.wrapped.Write(banner)
}

func (w *bannerResponseWriter) Write(bs []byte) (int, error) {
	if !w.wroteHeader {
		w.WriteHeader(http.StatusOK)
	}
	if !w.writeBytes {
		return len(bs), nil
	}
	return w.wrapped.Write(bs)
}

// Proxy builds an HTTP handler that proxies to a wrapped handler but injects the given HTML banner into every HTML response.
func Proxy(ctx context.Context, wrapped http.Handler, bannerHTML, bannerHeight, favIconURL string) (http.Handler, error) {
	mux := http.NewServeMux()
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if !isHTMLRequest(r) {
			wrapped.ServeHTTP(w, r)
			return
		}
		w = &bannerResponseWriter{
			wrapped:         w,
			bannerHTML:      bannerHTML,
			bannerHeight:    bannerHeight,
			targetURL:       r.URL,
			isAlreadyFramed: isAlreadyFramed(r),
			favIconURL:      favIconURL,
		}
		wrapped.ServeHTTP(w, r)
	})
	return mux, nil
}
<|endoftext|>


<commit_before>package gen

import (
	"bytes"
	"fmt"
	"hash/fnv"
	"io"
	"path"
	"reflect"
	"sort"
	"strconv"
	"strings"
	"unicode"
)

const pkgWriter = "github.com/mailru/easyjson/jwriter"
const pkgLexer = "github.com/mailru/easyjson/jlexer"
const pkgEasyJSON = "github.com/mailru/easyjson"

// FieldNamer defines a policy for generating names for struct fields.
type FieldNamer interface {
	GetJSONFieldName(t reflect.Type, f reflect.StructField) string
}

// Generator generates the requested marshaler/unmarshalers.
type Generator struct {
	out *bytes.Buffer

	pkgName    string
	pkgPath    string
	buildTags  string
	hashString string

	varCounter int

	noStdMarshalers bool
	omitEmpty       bool
	fieldNamer      FieldNamer

	// package path to local alias map for tracking imports
	imports map[string]string

	// types that marshalers were requested for by user
	marshalers map[reflect.Type]bool

	// types that encoders were already generated for
	typesSeen map[reflect.Type]bool

	// types that encoders were requested for (e.g. by encoders of other types)
	typesUnseen []reflect.Type

	// function name to relevant type maps to track names of de-/encoders in
	// case of a name clash or unnamed structs
	functionNames map[string]reflect.Type
}

// NewGenerator initializes and returns a Generator.
func NewGenerator(filename string) *Generator {
	ret := &Generator{
		imports: map[string]string{
			pkgWriter:       "jwriter",
			pkgLexer:        "jlexer",
			pkgEasyJSON:     "easyjson",
			"encoding/json": "json",
		},
		fieldNamer:    DefaultFieldNamer{},
		marshalers:    make(map[reflect.Type]bool),
		typesSeen:     make(map[reflect.Type]bool),
		functionNames: make(map[string]reflect.Type),
	}

	// Use a file-unique prefix on all auxiliary funcs to avoid
	// name clashes.
	hash := fnv.New32()
	hash.Write([]byte(filename))
	ret.hashString = fmt.Sprintf("%x", hash.Sum32())

	return ret
}

// SetPkg sets the name and path of output package.
func (g *Generator) SetPkg(name, path string) {
	g.pkgName = name
	g.pkgPath = path
}

// SetBuildTags sets build tags for the output file.
func (g *Generator) SetBuildTags(tags string) {
	g.buildTags = tags
}

// SetFieldNamer sets field naming strategy.
func (g *Generator) SetFieldNamer(n FieldNamer) {
	g.fieldNamer = n
}

// UseSnakeCase sets snake_case field naming strategy.
func (g *Generator) UseSnakeCase() {
	g.fieldNamer = SnakeCaseFieldNamer{}
}

// NoStdMarshalers instructs not to generate standard MarshalJSON/UnmarshalJSON
// methods (only the custom interface).
func (g *Generator) NoStdMarshalers() {
	g.noStdMarshalers = true
}

// OmitEmpty triggers `json=",omitempty"` behaviour by default.
func (g *Generator) OmitEmpty() {
	g.omitEmpty = true
}

// addTypes requests to generate encoding/decoding funcs for the given type.
func (g *Generator) addType(t reflect.Type) {
	if g.typesSeen[t] {
		return
	}
	for _, t1 := range g.typesUnseen {
		if t1 == t {
			return
		}
	}
	g.typesUnseen = append(g.typesUnseen, t)
}

// Add requests to generate marshaler/unmarshalers and encoding/decoding
// funcs for the type of given object.
func (g *Generator) Add(obj interface{}) {
	t := reflect.TypeOf(obj)
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	g.addType(t)
	g.marshalers[t] = true
}

// printHeader prints package declaration and imports.
func (g *Generator) printHeader() {
	if g.buildTags != "" {
		fmt.Println("// +build ", g.buildTags)
		fmt.Println()
	}
	fmt.Println("// AUTOGENERATED FILE: easyjson marshaler/unmarshalers.")
	fmt.Println()
	fmt.Println("package ", g.pkgName)
	fmt.Println()

	byAlias := map[string]string{}
	var aliases []string
	for path, alias := range g.imports {
		aliases = append(aliases, alias)
		byAlias[alias] = path
	}

	sort.Strings(aliases)
	fmt.Println("import (")
	for _, alias := range aliases {
		fmt.Printf("  %s %q\n", alias, byAlias[alias])
	}

	fmt.Println(")")
	fmt.Println("")
	fmt.Println("// suppress unused package warning")
	fmt.Println("var (")
	fmt.Println("   _ *json.RawMessage")
	fmt.Println("   _ *jlexer.Lexer")
	fmt.Println("   _ *jwriter.Writer")
	fmt.Println("   _ easyjson.Marshaler")
	fmt.Println(")")

	fmt.Println()
}

// Run runs the generator and outputs generated code to out.
func (g *Generator) Run(out io.Writer) error {
	g.out = &bytes.Buffer{}

	for len(g.typesUnseen) > 0 {
		t := g.typesUnseen[len(g.typesUnseen)-1]
		g.typesUnseen = g.typesUnseen[:len(g.typesUnseen)-1]
		g.typesSeen[t] = true

		if err := g.genDecoder(t); err != nil {
			return err
		}
		if err := g.genEncoder(t); err != nil {
			return err
		}

		if !g.marshalers[t] {
			continue
		}

		if err := g.genStructMarshaler(t); err != nil {
			return err
		}
		if err := g.genStructUnmarshaler(t); err != nil {
			return err
		}
	}
	g.printHeader()
	_, err := out.Write(g.out.Bytes())
	return err
}

// fixes vendored paths
func fixPkgPathVendoring(pkgPath string) string {
	const vendor = "/vendor/"
	if i := strings.LastIndex(pkgPath, vendor); i != -1 {
		return pkgPath[i+len(vendor):]
	}
	return pkgPath
}

func fixAliasName(alias string) string {
	alias = strings.Replace(
		strings.Replace(path.Base(pkgPath), ".", "_", -1),
		"-",
		"_",
		-1,
	)
	return alias
}

// pkgAlias creates and returns and import alias for a given package.
func (g *Generator) pkgAlias(pkgPath string) string {
	pkgPath = fixPkgPathVendoring(pkgPath)
	if alias := g.imports[pkgPath]; alias != "" {
		return alias
	}

	for i := 0; ; i++ {
		alias := fixAliasName(path.Base(pkgPath))
		if i > 0 {
			alias += fmt.Sprint(i)
		}

		exists := false
		for _, v := range g.imports {
			if v == alias {
				exists = true
				break
			}
		}

		if !exists {
			g.imports[pkgPath] = alias
			return alias
		}
	}
}

// getType return the textual type name of given type that can be used in generated code.
func (g *Generator) getType(t reflect.Type) string {
	if t.Name() == "" {
		switch t.Kind() {
		case reflect.Ptr:
			return "*" + g.getType(t.Elem())
		case reflect.Slice:
			return "[]" + g.getType(t.Elem())
		case reflect.Array:
			return "[" + strconv.Itoa(t.Len()) + "]" + g.getType(t.Elem())
		case reflect.Map:
			return "map[" + g.getType(t.Key()) + "]" + g.getType(t.Elem())
		}
	}

	if t.Name() == "" || t.PkgPath() == "" {
		if t.Kind() == reflect.Struct {
			// the fields of an anonymous struct can have named types,
			// and t.String() will not be sufficient because it does not
			// remove the package name when it matches g.pkgPath.
			// so we convert by hand
			nf := t.NumField()
			lines := make([]string, 0, nf)
			for i := 0; i < nf; i++ {
				f := t.Field(i)
				line := f.Name + " " + g.getType(f.Type)
				t := f.Tag
				if t != "" {
					line += " " + escapeTag(t)
				}
				lines = append(lines, line)
			}
			return strings.Join([]string{"struct { ", strings.Join(lines, "; "), " }"}, "")
		}
		return t.String()
	} else if t.PkgPath() == g.pkgPath {
		return t.Name()
	}
	return g.pkgAlias(t.PkgPath()) + "." + t.Name()
}

// escape a struct field tag string back to source code
func escapeTag(tag reflect.StructTag) string {
	t := string(tag)
	if strings.ContainsRune(t, '`') {
		// there are ` in the string; we can't use ` to enclose the string
		return strconv.Quote(t)
	}
	return "`" + t + "`"
}

// uniqueVarName returns a file-unique name that can be used for generated variables.
func (g *Generator) uniqueVarName() string {
	g.varCounter++
	return fmt.Sprint("v", g.varCounter)
}

// safeName escapes unsafe characters in pkg/type name and returns a string that can be used
// in encoder/decoder names for the type.
func (g *Generator) safeName(t reflect.Type) string {
	name := t.PkgPath()
	if t.Name() == "" {
		name += "anonymous"
	} else {
		name += "." + t.Name()
	}

	parts := []string{}
	part := []rune{}
	for _, c := range name {
		if unicode.IsLetter(c) || unicode.IsDigit(c) {
			part = append(part, c)
		} else if len(part) > 0 {
			parts = append(parts, string(part))
			part = []rune{}
		}
	}
	return joinFunctionNameParts(false, parts...)
}

// functionName returns a function name for a given type with a given prefix. If a function
// with this prefix already exists for a type, it is returned.
//
// Method is used to track encoder/decoder names for the type.
func (g *Generator) functionName(prefix string, t reflect.Type) string {
	prefix = joinFunctionNameParts(true, "easyjson", g.hashString, prefix)
	name := joinFunctionNameParts(true, prefix, g.safeName(t))

	// Most of the names will be unique, try a shortcut first.
	if e, ok := g.functionNames[name]; !ok || e == t {
		g.functionNames[name] = t
		return name
	}

	// Search if the function already exists.
	for name1, t1 := range g.functionNames {
		if t1 == t && strings.HasPrefix(name1, prefix) {
			return name1
		}
	}

	// Create a new name in the case of a clash.
	for i := 1; ; i++ {
		nm := fmt.Sprint(name, i)
		if _, ok := g.functionNames[nm]; ok {
			continue
		}
		g.functionNames[nm] = t
		return nm
	}
}

// DefaultFieldsNamer implements trivial naming policy equivalent to encoding/json.
type DefaultFieldNamer struct{}

func (DefaultFieldNamer) GetJSONFieldName(t reflect.Type, f reflect.StructField) string {
	jsonName := strings.Split(f.Tag.Get("json"), ",")[0]
	if jsonName != "" {
		return jsonName
	} else {
		return f.Name
	}
}

// SnakeCaseFieldNamer implements CamelCase to snake_case conversion for fields names.
type SnakeCaseFieldNamer struct{}

func camelToSnake(name string) string {
	var ret bytes.Buffer

	multipleUpper := false
	var lastUpper rune
	var beforeUpper rune

	for _, c := range name {
		// Non-lowercase character after uppercase is considered to be uppercase too.
		isUpper := (unicode.IsUpper(c) || (lastUpper != 0 && !unicode.IsLower(c)))

		if lastUpper != 0 {
			// Output a delimiter if last character was either the first uppercase character
			// in a row, or the last one in a row (e.g. 'S' in "HTTPServer").
			// Do not output a delimiter at the beginning of the name.

			firstInRow := !multipleUpper
			lastInRow := !isUpper

			if ret.Len() > 0 && (firstInRow || lastInRow) && beforeUpper != '_' {
				ret.WriteByte('_')
			}
			ret.WriteRune(unicode.ToLower(lastUpper))
		}

		// Buffer uppercase char, do not output it yet as a delimiter may be required if the
		// next character is lowercase.
		if isUpper {
			multipleUpper = (lastUpper != 0)
			lastUpper = c
			continue
		}

		ret.WriteRune(c)
		lastUpper = 0
		beforeUpper = c
		multipleUpper = false
	}

	if lastUpper != 0 {
		ret.WriteRune(unicode.ToLower(lastUpper))
	}
	return string(ret.Bytes())
}

func (SnakeCaseFieldNamer) GetJSONFieldName(t reflect.Type, f reflect.StructField) string {
	jsonName := strings.Split(f.Tag.Get("json"), ",")[0]
	if jsonName != "" {
		return jsonName
	}

	return camelToSnake(f.Name)
}

func joinFunctionNameParts(keepFirst bool, parts ...string) string {
	buf := bytes.NewBufferString("")
	for i, part := range parts {
		if i == 0 && keepFirst {
			buf.WriteString(part)
		} else {
			if len(part) > 0 {
				buf.WriteString(strings.ToUpper(string(part[0])))
			}
			if len(part) > 1 {
				buf.WriteString(part[1:])
			}
		}
	}
	return buf.String()
}
<commit_msg>fixed varname<commit_after>package gen

import (
	"bytes"
	"fmt"
	"hash/fnv"
	"io"
	"path"
	"reflect"
	"sort"
	"strconv"
	"strings"
	"unicode"
)

const pkgWriter = "github.com/mailru/easyjson/jwriter"
const pkgLexer = "github.com/mailru/easyjson/jlexer"
const pkgEasyJSON = "github.com/mailru/easyjson"

// FieldNamer defines a policy for generating names for struct fields.
type FieldNamer interface {
	GetJSONFieldName(t reflect.Type, f reflect.StructField) string
}

// Generator generates the requested marshaler/unmarshalers.
type Generator struct {
	out *bytes.Buffer

	pkgName    string
	pkgPath    string
	buildTags  string
	hashString string

	varCounter int

	noStdMarshalers bool
	omitEmpty       bool
	fieldNamer      FieldNamer

	// package path to local alias map for tracking imports
	imports map[string]string

	// types that marshalers were requested for by user
	marshalers map[reflect.Type]bool

	// types that encoders were already generated for
	typesSeen map[reflect.Type]bool

	// types that encoders were requested for (e.g. by encoders of other types)
	typesUnseen []reflect.Type

	// function name to relevant type maps to track names of de-/encoders in
	// case of a name clash or unnamed structs
	functionNames map[string]reflect.Type
}

// NewGenerator initializes and returns a Generator.
func NewGenerator(filename string) *Generator {
	ret := &Generator{
		imports: map[string]string{
			pkgWriter:       "jwriter",
			pkgLexer:        "jlexer",
			pkgEasyJSON:     "easyjson",
			"encoding/json": "json",
		},
		fieldNamer:    DefaultFieldNamer{},
		marshalers:    make(map[reflect.Type]bool),
		typesSeen:     make(map[reflect.Type]bool),
		functionNames: make(map[string]reflect.Type),
	}

	// Use a file-unique prefix on all auxiliary funcs to avoid
	// name clashes.
	hash := fnv.New32()
	hash.Write([]byte(filename))
	ret.hashString = fmt.Sprintf("%x", hash.Sum32())

	return ret
}

// SetPkg sets the name and path of output package.
func (g *Generator) SetPkg(name, path string) {
	g.pkgName = name
	g.pkgPath = path
}

// SetBuildTags sets build tags for the output file.
func (g *Generator) SetBuildTags(tags string) {
	g.buildTags = tags
}

// SetFieldNamer sets field naming strategy.
func (g *Generator) SetFieldNamer(n FieldNamer) {
	g.fieldNamer = n
}

// UseSnakeCase sets snake_case field naming strategy.
func (g *Generator) UseSnakeCase() {
	g.fieldNamer = SnakeCaseFieldNamer{}
}

// NoStdMarshalers instructs not to generate standard MarshalJSON/UnmarshalJSON
// methods (only the custom interface).
func (g *Generator) NoStdMarshalers() {
	g.noStdMarshalers = true
}

// OmitEmpty triggers `json=",omitempty"` behaviour by default.
func (g *Generator) OmitEmpty() {
	g.omitEmpty = true
}

// addTypes requests to generate encoding/decoding funcs for the given type.
func (g *Generator) addType(t reflect.Type) {
	if g.typesSeen[t] {
		return
	}
	for _, t1 := range g.typesUnseen {
		if t1 == t {
			return
		}
	}
	g.typesUnseen = append(g.typesUnseen, t)
}

// Add requests to generate marshaler/unmarshalers and encoding/decoding
// funcs for the type of given object.
func (g *Generator) Add(obj interface{}) {
	t := reflect.TypeOf(obj)
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	g.addType(t)
	g.marshalers[t] = true
}

// printHeader prints package declaration and imports.
func (g *Generator) printHeader() {
	if g.buildTags != "" {
		fmt.Println("// +build ", g.buildTags)
		fmt.Println()
	}
	fmt.Println("// AUTOGENERATED FILE: easyjson marshaler/unmarshalers.")
	fmt.Println()
	fmt.Println("package ", g.pkgName)
	fmt.Println()

	byAlias := map[string]string{}
	var aliases []string
	for path, alias := range g.imports {
		aliases = append(aliases, alias)
		byAlias[alias] = path
	}

	sort.Strings(aliases)
	fmt.Println("import (")
	for _, alias := range aliases {
		fmt.Printf("  %s %q\n", alias, byAlias[alias])
	}

	fmt.Println(")")
	fmt.Println("")
	fmt.Println("// suppress unused package warning")
	fmt.Println("var (")
	fmt.Println("   _ *json.RawMessage")
	fmt.Println("   _ *jlexer.Lexer")
	fmt.Println("   _ *jwriter.Writer")
	fmt.Println("   _ easyjson.Marshaler")
	fmt.Println(")")

	fmt.Println()
}

// Run runs the generator and outputs generated code to out.
func (g *Generator) Run(out io.Writer) error {
	g.out = &bytes.Buffer{}

	for len(g.typesUnseen) > 0 {
		t := g.typesUnseen[len(g.typesUnseen)-1]
		g.typesUnseen = g.typesUnseen[:len(g.typesUnseen)-1]
		g.typesSeen[t] = true

		if err := g.genDecoder(t); err != nil {
			return err
		}
		if err := g.genEncoder(t); err != nil {
			return err
		}

		if !g.marshalers[t] {
			continue
		}

		if err := g.genStructMarshaler(t); err != nil {
			return err
		}
		if err := g.genStructUnmarshaler(t); err != nil {
			return err
		}
	}
	g.printHeader()
	_, err := out.Write(g.out.Bytes())
	return err
}

// fixes vendored paths
func fixPkgPathVendoring(pkgPath string) string {
	const vendor = "/vendor/"
	if i := strings.LastIndex(pkgPath, vendor); i != -1 {
		return pkgPath[i+len(vendor):]
	}
	return pkgPath
}

func fixAliasName(alias string) string {
	alias = strings.Replace(
		strings.Replace(alias, ".", "_", -1),
		"-",
		"_",
		-1,
	)
	return alias
}

// pkgAlias creates and returns and import alias for a given package.
func (g *Generator) pkgAlias(pkgPath string) string {
	pkgPath = fixPkgPathVendoring(pkgPath)
	if alias := g.imports[pkgPath]; alias != "" {
		return alias
	}

	for i := 0; ; i++ {
		alias := fixAliasName(path.Base(pkgPath))
		if i > 0 {
			alias += fmt.Sprint(i)
		}

		exists := false
		for _, v := range g.imports {
			if v == alias {
				exists = true
				break
			}
		}

		if !exists {
			g.imports[pkgPath] = alias
			return alias
		}
	}
}

// getType return the textual type name of given type that can be used in generated code.
func (g *Generator) getType(t reflect.Type) string {
	if t.Name() == "" {
		switch t.Kind() {
		case reflect.Ptr:
			return "*" + g.getType(t.Elem())
		case reflect.Slice:
			return "[]" + g.getType(t.Elem())
		case reflect.Array:
			return "[" + strconv.Itoa(t.Len()) + "]" + g.getType(t.Elem())
		case reflect.Map:
			return "map[" + g.getType(t.Key()) + "]" + g.getType(t.Elem())
		}
	}

	if t.Name() == "" || t.PkgPath() == "" {
		if t.Kind() == reflect.Struct {
			// the fields of an anonymous struct can have named types,
			// and t.String() will not be sufficient because it does not
			// remove the package name when it matches g.pkgPath.
			// so we convert by hand
			nf := t.NumField()
			lines := make([]string, 0, nf)
			for i := 0; i < nf; i++ {
				f := t.Field(i)
				line := f.Name + " " + g.getType(f.Type)
				t := f.Tag
				if t != "" {
					line += " " + escapeTag(t)
				}
				lines = append(lines, line)
			}
			return strings.Join([]string{"struct { ", strings.Join(lines, "; "), " }"}, "")
		}
		return t.String()
	} else if t.PkgPath() == g.pkgPath {
		return t.Name()
	}
	return g.pkgAlias(t.PkgPath()) + "." + t.Name()
}

// escape a struct field tag string back to source code
func escapeTag(tag reflect.StructTag) string {
	t := string(tag)
	if strings.ContainsRune(t, '`') {
		// there are ` in the string; we can't use ` to enclose the string
		return strconv.Quote(t)
	}
	return "`" + t + "`"
}

// uniqueVarName returns a file-unique name that can be used for generated variables.
func (g *Generator) uniqueVarName() string {
	g.varCounter++
	return fmt.Sprint("v", g.varCounter)
}

// safeName escapes unsafe characters in pkg/type name and returns a string that can be used
// in encoder/decoder names for the type.
func (g *Generator) safeName(t reflect.Type) string {
	name := t.PkgPath()
	if t.Name() == "" {
		name += "anonymous"
	} else {
		name += "." + t.Name()
	}

	parts := []string{}
	part := []rune{}
	for _, c := range name {
		if unicode.IsLetter(c) || unicode.IsDigit(c) {
			part = append(part, c)
		} else if len(part) > 0 {
			parts = append(parts, string(part))
			part = []rune{}
		}
	}
	return joinFunctionNameParts(false, parts...)
}

// functionName returns a function name for a given type with a given prefix. If a function
// with this prefix already exists for a type, it is returned.
//
// Method is used to track encoder/decoder names for the type.
func (g *Generator) functionName(prefix string, t reflect.Type) string {
	prefix = joinFunctionNameParts(true, "easyjson", g.hashString, prefix)
	name := joinFunctionNameParts(true, prefix, g.safeName(t))

	// Most of the names will be unique, try a shortcut first.
	if e, ok := g.functionNames[name]; !ok || e == t {
		g.functionNames[name] = t
		return name
	}

	// Search if the function already exists.
	for name1, t1 := range g.functionNames {
		if t1 == t && strings.HasPrefix(name1, prefix) {
			return name1
		}
	}

	// Create a new name in the case of a clash.
	for i := 1; ; i++ {
		nm := fmt.Sprint(name, i)
		if _, ok := g.functionNames[nm]; ok {
			continue
		}
		g.functionNames[nm] = t
		return nm
	}
}

// DefaultFieldsNamer implements trivial naming policy equivalent to encoding/json.
type DefaultFieldNamer struct{}

func (DefaultFieldNamer) GetJSONFieldName(t reflect.Type, f reflect.StructField) string {
	jsonName := strings.Split(f.Tag.Get("json"), ",")[0]
	if jsonName != "" {
		return jsonName
	} else {
		return f.Name
	}
}

// SnakeCaseFieldNamer implements CamelCase to snake_case conversion for fields names.
type SnakeCaseFieldNamer struct{}

func camelToSnake(name string) string {
	var ret bytes.Buffer

	multipleUpper := false
	var lastUpper rune
	var beforeUpper rune

	for _, c := range name {
		// Non-lowercase character after uppercase is considered to be uppercase too.
		isUpper := (unicode.IsUpper(c) || (lastUpper != 0 && !unicode.IsLower(c)))

		if lastUpper != 0 {
			// Output a delimiter if last character was either the first uppercase character
			// in a row, or the last one in a row (e.g. 'S' in "HTTPServer").
			// Do not output a delimiter at the beginning of the name.

			firstInRow := !multipleUpper
			lastInRow := !isUpper

			if ret.Len() > 0 && (firstInRow || lastInRow) && beforeUpper != '_' {
				ret.WriteByte('_')
			}
			ret.WriteRune(unicode.ToLower(lastUpper))
		}

		// Buffer uppercase char, do not output it yet as a delimiter may be required if the
		// next character is lowercase.
		if isUpper {
			multipleUpper = (lastUpper != 0)
			lastUpper = c
			continue
		}

		ret.WriteRune(c)
		lastUpper = 0
		beforeUpper = c
		multipleUpper = false
	}

	if lastUpper != 0 {
		ret.WriteRune(unicode.ToLower(lastUpper))
	}
	return string(ret.Bytes())
}

func (SnakeCaseFieldNamer) GetJSONFieldName(t reflect.Type, f reflect.StructField) string {
	jsonName := strings.Split(f.Tag.Get("json"), ",")[0]
	if jsonName != "" {
		return jsonName
	}

	return camelToSnake(f.Name)
}

func joinFunctionNameParts(keepFirst bool, parts ...string) string {
	buf := bytes.NewBufferString("")
	for i, part := range parts {
		if i == 0 && keepFirst {
			buf.WriteString(part)
		} else {
			if len(part) > 0 {
				buf.WriteString(strings.ToUpper(string(part[0])))
			}
			if len(part) > 1 {
				buf.WriteString(part[1:])
			}
		}
	}
	return buf.String()
}
<|endoftext|>


<commit_before>package amazonimport

import (
	"fmt"
	"log"
	"os"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"
	awscommon "github.com/hashicorp/packer/builder/amazon/common"
	"github.com/hashicorp/packer/common"
	"github.com/hashicorp/packer/helper/config"
	"github.com/hashicorp/packer/packer"
	"github.com/hashicorp/packer/template/interpolate"
)

const BuilderId = "packer.post-processor.amazon-import"

// Configuration of this post processor
type Config struct {
	common.PackerConfig    `mapstructure:",squash"`
	awscommon.AccessConfig `mapstructure:",squash"`

	// Variables specific to this post processor
	S3Bucket    string            `mapstructure:"s3_bucket_name"`
	S3Key       string            `mapstructure:"s3_key_name"`
	SkipClean   bool              `mapstructure:"skip_clean"`
	Tags        map[string]string `mapstructure:"tags"`
	Name        string            `mapstructure:"ami_name"`
	Description string            `mapstructure:"ami_description"`
	Users       []string          `mapstructure:"ami_users"`
	Groups      []string          `mapstructure:"ami_groups"`
	LicenseType string            `mapstructure:"license_type"`
	RoleName    string            `mapstructure:"role_name"`

	ctx interpolate.Context
}

type PostProcessor struct {
	config Config
}

// Entry point for configuration parsing when we've defined
func (p *PostProcessor) Configure(raws ...interface{}) error {
	p.config.ctx.Funcs = awscommon.TemplateFuncs
	err := config.Decode(&p.config, &config.DecodeOpts{
		Interpolate:        true,
		InterpolateContext: &p.config.ctx,
		InterpolateFilter: &interpolate.RenderFilter{
			Exclude: []string{
				"s3_key_name",
			},
		},
	}, raws...)
	if err != nil {
		return err
	}

	// Set defaults
	if p.config.S3Key == "" {
		p.config.S3Key = "packer-import-{{timestamp}}.ova"
	}

	errs := new(packer.MultiError)

	// Check and render s3_key_name
	if err = interpolate.Validate(p.config.S3Key, &p.config.ctx); err != nil {
		errs = packer.MultiErrorAppend(
			errs, fmt.Errorf("Error parsing s3_key_name template: %s", err))
	}

	// Check we have AWS access variables defined somewhere
	errs = packer.MultiErrorAppend(errs, p.config.AccessConfig.Prepare(&p.config.ctx)...)

	// define all our required parameters
	templates := map[string]*string{
		"s3_bucket_name": &p.config.S3Bucket,
	}
	// Check out required params are defined
	for key, ptr := range templates {
		if *ptr == "" {
			errs = packer.MultiErrorAppend(
				errs, fmt.Errorf("%s must be set", key))
		}
	}

	// Anything which flagged return back up the stack
	if len(errs.Errors) > 0 {
		return errs
	}

	packer.LogSecretFilter.Set(p.config.AccessKey, p.config.SecretKey, p.config.Token)
	log.Println(p.config)
	return nil
}

func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) {
	var err error

	session, err := p.config.Session()
	if err != nil {
		return nil, false, err
	}
	config := session.Config

	// Render this key since we didn't in the configure phase
	p.config.S3Key, err = interpolate.Render(p.config.S3Key, &p.config.ctx)
	if err != nil {
		return nil, false, fmt.Errorf("Error rendering s3_key_name template: %s", err)
	}
	log.Printf("Rendered s3_key_name as %s", p.config.S3Key)

	log.Println("Looking for OVA in artifact")
	// Locate the files output from the builder
	source := ""
	for _, path := range artifact.Files() {
		if strings.HasSuffix(path, ".ova") {
			source = path
			break
		}
	}

	// Hope we found something useful
	if source == "" {
		return nil, false, fmt.Errorf("No OVA file found in artifact from builder")
	}

	// open the source file
	log.Printf("Opening file %s to upload", source)
	file, err := os.Open(source)
	if err != nil {
		return nil, false, fmt.Errorf("Failed to open %s: %s", source, err)
	}

	ui.Message(fmt.Sprintf("Uploading %s to s3://%s/%s", source, p.config.S3Bucket, p.config.S3Key))

	// Copy the OVA file into the S3 bucket specified
	uploader := s3manager.NewUploader(session)
	_, err = uploader.Upload(&s3manager.UploadInput{
		Body:   file,
		Bucket: &p.config.S3Bucket,
		Key:    &p.config.S3Key,
	})
	if err != nil {
		return nil, false, fmt.Errorf("Failed to upload %s: %s", source, err)
	}

	// May as well stop holding this open now
	file.Close()

	ui.Message(fmt.Sprintf("Completed upload of %s to s3://%s/%s", source, p.config.S3Bucket, p.config.S3Key))

	// Call EC2 image import process
	log.Printf("Calling EC2 to import from s3://%s/%s", p.config.S3Bucket, p.config.S3Key)

	ec2conn := ec2.New(session)
	params := &ec2.ImportImageInput{
		DiskContainers: []*ec2.ImageDiskContainer{
			{
				UserBucket: &ec2.UserBucket{
					S3Bucket: &p.config.S3Bucket,
					S3Key:    &p.config.S3Key,
				},
			},
		},
	}

	if p.config.RoleName != "" {
		params.SetRoleName(p.config.RoleName)
	}

	if p.config.LicenseType != "" {
		ui.Message(fmt.Sprintf("Setting license type to '%s'", p.config.LicenseType))
		params.LicenseType = &p.config.LicenseType
	}

	import_start, err := ec2conn.ImportImage(params)

	if err != nil {
		return nil, false, fmt.Errorf("Failed to start import from s3://%s/%s: %s", p.config.S3Bucket, p.config.S3Key, err)
	}

	ui.Message(fmt.Sprintf("Started import of s3://%s/%s, task id %s", p.config.S3Bucket, p.config.S3Key, *import_start.ImportTaskId))

	// Wait for import process to complete, this takes a while
	ui.Message(fmt.Sprintf("Waiting for task %s to complete (may take a while)", *import_start.ImportTaskId))
	err = awscommon.WaitUntilImageImported(aws.BackgroundContext(), ec2conn, *import_start.ImportTaskId)
	if err != nil {
		return nil, false, fmt.Errorf("Import task %s failed with error: %s", *import_start.ImportTaskId, err)
	}

	// Retrieve what the outcome was for the import task
	import_result, err := ec2conn.DescribeImportImageTasks(&ec2.DescribeImportImageTasksInput{
		ImportTaskIds: []*string{
			import_start.ImportTaskId,
		},
	})

	if err != nil {
		return nil, false, fmt.Errorf("Failed to find import task %s: %s", *import_start.ImportTaskId, err)
	}

	// Check it was actually completed
	if *import_result.ImportImageTasks[0].Status != "completed" {
		// The most useful error message is from the job itself
		return nil, false, fmt.Errorf("Import task %s failed: %s", *import_start.ImportTaskId, *import_result.ImportImageTasks[0].StatusMessage)
	}

	ui.Message(fmt.Sprintf("Import task %s complete", *import_start.ImportTaskId))

	// Pull AMI ID out of the completed job
	createdami := *import_result.ImportImageTasks[0].ImageId

	if p.config.Name != "" {

		ui.Message(fmt.Sprintf("Starting rename of AMI (%s)", createdami))

		resp, err := ec2conn.CopyImage(&ec2.CopyImageInput{
			Name:          &p.config.Name,
			SourceImageId: &createdami,
			SourceRegion:  config.Region,
		})

		if err != nil {
			return nil, false, fmt.Errorf("Error Copying AMI (%s): %s", createdami, err)
		}

		ui.Message(fmt.Sprintf("Waiting for AMI rename to complete (may take a while)"))

		if err := awscommon.WaitUntilAMIAvailable(aws.BackgroundContext(), ec2conn, *resp.ImageId); err != nil {
			return nil, false, fmt.Errorf("Error waiting for AMI (%s): %s", *resp.ImageId, err)
		}

		_, err = ec2conn.DeregisterImage(&ec2.DeregisterImageInput{
			ImageId: &createdami,
		})

		if err != nil {
			return nil, false, fmt.Errorf("Error deregistering existing AMI: %s", err)
		}

		ui.Message(fmt.Sprintf("AMI rename completed"))

		createdami = *resp.ImageId
	}

	// If we have tags, then apply them now to both the AMI and snaps
	// created by the import
	if len(p.config.Tags) > 0 {
		var ec2Tags []*ec2.Tag

		log.Printf("Repacking tags into AWS format")

		for key, value := range p.config.Tags {
			ui.Message(fmt.Sprintf("Adding tag \"%s\": \"%s\"", key, value))
			ec2Tags = append(ec2Tags, &ec2.Tag{
				Key:   aws.String(key),
				Value: aws.String(value),
			})
		}

		resourceIds := []*string{&createdami}

		log.Printf("Getting details of %s", createdami)

		imageResp, err := ec2conn.DescribeImages(&ec2.DescribeImagesInput{
			ImageIds: resourceIds,
		})

		if err != nil {
			return nil, false, fmt.Errorf("Failed to retrieve details for AMI %s: %s", createdami, err)
		}

		if len(imageResp.Images) == 0 {
			return nil, false, fmt.Errorf("AMI %s has no images", createdami)
		}

		image := imageResp.Images[0]

		log.Printf("Walking block device mappings for %s to find snapshots", createdami)

		for _, device := range image.BlockDeviceMappings {
			if device.Ebs != nil && device.Ebs.SnapshotId != nil {
				ui.Message(fmt.Sprintf("Tagging snapshot %s", *device.Ebs.SnapshotId))
				resourceIds = append(resourceIds, device.Ebs.SnapshotId)
			}
		}

		ui.Message(fmt.Sprintf("Tagging AMI %s", createdami))

		_, err = ec2conn.CreateTags(&ec2.CreateTagsInput{
			Resources: resourceIds,
			Tags:      ec2Tags,
		})

		if err != nil {
			return nil, false, fmt.Errorf("Failed to add tags to resources %#v: %s", resourceIds, err)
		}

	}

	// Apply attributes for AMI specified in config
	// (duped from builder/amazon/common/step_modify_ami_attributes.go)
	options := make(map[string]*ec2.ModifyImageAttributeInput)
	if p.config.Description != "" {
		options["description"] = &ec2.ModifyImageAttributeInput{
			Description: &ec2.AttributeValue{Value: &p.config.Description},
		}
	}

	if len(p.config.Groups) > 0 {
		groups := make([]*string, len(p.config.Groups))
		adds := make([]*ec2.LaunchPermission, len(p.config.Groups))
		addGroups := &ec2.ModifyImageAttributeInput{
			LaunchPermission: &ec2.LaunchPermissionModifications{},
		}

		for i, g := range p.config.Groups {
			groups[i] = aws.String(g)
			adds[i] = &ec2.LaunchPermission{
				Group: aws.String(g),
			}
		}
		addGroups.UserGroups = groups
		addGroups.LaunchPermission.Add = adds

		options["groups"] = addGroups
	}

	if len(p.config.Users) > 0 {
		users := make([]*string, len(p.config.Users))
		adds := make([]*ec2.LaunchPermission, len(p.config.Users))
		for i, u := range p.config.Users {
			users[i] = aws.String(u)
			adds[i] = &ec2.LaunchPermission{UserId: aws.String(u)}
		}
		options["users"] = &ec2.ModifyImageAttributeInput{
			UserIds: users,
			LaunchPermission: &ec2.LaunchPermissionModifications{
				Add: adds,
			},
		}
	}

	if len(options) > 0 {
		for name, input := range options {
			ui.Message(fmt.Sprintf("Modifying: %s", name))
			input.ImageId = &createdami
			_, err := ec2conn.ModifyImageAttribute(input)
			if err != nil {
				return nil, false, fmt.Errorf("Error modifying AMI attributes: %s", err)
			}
		}
	}

	// Add the reported AMI ID to the artifact list
	log.Printf("Adding created AMI ID %s in region %s to output artifacts", createdami, *config.Region)
	artifact = &awscommon.Artifact{
		Amis: map[string]string{
			*config.Region: createdami,
		},
		BuilderIdValue: BuilderId,
		Session:        session,
	}

	if !p.config.SkipClean {
		ui.Message(fmt.Sprintf("Deleting import source s3://%s/%s", p.config.S3Bucket, p.config.S3Key))
		s3conn := s3.New(session)
		_, err = s3conn.DeleteObject(&s3.DeleteObjectInput{
			Bucket: &p.config.S3Bucket,
			Key:    &p.config.S3Key,
		})
		if err != nil {
			return nil, false, fmt.Errorf("Failed to delete s3://%s/%s: %s", p.config.S3Bucket, p.config.S3Key, err)
		}
	}

	return artifact, false, nil
}
<commit_msg>Support formats other than OVA.<commit_after>package amazonimport

import (
	"fmt"
	"log"
	"os"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"
	awscommon "github.com/hashicorp/packer/builder/amazon/common"
	"github.com/hashicorp/packer/common"
	"github.com/hashicorp/packer/helper/config"
	"github.com/hashicorp/packer/packer"
	"github.com/hashicorp/packer/template/interpolate"
)

const BuilderId = "packer.post-processor.amazon-import"

// Configuration of this post processor
type Config struct {
	common.PackerConfig    `mapstructure:",squash"`
	awscommon.AccessConfig `mapstructure:",squash"`

	// Variables specific to this post processor
	S3Bucket    string            `mapstructure:"s3_bucket_name"`
	S3Key       string            `mapstructure:"s3_key_name"`
	SkipClean   bool              `mapstructure:"skip_clean"`
	Tags        map[string]string `mapstructure:"tags"`
	Name        string            `mapstructure:"ami_name"`
	Description string            `mapstructure:"ami_description"`
	Users       []string          `mapstructure:"ami_users"`
	Groups      []string          `mapstructure:"ami_groups"`
	LicenseType string            `mapstructure:"license_type"`
	RoleName    string            `mapstructure:"role_name"`
	Format      string            `mapstructure:"format"`

	ctx interpolate.Context
}

type PostProcessor struct {
	config Config
}

// Entry point for configuration parsing when we've defined
func (p *PostProcessor) Configure(raws ...interface{}) error {
	p.config.ctx.Funcs = awscommon.TemplateFuncs
	err := config.Decode(&p.config, &config.DecodeOpts{
		Interpolate:        true,
		InterpolateContext: &p.config.ctx,
		InterpolateFilter: &interpolate.RenderFilter{
			Exclude: []string{
				"s3_key_name",
			},
		},
	}, raws...)
	if err != nil {
		return err
	}

	// Set defaults
	if p.config.Format == "" {
		p.config.Format = "ova"
	}

	if p.config.S3Key == "" {
		p.config.S3Key = "packer-import-{{timestamp}}." + p.config.Format
	}

	errs := new(packer.MultiError)

	// Check and render s3_key_name
	if err = interpolate.Validate(p.config.S3Key, &p.config.ctx); err != nil {
		errs = packer.MultiErrorAppend(
			errs, fmt.Errorf("Error parsing s3_key_name template: %s", err))
	}

	// Check we have AWS access variables defined somewhere
	errs = packer.MultiErrorAppend(errs, p.config.AccessConfig.Prepare(&p.config.ctx)...)

	// define all our required parameters
	templates := map[string]*string{
		"s3_bucket_name": &p.config.S3Bucket,
	}
	// Check out required params are defined
	for key, ptr := range templates {
		if *ptr == "" {
			errs = packer.MultiErrorAppend(
				errs, fmt.Errorf("%s must be set", key))
		}
	}

	if !(p.config.Format == "ova" || p.config.Format == "raw" || p.config.Format == "vmdk" || p.config.Format == "vhd" || p.config.Format == "vhdx") {
		errs = packer.MultiErrorAppend(
			errs, fmt.Errorf("invalid format '%s'. Only 'ova', 'raw', 'vhd', 'vhdx', or 'vmdk' are allowed", p.config.Format))
	}

	// Anything which flagged return back up the stack
	if len(errs.Errors) > 0 {
		return errs
	}

	packer.LogSecretFilter.Set(p.config.AccessKey, p.config.SecretKey, p.config.Token)
	log.Println(p.config)
	return nil
}

func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) {
	var err error

	session, err := p.config.Session()
	if err != nil {
		return nil, false, err
	}
	config := session.Config

	// Render this key since we didn't in the configure phase
	p.config.S3Key, err = interpolate.Render(p.config.S3Key, &p.config.ctx)
	if err != nil {
		return nil, false, fmt.Errorf("Error rendering s3_key_name template: %s", err)
	}
	log.Printf("Rendered s3_key_name as %s", p.config.S3Key)

	log.Println("Looking for image in artifact")
	// Locate the files output from the builder
	source := ""
	for _, path := range artifact.Files() {
		if strings.HasSuffix(path, "."+p.config.Format) {
			source = path
			break
		}
	}

	// Hope we found something useful
	if source == "" {
		return nil, false, fmt.Errorf("No %s image file found in artifact from builder", p.config.Format)
	}

	// open the source file
	log.Printf("Opening file %s to upload", source)
	file, err := os.Open(source)
	if err != nil {
		return nil, false, fmt.Errorf("Failed to open %s: %s", source, err)
	}

	ui.Message(fmt.Sprintf("Uploading %s to s3://%s/%s", source, p.config.S3Bucket, p.config.S3Key))

	// Copy the image file into the S3 bucket specified
	uploader := s3manager.NewUploader(session)
	_, err = uploader.Upload(&s3manager.UploadInput{
		Body:   file,
		Bucket: &p.config.S3Bucket,
		Key:    &p.config.S3Key,
	})
	if err != nil {
		return nil, false, fmt.Errorf("Failed to upload %s: %s", source, err)
	}

	// May as well stop holding this open now
	file.Close()

	ui.Message(fmt.Sprintf("Completed upload of %s to s3://%s/%s", source, p.config.S3Bucket, p.config.S3Key))

	// Call EC2 image import process
	log.Printf("Calling EC2 to import from s3://%s/%s", p.config.S3Bucket, p.config.S3Key)

	ec2conn := ec2.New(session)
	params := &ec2.ImportImageInput{
		DiskContainers: []*ec2.ImageDiskContainer{
			{
				Format: &p.config.Format,
				UserBucket: &ec2.UserBucket{
					S3Bucket: &p.config.S3Bucket,
					S3Key:    &p.config.S3Key,
				},
			},
		},
	}

	if p.config.RoleName != "" {
		params.SetRoleName(p.config.RoleName)
	}

	if p.config.LicenseType != "" {
		ui.Message(fmt.Sprintf("Setting license type to '%s'", p.config.LicenseType))
		params.LicenseType = &p.config.LicenseType
	}

	import_start, err := ec2conn.ImportImage(params)

	if err != nil {
		return nil, false, fmt.Errorf("Failed to start import from s3://%s/%s: %s", p.config.S3Bucket, p.config.S3Key, err)
	}

	ui.Message(fmt.Sprintf("Started import of s3://%s/%s, task id %s", p.config.S3Bucket, p.config.S3Key, *import_start.ImportTaskId))

	// Wait for import process to complete, this takes a while
	ui.Message(fmt.Sprintf("Waiting for task %s to complete (may take a while)", *import_start.ImportTaskId))
	err = awscommon.WaitUntilImageImported(aws.BackgroundContext(), ec2conn, *import_start.ImportTaskId)
	if err != nil {
		return nil, false, fmt.Errorf("Import task %s failed with error: %s", *import_start.ImportTaskId, err)
	}

	// Retrieve what the outcome was for the import task
	import_result, err := ec2conn.DescribeImportImageTasks(&ec2.DescribeImportImageTasksInput{
		ImportTaskIds: []*string{
			import_start.ImportTaskId,
		},
	})

	if err != nil {
		return nil, false, fmt.Errorf("Failed to find import task %s: %s", *import_start.ImportTaskId, err)
	}

	// Check it was actually completed
	if *import_result.ImportImageTasks[0].Status != "completed" {
		// The most useful error message is from the job itself
		return nil, false, fmt.Errorf("Import task %s failed: %s", *import_start.ImportTaskId, *import_result.ImportImageTasks[0].StatusMessage)
	}

	ui.Message(fmt.Sprintf("Import task %s complete", *import_start.ImportTaskId))

	// Pull AMI ID out of the completed job
	createdami := *import_result.ImportImageTasks[0].ImageId

	if p.config.Name != "" {

		ui.Message(fmt.Sprintf("Starting rename of AMI (%s)", createdami))

		resp, err := ec2conn.CopyImage(&ec2.CopyImageInput{
			Name:          &p.config.Name,
			SourceImageId: &createdami,
			SourceRegion:  config.Region,
		})

		if err != nil {
			return nil, false, fmt.Errorf("Error Copying AMI (%s): %s", createdami, err)
		}

		ui.Message(fmt.Sprintf("Waiting for AMI rename to complete (may take a while)"))

		if err := awscommon.WaitUntilAMIAvailable(aws.BackgroundContext(), ec2conn, *resp.ImageId); err != nil {
			return nil, false, fmt.Errorf("Error waiting for AMI (%s): %s", *resp.ImageId, err)
		}

		_, err = ec2conn.DeregisterImage(&ec2.DeregisterImageInput{
			ImageId: &createdami,
		})

		if err != nil {
			return nil, false, fmt.Errorf("Error deregistering existing AMI: %s", err)
		}

		ui.Message(fmt.Sprintf("AMI rename completed"))

		createdami = *resp.ImageId
	}

	// If we have tags, then apply them now to both the AMI and snaps
	// created by the import
	if len(p.config.Tags) > 0 {
		var ec2Tags []*ec2.Tag

		log.Printf("Repacking tags into AWS format")

		for key, value := range p.config.Tags {
			ui.Message(fmt.Sprintf("Adding tag \"%s\": \"%s\"", key, value))
			ec2Tags = append(ec2Tags, &ec2.Tag{
				Key:   aws.String(key),
				Value: aws.String(value),
			})
		}

		resourceIds := []*string{&createdami}

		log.Printf("Getting details of %s", createdami)

		imageResp, err := ec2conn.DescribeImages(&ec2.DescribeImagesInput{
			ImageIds: resourceIds,
		})

		if err != nil {
			return nil, false, fmt.Errorf("Failed to retrieve details for AMI %s: %s", createdami, err)
		}

		if len(imageResp.Images) == 0 {
			return nil, false, fmt.Errorf("AMI %s has no images", createdami)
		}

		image := imageResp.Images[0]

		log.Printf("Walking block device mappings for %s to find snapshots", createdami)

		for _, device := range image.BlockDeviceMappings {
			if device.Ebs != nil && device.Ebs.SnapshotId != nil {
				ui.Message(fmt.Sprintf("Tagging snapshot %s", *device.Ebs.SnapshotId))
				resourceIds = append(resourceIds, device.Ebs.SnapshotId)
			}
		}

		ui.Message(fmt.Sprintf("Tagging AMI %s", createdami))

		_, err = ec2conn.CreateTags(&ec2.CreateTagsInput{
			Resources: resourceIds,
			Tags:      ec2Tags,
		})

		if err != nil {
			return nil, false, fmt.Errorf("Failed to add tags to resources %#v: %s", resourceIds, err)
		}

	}

	// Apply attributes for AMI specified in config
	// (duped from builder/amazon/common/step_modify_ami_attributes.go)
	options := make(map[string]*ec2.ModifyImageAttributeInput)
	if p.config.Description != "" {
		options["description"] = &ec2.ModifyImageAttributeInput{
			Description: &ec2.AttributeValue{Value: &p.config.Description},
		}
	}

	if len(p.config.Groups) > 0 {
		groups := make([]*string, len(p.config.Groups))
		adds := make([]*ec2.LaunchPermission, len(p.config.Groups))
		addGroups := &ec2.ModifyImageAttributeInput{
			LaunchPermission: &ec2.LaunchPermissionModifications{},
		}

		for i, g := range p.config.Groups {
			groups[i] = aws.String(g)
			adds[i] = &ec2.LaunchPermission{
				Group: aws.String(g),
			}
		}
		addGroups.UserGroups = groups
		addGroups.LaunchPermission.Add = adds

		options["groups"] = addGroups
	}

	if len(p.config.Users) > 0 {
		users := make([]*string, len(p.config.Users))
		adds := make([]*ec2.LaunchPermission, len(p.config.Users))
		for i, u := range p.config.Users {
			users[i] = aws.String(u)
			adds[i] = &ec2.LaunchPermission{UserId: aws.String(u)}
		}
		options["users"] = &ec2.ModifyImageAttributeInput{
			UserIds: users,
			LaunchPermission: &ec2.LaunchPermissionModifications{
				Add: adds,
			},
		}
	}

	if len(options) > 0 {
		for name, input := range options {
			ui.Message(fmt.Sprintf("Modifying: %s", name))
			input.ImageId = &createdami
			_, err := ec2conn.ModifyImageAttribute(input)
			if err != nil {
				return nil, false, fmt.Errorf("Error modifying AMI attributes: %s", err)
			}
		}
	}

	// Add the reported AMI ID to the artifact list
	log.Printf("Adding created AMI ID %s in region %s to output artifacts", createdami, *config.Region)
	artifact = &awscommon.Artifact{
		Amis: map[string]string{
			*config.Region: createdami,
		},
		BuilderIdValue: BuilderId,
		Session:        session,
	}

	if !p.config.SkipClean {
		ui.Message(fmt.Sprintf("Deleting import source s3://%s/%s", p.config.S3Bucket, p.config.S3Key))
		s3conn := s3.New(session)
		_, err = s3conn.DeleteObject(&s3.DeleteObjectInput{
			Bucket: &p.config.S3Bucket,
			Key:    &p.config.S3Key,
		})
		if err != nil {
			return nil, false, fmt.Errorf("Failed to delete s3://%s/%s: %s", p.config.S3Bucket, p.config.S3Key, err)
		}
	}

	return artifact, false, nil
}
<|endoftext|>


<commit_before>package analysis

import (
	"database/sql"
	"sort"
	"time"

	"github.com/tsukanov/steamhistory/apps"
	"github.com/tsukanov/steamhistory/steam"
	"github.com/tsukanov/steamhistory/usage"
)

type peak struct {
	Count int       `json:"count"`
	Time  time.Time `json:"time"`
}

type appRow struct {
	App  steam.App `json:"app"`
	Peak peak      `json:"peak"`
}

type byPeak []appRow

func (a byPeak) Len() int           { return len(a) }
func (a byPeak) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a byPeak) Less(i, j int) bool { return a[i].Peak.Count > a[j].Peak.Count }

// MostPopularAppsToday function returns list of apps that had most users today
// (excluding app #0 - Steam Client).
func MostPopularAppsToday() ([]appRow, error) {
	applications, err := apps.AllUsableApps()
	if err != nil {
		return nil, err
	}

	var rows []appRow
	now := time.Now().UTC()
	yesterday := now.Add(-24 * time.Hour)
	for _, app := range applications {
		if app.ID == 0 {
			continue
		}
		count, tim, err := usage.GetPeakBetween(yesterday, now, app.ID)
		if err != nil {
			switch {
			case err == sql.ErrNoRows:
				continue
			default:
				return nil, err
			}
		}
		currentRow := appRow{
			App: app,
			Peak: peak{
				Count: count,
				Time:  tim,
			},
		}
		rows = append(rows, currentRow)
	}

	sort.Sort(byPeak(rows))

	if len(rows) <= 100 {
		return rows, nil
	}
	return rows[:100], nil
}
<commit_msg>Reduced number of items returned in the list of most popular apps.<commit_after>package analysis

import (
	"database/sql"
	"sort"
	"time"

	"github.com/tsukanov/steamhistory/apps"
	"github.com/tsukanov/steamhistory/steam"
	"github.com/tsukanov/steamhistory/usage"
)

type peak struct {
	Count int       `json:"count"`
	Time  time.Time `json:"time"`
}

type appRow struct {
	App  steam.App `json:"app"`
	Peak peak      `json:"peak"`
}

type byPeak []appRow

func (a byPeak) Len() int           { return len(a) }
func (a byPeak) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a byPeak) Less(i, j int) bool { return a[i].Peak.Count > a[j].Peak.Count }

// MostPopularAppsToday function returns list of 30 apps that had most users
// today (excluding app #0 - Steam Client).
func MostPopularAppsToday() ([]appRow, error) {
	applications, err := apps.AllUsableApps()
	if err != nil {
		return nil, err
	}

	var rows []appRow
	now := time.Now().UTC()
	yesterday := now.Add(-24 * time.Hour)
	for _, app := range applications {
		if app.ID == 0 {
			continue
		}
		count, tim, err := usage.GetPeakBetween(yesterday, now, app.ID)
		if err != nil {
			switch {
			case err == sql.ErrNoRows:
				continue
			default:
				return nil, err
			}
		}
		currentRow := appRow{
			App: app,
			Peak: peak{
				Count: count,
				Time:  tim,
			},
		}
		rows = append(rows, currentRow)
	}

	sort.Sort(byPeak(rows))

	if len(rows) <= 30 {
		return rows, nil
	}
	return rows[:30], nil
}
<|endoftext|>