<commit_before>package pi

import (
	"encoding/json"
	"encoding/xml"
	"fmt"
	"github.com/gocarina/formdata"
	"github.com/gorilla/schema"
	"html/template"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"strings"
)

var (
	decoderFormValues = schema.NewDecoder()

	// ErrNoFiles is the error when no files is present in the value provided when
	// calling RequestContext.GetFileHeaders.
	ErrNoFiles = fmt.Errorf("no files")

	// ErrContentTypeNotSupported is the error when the format of the Content-Type is not supported
	ErrContentTypeNotSupported = fmt.Errorf("format not supported")

	// ContentTypeJSON is the default MIME for JSON data.
	ContentTypeJSON = "application/json"

	// ContentTypeXML is the default MIME for XML data.
	ContentTypeXML = "application/xml"

	// ContentTypeClassicForm is the default MIME for Form Encoded data.
	ContentTypeClassicForm = "application/x-www-form-urlencoded"

	// ContentTypeMultipart is the default MIME for Webform.
	ContentTypeMultipart = "multipart/form-data"

	// ContentTypeText is the default MIME for Textual data.
	ContentTypeText = "text/plain"
)

// J is an helper to write JSON.
// Example:
//		c.WriteJSON(pi.J{"status": "OK"})
//
type J map[string]interface{}

// RequestContext represents the context of the HTTP request.
// It is shared across interceptors and handler.
type RequestContext struct {
	W        http.ResponseWriter
	R        *http.Request
	RouteURL string
	Data     map[interface{}]interface{}
}

// newRequestContext returns a new RequestContext.
func newRequestContext(w http.ResponseWriter, r *http.Request, routeURL string) *RequestContext {
	return &RequestContext{
		W:        w,
		R:        r,
		RouteURL: routeURL,
		Data:     make(map[interface{}]interface{}),
	}
}

// WriteString writes the specified strings to the ResponseWriter.
func (c *RequestContext) WriteString(strings ...string) error {
	for _, s := range strings {
		if _, err := c.W.Write([]byte(s)); err != nil {
			return err
		}
	}
	return nil
}

// WriteJSON marshal the object to JSON and writes it via the ResponseWriter.
func (c *RequestContext) WriteJSON(object interface{}) error {
	c.W.Header().Set("Content-Type", "application/json; charset=utf-8")
	if debugMode {
		output, err := json.MarshalIndent(object, "", "  ")
		if err != nil {
			return err
		}
		writeDebug("WriteJSON", c.R.RemoteAddr, string(output))
		c.W.Write(output)
	} else {
		output, err := json.Marshal(object)
		if err != nil {
			return err
		}
		c.W.Write(output)
	}
	return nil
}

// WriteXML marshal the object to XML and writes it via the ResponseWriter.
func (c *RequestContext) WriteXML(object interface{}) error {
	c.W.Header().Set("Content-Type", "application/xml; charset=utf-8")
	if debugMode {
		output, err := xml.MarshalIndent(object, "", "  ")
		if err != nil {
			return err
		}
		writeDebug("WriteXML", c.R.RemoteAddr, string(output))
		c.W.Write(output)
	} else {
		output, err := xml.Marshal(object)
		if err != nil {
			return err
		}
		c.W.Write(output)
	}
	return nil
}

// WriteDefault writes the object to the caller according to the acceptable MIME in the Accept header value.
// If the MIME is not supported, it sends a 406 Not Acceptable request.
// text/plain uses the String method to be serialized.
// Mime supported for write:
//
//		application/json
//		application/xml
//		text/plain
//
// If no Accept header is present, it writes the object as JSON.
func (c *RequestContext) WriteDefault(object interface{}) error {
	acceptedContentType := c.GetAccepts()
	for _, contentType := range acceptedContentType {
		switch contentType {
		case ContentTypeText:
			return c.WriteString(fmt.Sprintf("%v", object))
		case ContentTypeJSON, "*/*":
			return c.WriteJSON(object)
		case ContentTypeXML:
			return c.WriteXML(object)
		}
	}
	return NewError(406, ErrContentTypeNotSupported)
}

// WriteReader copy the reader to the ResponseWriter.
func (c *RequestContext) WriteReader(reader io.Reader) error {
	_, err := io.Copy(c.W, reader)
	return err
}

// WriteTemplate writes the given template to the ResponseWriter.
func (c *RequestContext) WriteTemplateFile(filename string, data interface{}) error {
	tmplate, err := template.ParseFiles(filename)
	if err != nil {
		return err
	}
	return tmplate.Execute(c.W, data)
}

// SetStatusCode sets the response status code.
func (c *RequestContext) SetStatusCode(statusCode int) {
	c.W.WriteHeader(statusCode)
}

// GetBody return the body as a ReadCloser. It is the client responsibility to close the body.
func (c *RequestContext) GetBody() io.ReadCloser {
	return c.R.Body
}

// GetRawBody returns the body as a byte array, closing the body reader.
func (c *RequestContext) GetRawBody() ([]byte, error) {
	body := c.GetBody()
	defer body.Close()
	rawBody, err := ioutil.ReadAll(body)
	if err != nil {
		return nil, err
	}
	if debugMode {
		writeDebug("GetRawBody", c.R.RemoteAddr, fmt.Sprintf("got %s", string(rawBody)))
	}
	return rawBody, nil
}

// GetJSONObject call json.Unmarshal by sending the reference of the given object.
// For example:
//		func GetUser(c *pi.RequestContext) error {
// 			user := &User{}
// 			if err := c.GetJSONObject(user); err != nil {
//				return pi.NewError(400, err)
//			}
//			// Do something with the user...
//			return nil
//		}
//
func (c *RequestContext) GetJSONObject(object interface{}) error {
	rawBody, err := c.GetRawBody()
	if err != nil {
		return err
	}
	return json.Unmarshal(rawBody, &object)
}

// GetXMLObject call xml.Unmarshal by sending the reference of the given object.
func (c *RequestContext) GetXMLObject(object interface{}) error {
	rawBody, err := c.GetRawBody()
	if err != nil {
		return err
	}
	return xml.Unmarshal(rawBody, &object)
}

// GetFormObject call gorilla/schema.Decode to maps the form values of the request into the object.
// For more information: http://www.gorillatoolkit.org/pkg/schema
func (c *RequestContext) GetFormObject(object interface{}) error {
	if err := c.R.ParseForm(); err != nil {
		return err
	}
	return decoderFormValues.Decode(object, c.R.PostForm)
}

// GetMultipartObject calls gocarina/formdata.Unmarshal to maps the multipart form values of the request into the object.
// It supports files through multipart.FileHeader.
func (c *RequestContext) GetMultipartObject(object interface{}) error {
	return formdata.Unmarshal(c.R, object)
}

// GetDefaultObject calls one of a GetX method according to the Content-Type of the request.
// Content-Types supported:
// 		application/json
//		application/xml
//		application/x-www-form-urlencoded
//		multipart/form-data
//
func (c *RequestContext) GetDefaultObject(object interface{}) error {
	switch c.GetContentType() {
	case ContentTypeJSON:
		return c.GetJSONObject(object)
	case ContentTypeXML:
		return c.GetXMLObject(object)
	case ContentTypeClassicForm:
		return c.GetFormObject(object)
	}
	if strings.SplitAfter(c.GetContentType(), ContentTypeMultipart)[0] == ContentTypeMultipart {
		return c.GetMultipartObject(object)
	}
	return ErrContentTypeNotSupported
}

// GetRouteExtraPath returns the extra path.
// For example:
// 		for route("/files"), "/files/home/user/.emacs" will return "/home/user/.emacs"
func (c *RequestContext) GetRouteExtraPath() (path string) {
	fullPath := c.R.URL.String()
	if len(fullPath) > len(c.RouteURL) {
		path = fullPath[len(c.RouteURL):]
	}
	return path
}

// GetURLParam returns an URL parameter.
// For example, given this URL:
//		/user?id=1234
//
//		fmt.Println(c.GetURLParam("id"))
//		// Outputs 1234
//
func (c *RequestContext) GetURLParam(param string) string {
	return c.R.FormValue(param)
}

// GetURLParamOrDefault returns an URL parameter or the defaultValue if the value is empty.
func (c *RequestContext) GetURLParamOrDefault(param, defaultValue string) string {
	value := c.GetURLParam(param)
	if value == "" {
		return defaultValue
	}
	return value
}

// GetRouteVariable returns a route variable.
// For example:
//		getUserByID := func(c *RequestContext) error {
//			id := c.GetRouteVariable("id")
//			// Do something with the ID.
//			return nil
//		}
//
//		p := pi.New()
//		p.Route("/user/{id}").Get(getUserByID)
//		p.ListenAndServe(":8080")
//
func (c *RequestContext) GetRouteVariable(key string) string {
	return c.R.URL.Query().Get(":" + key)
}

// GetFileHeaders returns an array of FileHeader.
// For example:
//		getImages := func(c *RequestContext) error {
//			files, err := c.GetFileHeaders("files")
//			if err != nil {
//				return pi.NewError(400, err)
//			}
//			// Handle files
//			return nil
//		}
//
//		p := pi.New()
//		p.Route("/images").Post(getImages)
//		p.ListenAndServe(":8080")
//
func (c *RequestContext) GetFileHeaders(key string) ([]*multipart.FileHeader, error) {
	if err := c.R.ParseMultipartForm(32 << 20); err != nil {
		return nil, err
	}
	if c.R.MultipartForm != nil && c.R.MultipartForm.File[key] != nil {
		if debugMode {
			writeDebug("GetFileHeaders", c.R.RemoteAddr, fmt.Sprintf("got %d files from key %s", len(c.R.MultipartForm.File[key]), key))
		}
		return c.R.MultipartForm.File[key], nil
	}
	if debugMode {
		writeDebug("GetFileHeaders", c.R.RemoteAddr, fmt.Sprintf("got 0 files from key %s", key))
	}
	return nil, ErrNoFiles
}

// GetHeader returns the first value of the header of the request associated with the given key.
func (c *RequestContext) GetHeader(key string) string {
	return c.R.Header.Get(key)
}

// GetContentType returns the Content-Type of the request.
func (c *RequestContext) GetContentType() string {
	return c.GetHeader("Content-Type")
}

// GetAccepts returns the MIME types acceptable by the caller.
func (c *RequestContext) GetAccepts() []string {
	return c.GetHeaders("Accept")
}

// GetHeaderOrDefault returns the value of the header of the given defaultValue if the value is empty.
func (c *RequestContext) GetHeaderOrDefault(key, defaultValue string) string {
	value := c.GetHeader(key)
	if value == "" {
		return defaultValue
	}
	return key
}

// SetHeader sets to the response the header entries associated with key to
// the single element value.  It replaces any existing
// values associated with key.
func (c *RequestContext) SetHeader(key, value string) {
	c.W.Header().Set(key, value)
}

// AddHeader adds to the response the key, value pair to the header.
// It appends to any existing values associated with key.
func (c *RequestContext) AddHeader(key, value string) {
	c.W.Header().Add(key, value)
}

// DeleteHeader deletes from the response the values associated with key.
func (c *RequestContext) DeleteHeader(key string) {
	c.W.Header().Del(key)
}

// GetHeaders returns the array of values associated with the key from the request.
func (c *RequestContext) GetHeaders(key string) []string {
	return c.R.Header[key]
}
<commit_msg>Added GetURLParams method to RequestContext struct<commit_after>package pi

import (
	"encoding/json"
	"encoding/xml"
	"fmt"
	"github.com/gocarina/formdata"
	"github.com/gorilla/schema"
	"html/template"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"strings"
)

var (
	decoderFormValues = schema.NewDecoder()

	// ErrNoFiles is the error when no files is present in the value provided when
	// calling RequestContext.GetFileHeaders.
	ErrNoFiles = fmt.Errorf("no files")

	// ErrContentTypeNotSupported is the error when the format of the Content-Type is not supported
	ErrContentTypeNotSupported = fmt.Errorf("format not supported")

	// ContentTypeJSON is the default MIME for JSON data.
	ContentTypeJSON = "application/json"

	// ContentTypeXML is the default MIME for XML data.
	ContentTypeXML = "application/xml"

	// ContentTypeClassicForm is the default MIME for Form Encoded data.
	ContentTypeClassicForm = "application/x-www-form-urlencoded"

	// ContentTypeMultipart is the default MIME for Webform.
	ContentTypeMultipart = "multipart/form-data"

	// ContentTypeText is the default MIME for Textual data.
	ContentTypeText = "text/plain"
)

// J is an helper to write JSON.
// Example:
//		c.WriteJSON(pi.J{"status": "OK"})
//
type J map[string]interface{}

// RequestContext represents the context of the HTTP request.
// It is shared across interceptors and handler.
type RequestContext struct {
	W        http.ResponseWriter
	R        *http.Request
	RouteURL string
	Data     map[interface{}]interface{}
}

// newRequestContext returns a new RequestContext.
func newRequestContext(w http.ResponseWriter, r *http.Request, routeURL string) *RequestContext {
	return &RequestContext{
		W:        w,
		R:        r,
		RouteURL: routeURL,
		Data:     make(map[interface{}]interface{}),
	}
}

// WriteString writes the specified strings to the ResponseWriter.
func (c *RequestContext) WriteString(strings ...string) error {
	for _, s := range strings {
		if _, err := c.W.Write([]byte(s)); err != nil {
			return err
		}
	}
	return nil
}

// WriteJSON marshal the object to JSON and writes it via the ResponseWriter.
func (c *RequestContext) WriteJSON(object interface{}) error {
	c.W.Header().Set("Content-Type", "application/json; charset=utf-8")
	if debugMode {
		output, err := json.MarshalIndent(object, "", "  ")
		if err != nil {
			return err
		}
		writeDebug("WriteJSON", c.R.RemoteAddr, string(output))
		c.W.Write(output)
	} else {
		output, err := json.Marshal(object)
		if err != nil {
			return err
		}
		c.W.Write(output)
	}
	return nil
}

// WriteXML marshal the object to XML and writes it via the ResponseWriter.
func (c *RequestContext) WriteXML(object interface{}) error {
	c.W.Header().Set("Content-Type", "application/xml; charset=utf-8")
	if debugMode {
		output, err := xml.MarshalIndent(object, "", "  ")
		if err != nil {
			return err
		}
		writeDebug("WriteXML", c.R.RemoteAddr, string(output))
		c.W.Write(output)
	} else {
		output, err := xml.Marshal(object)
		if err != nil {
			return err
		}
		c.W.Write(output)
	}
	return nil
}

// WriteDefault writes the object to the caller according to the acceptable MIME in the Accept header value.
// If the MIME is not supported, it sends a 406 Not Acceptable request.
// text/plain uses the String method to be serialized.
// Mime supported for write:
//
//		application/json
//		application/xml
//		text/plain
//
// If no Accept header is present, it writes the object as JSON.
func (c *RequestContext) WriteDefault(object interface{}) error {
	acceptedContentType := c.GetAccepts()
	for _, contentType := range acceptedContentType {
		switch contentType {
		case ContentTypeText:
			return c.WriteString(fmt.Sprintf("%v", object))
		case ContentTypeJSON, "*/*":
			return c.WriteJSON(object)
		case ContentTypeXML:
			return c.WriteXML(object)
		}
	}
	return NewError(406, ErrContentTypeNotSupported)
}

// WriteReader copy the reader to the ResponseWriter.
func (c *RequestContext) WriteReader(reader io.Reader) error {
	_, err := io.Copy(c.W, reader)
	return err
}

// WriteTemplate writes the given template to the ResponseWriter.
func (c *RequestContext) WriteTemplateFile(filename string, data interface{}) error {
	tmplate, err := template.ParseFiles(filename)
	if err != nil {
		return err
	}
	return tmplate.Execute(c.W, data)
}

// SetStatusCode sets the response status code.
func (c *RequestContext) SetStatusCode(statusCode int) {
	c.W.WriteHeader(statusCode)
}

// GetBody return the body as a ReadCloser. It is the client responsibility to close the body.
func (c *RequestContext) GetBody() io.ReadCloser {
	return c.R.Body
}

// GetRawBody returns the body as a byte array, closing the body reader.
func (c *RequestContext) GetRawBody() ([]byte, error) {
	body := c.GetBody()
	defer body.Close()
	rawBody, err := ioutil.ReadAll(body)
	if err != nil {
		return nil, err
	}
	if debugMode {
		writeDebug("GetRawBody", c.R.RemoteAddr, fmt.Sprintf("got %s", string(rawBody)))
	}
	return rawBody, nil
}

// GetJSONObject call json.Unmarshal by sending the reference of the given object.
// For example:
//		func GetUser(c *pi.RequestContext) error {
// 			user := &User{}
// 			if err := c.GetJSONObject(user); err != nil {
//				return pi.NewError(400, err)
//			}
//			// Do something with the user...
//			return nil
//		}
//
func (c *RequestContext) GetJSONObject(object interface{}) error {
	rawBody, err := c.GetRawBody()
	if err != nil {
		return err
	}
	return json.Unmarshal(rawBody, &object)
}

// GetXMLObject call xml.Unmarshal by sending the reference of the given object.
func (c *RequestContext) GetXMLObject(object interface{}) error {
	rawBody, err := c.GetRawBody()
	if err != nil {
		return err
	}
	return xml.Unmarshal(rawBody, &object)
}

// GetFormObject call gorilla/schema.Decode to maps the form values of the request into the object.
// For more information: http://www.gorillatoolkit.org/pkg/schema
func (c *RequestContext) GetFormObject(object interface{}) error {
	if err := c.R.ParseForm(); err != nil {
		return err
	}
	return decoderFormValues.Decode(object, c.R.PostForm)
}

// GetMultipartObject calls gocarina/formdata.Unmarshal to maps the multipart form values of the request into the object.
// It supports files through multipart.FileHeader.
func (c *RequestContext) GetMultipartObject(object interface{}) error {
	return formdata.Unmarshal(c.R, object)
}

// GetDefaultObject calls one of a GetX method according to the Content-Type of the request.
// Content-Types supported:
// 		application/json
//		application/xml
//		application/x-www-form-urlencoded
//		multipart/form-data
//
func (c *RequestContext) GetDefaultObject(object interface{}) error {
	switch c.GetContentType() {
	case ContentTypeJSON:
		return c.GetJSONObject(object)
	case ContentTypeXML:
		return c.GetXMLObject(object)
	case ContentTypeClassicForm:
		return c.GetFormObject(object)
	}
	if strings.SplitAfter(c.GetContentType(), ContentTypeMultipart)[0] == ContentTypeMultipart {
		return c.GetMultipartObject(object)
	}
	return ErrContentTypeNotSupported
}

// GetRouteExtraPath returns the extra path.
// For example:
// 		for route("/files"), "/files/home/user/.emacs" will return "/home/user/.emacs"
func (c *RequestContext) GetRouteExtraPath() (path string) {
	fullPath := c.R.URL.String()
	if len(fullPath) > len(c.RouteURL) {
		path = fullPath[len(c.RouteURL):]
	}
	return path
}

// GetURLParam returns an URL parameter.
// For example, given this URL:
//		/user?id=1234
//
//		fmt.Println(c.GetURLParam("id"))
//		// Outputs 1234
//
func (c *RequestContext) GetURLParam(param string) string {
	return c.R.FormValue(param)
}

// GetURLParams returns multiple URL parameter.
// For example, given this URL:
//		/user?c=1&c=2
//
//		fmt.Println(c.GetURLParams("c"))
//		// Outputs [1, 2]
//
func (c *RequestContext) GetURLParams(param string) []string {
	c.R.ParseForm()
	return c.R.Form[param]
}

// GetURLParamOrDefault returns an URL parameter or the defaultValue if the value is empty.
func (c *RequestContext) GetURLParamOrDefault(param, defaultValue string) string {
	value := c.GetURLParam(param)
	if value == "" {
		return defaultValue
	}
	return value
}

// GetRouteVariable returns a route variable.
// For example:
//		getUserByID := func(c *RequestContext) error {
//			id := c.GetRouteVariable("id")
//			// Do something with the ID.
//			return nil
//		}
//
//		p := pi.New()
//		p.Route("/user/{id}").Get(getUserByID)
//		p.ListenAndServe(":8080")
//
func (c *RequestContext) GetRouteVariable(key string) string {
	return c.R.URL.Query().Get(":" + key)
}

// GetFileHeaders returns an array of FileHeader.
// For example:
//		getImages := func(c *RequestContext) error {
//			files, err := c.GetFileHeaders("files")
//			if err != nil {
//				return pi.NewError(400, err)
//			}
//			// Handle files
//			return nil
//		}
//
//		p := pi.New()
//		p.Route("/images").Post(getImages)
//		p.ListenAndServe(":8080")
//
func (c *RequestContext) GetFileHeaders(key string) ([]*multipart.FileHeader, error) {
	if err := c.R.ParseMultipartForm(32 << 20); err != nil {
		return nil, err
	}
	if c.R.MultipartForm != nil && c.R.MultipartForm.File[key] != nil {
		if debugMode {
			writeDebug("GetFileHeaders", c.R.RemoteAddr, fmt.Sprintf("got %d files from key %s", len(c.R.MultipartForm.File[key]), key))
		}
		return c.R.MultipartForm.File[key], nil
	}
	if debugMode {
		writeDebug("GetFileHeaders", c.R.RemoteAddr, fmt.Sprintf("got 0 files from key %s", key))
	}
	return nil, ErrNoFiles
}

// GetHeader returns the first value of the header of the request associated with the given key.
func (c *RequestContext) GetHeader(key string) string {
	return c.R.Header.Get(key)
}

// GetContentType returns the Content-Type of the request.
func (c *RequestContext) GetContentType() string {
	return c.GetHeader("Content-Type")
}

// GetAccepts returns the MIME types acceptable by the caller.
func (c *RequestContext) GetAccepts() []string {
	return c.GetHeaders("Accept")
}

// GetHeaderOrDefault returns the value of the header of the given defaultValue if the value is empty.
func (c *RequestContext) GetHeaderOrDefault(key, defaultValue string) string {
	value := c.GetHeader(key)
	if value == "" {
		return defaultValue
	}
	return key
}

// SetHeader sets to the response the header entries associated with key to
// the single element value.  It replaces any existing
// values associated with key.
func (c *RequestContext) SetHeader(key, value string) {
	c.W.Header().Set(key, value)
}

// AddHeader adds to the response the key, value pair to the header.
// It appends to any existing values associated with key.
func (c *RequestContext) AddHeader(key, value string) {
	c.W.Header().Add(key, value)
}

// DeleteHeader deletes from the response the values associated with key.
func (c *RequestContext) DeleteHeader(key string) {
	c.W.Header().Del(key)
}

// GetHeaders returns the array of values associated with the key from the request.
func (c *RequestContext) GetHeaders(key string) []string {
	return c.R.Header[key]
}
<|endoftext|>


<commit_before>package moka

import "testing"

type Register struct{}

func New(testingT *testing.T) Register {
	return Register{}
}

func (r Register) Allow(double Double) Subject {
	return Subject{double: double}
}

func (r Register) Expect(double Double) Subject {
	return Subject{}
}

func (r Register) Verify() {}
<commit_msg>Remove Register.Expect and Register.Verify for now<commit_after>package moka

import "testing"

type Register struct{}

func New(testingT *testing.T) Register {
	return Register{}
}

func (r Register) Allow(double Double) Subject {
	return Subject{double: double}
}
<|endoftext|>


<commit_before>package empire

import (
	"database/sql"
	"database/sql/driver"
)

// ReleaseID represents the unique identifier for a Release.
type ReleaseID string

// Scan implements the sql.Scanner interface.
func (r *ReleaseID) Scan(src interface{}) error {
	if src, ok := src.([]byte); ok {
		*r = ReleaseID(src)
	}

	return nil
}

// Value implements the driver.Value interface.
func (r ReleaseID) Value() (driver.Value, error) {
	return driver.Value(string(r)), nil
}

// ReleaseVersion represents the auto incremented human friendly version number of the
// release.
type ReleaseVersion int

// Release is a combination of a Config and a Slug, which form a deployable
// release.
type Release struct {
	ID  ReleaseID      `json:"id" db:"id"`
	Ver ReleaseVersion `json:"version" db:"version"` // Version conflicts with gorps optimistic locking.

	AppName  `json:"-" db:"app_id"`
	ConfigID `json:"-" db:"config_id"`
	SlugID   `json:"-" db:"slug_id"`
}

// ReleaseRepository is an interface that can be implemented for storing and
// retrieving releases.
type ReleasesRepository interface {
	Create(*Release) (*Release, error)
	FindByAppName(AppName) ([]*Release, error)
	Head(AppName) (*Release, error)
}

// dbRelease is a db representation of a release.
type dbRelease struct {
	ID       *string `db:"id"`
	Ver      int64   `db:"version"` // Ver because Version is reserved in gorp for optimistic locking.
	AppID    string  `db:"app_id"`
	ConfigID string  `db:"config_id"`
	SlugID   string  `db:"slug_id"`
}

// releasesRepository is an implementation of the ReleasesRepository interface backed by
// a DB.
type releasesRepository struct {
	DB
}

func (r *releasesRepository) Create(release *Release) (*Release, error) {
	return CreateRelease(r.DB, release)
}

func (r *releasesRepository) Head(appName AppName) (*Release, error) {
	return LastRelease(r.DB, appName)
}

func (r *releasesRepository) FindByAppName(appName AppName) ([]*Release, error) {
	var rs []*Release
	return rs, r.DB.Select(&rs, `select * from releases where app_id = $1 order by version desc limit 1`, string(appName))
}

// CreateRelease creates a new Release and inserts it into the database.
func CreateRelease(db DB, release *Release) (*Release, error) {
	t, err := db.Begin()
	if err != nil {
		return release, err
	}

	// Get the last release version for this app.
	v, err := LastReleaseVersion(t, release.AppName)
	if err != nil {
		return release, err
	}

	// Increment the release version.
	release.Ver = v + 1

	if err := t.Insert(release); err != nil {
		return release, err
	}

	return release, t.Commit()
}

// LastReleaseVersion returns the last ReleaseVersion for the given App. This
// function also ensures that the last release is locked until the transaction
// is commited, so the release version can be incremented atomically.
func LastReleaseVersion(db Queryier, appName AppName) (version ReleaseVersion, err error) {
	err = db.SelectOne(&version, `select version from releases where app_id = $1 order by version desc for update`, string(appName))

	if err == sql.ErrNoRows {
		return 0, nil
	}

	return
}

// LastRelease returns the last Release for the given App.
func LastRelease(db Queryier, appName AppName) (*Release, error) {
	var release Release

	if err := db.SelectOne(&release, `select * from releases where app_id = $1 order by version desc limit 1`, string(appName)); err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		}

		return nil, err
	}

	return &release, nil
}

// ReleaseesService represents a service for interacting with Releases.
type ReleasesService interface {
	// Create creates a new release.
	Create(*App, *Config, *Slug) (*Release, error)

	// Find existing releases for an app
	FindByApp(*App) ([]*Release, error)

	// Find current release for an app
	Head(*App) (*Release, error)
}

// releasesService is a base implementation of the ReleasesService interface.
type releasesService struct {
	ReleasesRepository
	ProcessesRepository
	Manager
}

// Create creates the release, then sets the current process formation on the release.
func (s *releasesService) Create(app *App, config *Config, slug *Slug) (*Release, error) {
	r := &Release{
		AppName:  app.Name,
		ConfigID: config.ID,
		SlugID:   slug.ID,
	}

	r, err := s.ReleasesRepository.Create(r)
	if err != nil {
		return r, err
	}

	// Create a new formation for this release.
	formation, err := s.createFormation(r, slug)
	if err != nil {
		return nil, err
	}

	// Schedule the new release onto the cluster.
	if err := s.Manager.ScheduleRelease(r, config, slug, formation); err != nil {
		return r, err
	}

	return r, nil
}

func (s *releasesService) FindByApp(a *App) ([]*Release, error) {
	return s.ReleasesRepository.FindByAppName(a.Name)
}

func (s *releasesService) Head(app *App) (*Release, error) {
	return s.ReleasesRepository.Head(app.Name)
}

func (s *releasesService) createFormation(release *Release, slug *Slug) (Formation, error) {
	// Get the old release, so we can copy the Formation.
	last, err := s.ReleasesRepository.Head(release.AppName)
	if err != nil {
		return nil, err
	}

	var existing Formation

	if last != nil {
		existing, err = s.ProcessesRepository.All(last.ID)
		if err != nil {
			return nil, err
		}
	}

	f := NewFormation(existing, slug.ProcessTypes)

	for _, p := range f {
		p.ReleaseID = release.ID

		if _, err := s.ProcessesRepository.Create(p); err != nil {
			return f, err
		}
	}

	return f, nil
}
<commit_msg>Cleanup.<commit_after>package empire

import (
	"database/sql"
	"database/sql/driver"
)

// ReleaseID represents the unique identifier for a Release.
type ReleaseID string

// Scan implements the sql.Scanner interface.
func (r *ReleaseID) Scan(src interface{}) error {
	if src, ok := src.([]byte); ok {
		*r = ReleaseID(src)
	}

	return nil
}

// Value implements the driver.Value interface.
func (r ReleaseID) Value() (driver.Value, error) {
	return driver.Value(string(r)), nil
}

// ReleaseVersion represents the auto incremented human friendly version number of the
// release.
type ReleaseVersion int

// Release is a combination of a Config and a Slug, which form a deployable
// release.
type Release struct {
	ID  ReleaseID      `json:"id" db:"id"`
	Ver ReleaseVersion `json:"version" db:"version"` // Version conflicts with gorps optimistic locking.

	AppName  `json:"-" db:"app_id"`
	ConfigID `json:"-" db:"config_id"`
	SlugID   `json:"-" db:"slug_id"`
}

// ReleaseRepository is an interface that can be implemented for storing and
// retrieving releases.
type ReleasesRepository interface {
	Create(*Release) (*Release, error)
	FindByAppName(AppName) ([]*Release, error)
	Head(AppName) (*Release, error)
}

// releasesRepository is an implementation of the ReleasesRepository interface backed by
// a DB.
type releasesRepository struct {
	DB
}

func (r *releasesRepository) Create(release *Release) (*Release, error) {
	return CreateRelease(r.DB, release)
}

func (r *releasesRepository) Head(appName AppName) (*Release, error) {
	return LastRelease(r.DB, appName)
}

func (r *releasesRepository) FindByAppName(appName AppName) ([]*Release, error) {
	var rs []*Release
	return rs, r.DB.Select(&rs, `select * from releases where app_id = $1 order by version desc limit 1`, string(appName))
}

// CreateRelease creates a new Release and inserts it into the database.
func CreateRelease(db DB, release *Release) (*Release, error) {
	t, err := db.Begin()
	if err != nil {
		return release, err
	}

	// Get the last release version for this app.
	v, err := LastReleaseVersion(t, release.AppName)
	if err != nil {
		return release, err
	}

	// Increment the release version.
	release.Ver = v + 1

	if err := t.Insert(release); err != nil {
		return release, err
	}

	return release, t.Commit()
}

// LastReleaseVersion returns the last ReleaseVersion for the given App. This
// function also ensures that the last release is locked until the transaction
// is commited, so the release version can be incremented atomically.
func LastReleaseVersion(db Queryier, appName AppName) (version ReleaseVersion, err error) {
	err = db.SelectOne(&version, `select version from releases where app_id = $1 order by version desc for update`, string(appName))

	if err == sql.ErrNoRows {
		return 0, nil
	}

	return
}

// LastRelease returns the last Release for the given App.
func LastRelease(db Queryier, appName AppName) (*Release, error) {
	var release Release

	if err := db.SelectOne(&release, `select * from releases where app_id = $1 order by version desc limit 1`, string(appName)); err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		}

		return nil, err
	}

	return &release, nil
}

// ReleaseesService represents a service for interacting with Releases.
type ReleasesService interface {
	// Create creates a new release.
	Create(*App, *Config, *Slug) (*Release, error)

	// Find existing releases for an app
	FindByApp(*App) ([]*Release, error)

	// Find current release for an app
	Head(*App) (*Release, error)
}

// releasesService is a base implementation of the ReleasesService interface.
type releasesService struct {
	ReleasesRepository
	ProcessesRepository
	Manager
}

// Create creates the release, then sets the current process formation on the release.
func (s *releasesService) Create(app *App, config *Config, slug *Slug) (*Release, error) {
	r := &Release{
		AppName:  app.Name,
		ConfigID: config.ID,
		SlugID:   slug.ID,
	}

	r, err := s.ReleasesRepository.Create(r)
	if err != nil {
		return r, err
	}

	// Create a new formation for this release.
	formation, err := s.createFormation(r, slug)
	if err != nil {
		return nil, err
	}

	// Schedule the new release onto the cluster.
	if err := s.Manager.ScheduleRelease(r, config, slug, formation); err != nil {
		return r, err
	}

	return r, nil
}

func (s *releasesService) FindByApp(a *App) ([]*Release, error) {
	return s.ReleasesRepository.FindByAppName(a.Name)
}

func (s *releasesService) Head(app *App) (*Release, error) {
	return s.ReleasesRepository.Head(app.Name)
}

func (s *releasesService) createFormation(release *Release, slug *Slug) (Formation, error) {
	// Get the old release, so we can copy the Formation.
	last, err := s.ReleasesRepository.Head(release.AppName)
	if err != nil {
		return nil, err
	}

	var existing Formation

	if last != nil {
		existing, err = s.ProcessesRepository.All(last.ID)
		if err != nil {
			return nil, err
		}
	}

	f := NewFormation(existing, slug.ProcessTypes)

	for _, p := range f {
		p.ReleaseID = release.ID

		if _, err := s.ProcessesRepository.Create(p); err != nil {
			return f, err
		}
	}

	return f, nil
}
<|endoftext|>


<commit_before>// Copyright 2022 Google LLC
//
// 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
//
//     https://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 ezcx

import (
	"bytes"
	"context"
	"io"
	"net/http"

	"github.com/google/uuid"
	cx "google.golang.org/genproto/googleapis/cloud/dialogflow/cx/v3"
	"google.golang.org/protobuf/encoding/protojson"
	"google.golang.org/protobuf/types/known/structpb"
)

type WebhookRequest struct {
	cx.WebhookRequest
	// 2022-10-08: Replaced context.Context with func () context.Context.
	ctx func() context.Context
}

func NewWebhookRequest() *WebhookRequest {
	return new(WebhookRequest)
}

// WebhookRequest Initializations

// Initialize the PageInfo field
func (req *WebhookRequest) initPageInfo() {
	if req.PageInfo == nil {
		req.PageInfo = new(cx.PageInfo)
	}
	if req.PageInfo.FormInfo == nil {
		req.PageInfo.FormInfo = new(cx.PageInfo_FormInfo)
	}
	if req.PageInfo.FormInfo.ParameterInfo == nil {
		req.PageInfo.FormInfo.ParameterInfo = make([]*cx.PageInfo_FormInfo_ParameterInfo, 0)
	}
}

// Initialize the SessionInfo field
func (req *WebhookRequest) initSessionInfo() {
	if req.SessionInfo == nil {
		req.SessionInfo = new(cx.SessionInfo)
	}
}

// Initialize the Payload field
func (req *WebhookRequest) initPayload() {
	if req.Payload == nil {
		req.Payload = new(structpb.Struct)
	}
	if req.Payload.Fields == nil {
		req.Payload.Fields = make(map[string]*structpb.Value)
	}
}

func (req *WebhookRequest) Context() context.Context {
	return req.ctx()
}

// Sets (overrides) the PageInfo.ParameterInfos to match the provided map m
func (req *WebhookRequest) setPageFormParameters(m map[string]any) error {
	params := make([]*cx.PageInfo_FormInfo_ParameterInfo, 0)
	for k, v := range m {
		var formParameter cx.PageInfo_FormInfo_ParameterInfo
		pv, err := anyToProto(v)
		if err != nil {
			return err
		}
		formParameter.DisplayName = k
		formParameter.Value = pv
		formParameter.State = cx.PageInfo_FormInfo_ParameterInfo_FILLED
		params = append(params, &formParameter)
	}
	req.PageInfo.FormInfo.ParameterInfo = params
	return nil
}

// Sets (overrides) the SessionInfo.Parameters to match the provided map m
func (req *WebhookRequest) setSessionParameters(m map[string]any) error {
	pm, err := anyToProtoMap(m)
	if err != nil {
		return err
	}
	req.SessionInfo.Parameters = pm
	return nil
}

// Sets (overrides the SessionInfo.Parameters) to match the provided map m
func (req *WebhookRequest) setPayload(m map[string]any) error {
	pm, err := anyToProtoMap(m)
	if err != nil {
		return err
	}
	req.Payload.Fields = pm
	return nil
}

// yaquino@2022-10-11: Dialogflow CX API May include "extra" fields that may
// throw errors and interface with protojson.Unmarshal.  As per the documentation,
// these fields may be ignored. Now also pointing at req.WebhookRequest for unmarshalling..
func WebhookRequestFromReader(rd io.Reader) (*WebhookRequest, error) {
	var req WebhookRequest
	b, err := io.ReadAll(rd)
	if err != nil {
		return nil, err
	}
	unmarshaler := &protojson.UnmarshalOptions{
		DiscardUnknown: true,
	}
	err = unmarshaler.Unmarshal(b, &req.WebhookRequest)
	if err != nil {
		return nil, err
	}
	return &req, nil
}

// yaquino@2022-10-07: Refactored to flow http.Request's context to the
// WebhookRequest instance.
func WebhookRequestFromRequest(r *http.Request) (*WebhookRequest, error) {
	req, err := WebhookRequestFromReader(r.Body)
	if err != nil {
		return nil, err
	}
	return req, nil
}

func (req *WebhookRequest) ReadReader(rd io.Reader) error {
	b, err := io.ReadAll(rd)
	if err != nil {
		return err
	}
	unmarshaler := &protojson.UnmarshalOptions{
		DiscardUnknown: true,
	}
	err = unmarshaler.Unmarshal(b, &req.WebhookRequest)
	if err != nil {
		return err
	}
	return nil
}

func (req *WebhookRequest) ReadRequest(r *http.Request) error {
	return req.ReadReader(r.Body)
}

// Is this the right format??
func (req *WebhookRequest) WriteRequest(w io.Writer) error {
	m := protojson.MarshalOptions{Indent: "\t"}
	b, err := m.Marshal(&req.WebhookRequest)
	if err != nil {
		return err
	}
	r := bytes.NewReader(b)
	_, err = io.Copy(w, r)
	if err != nil {
		return err
	}
	return nil
}

func (req *WebhookRequest) InitializeResponse() *WebhookResponse {
	return req.initializeResponse()
}

func (req *WebhookRequest) initializeResponse() *WebhookResponse {
	resp := NewWebhookResponse()
	return req.copySession(resp)
}

func (req *WebhookRequest) copySession(res *WebhookResponse) *WebhookResponse {
	if res.SessionInfo == nil {
		res.SessionInfo = new(cx.SessionInfo)
	}
	res.SessionInfo.Session = req.SessionInfo.Session
	return res
}

func (req *WebhookRequest) CopyPageInfo(res *WebhookResponse) {
	if req.PageInfo != nil {
		res.PageInfo = req.PageInfo
	}
}

func (req *WebhookRequest) CopySessionInfo(res *WebhookResponse) *WebhookResponse {
	if req.SessionInfo != nil {
		res.SessionInfo = req.SessionInfo
	}
	return res
}

func (req *WebhookRequest) CopyPayload(res *WebhookResponse) *WebhookResponse {
	if req.Payload != nil {
		res.Payload = req.Payload
	}
	return res
}

func (req *WebhookRequest) GetPageFormParameters() map[string]any {
	params := make(map[string]any)

	// Just in case - I don't think we can iterate over a nil map.
	if req.PageInfo == nil {
		return nil
	}
	if req.PageInfo.FormInfo == nil {
		return nil
	}
	if req.PageInfo.FormInfo.ParameterInfo == nil {
		return nil
	}

	for _, paramInfo := range req.PageInfo.FormInfo.ParameterInfo {
		params[paramInfo.DisplayName] = protoToAny(paramInfo.Value)
	}

	return params
}

func (req *WebhookRequest) GetSessionParameters() map[string]any {
	if req.SessionInfo == nil {
		return nil
	}
	if req.SessionInfo.Parameters == nil {
		return nil
	}
	return protoToAnyMap(req.SessionInfo.Parameters)
}

func (req *WebhookRequest) GetSessionParameter(key string) (any, bool) {
	// Check if SessionInfo Parameters is nil.
	if req.SessionInfo == nil {
		return nil, false
	}
	if req.SessionInfo.Parameters == nil {
		return nil, false
	}
	pv, ok := req.SessionInfo.Parameters[key]
	return protoToAny(pv), ok
}

func (req *WebhookRequest) GetPayload() map[string]any {
	if req.Payload == nil {
		return nil
	}
	if req.Payload.Fields == nil {
		return nil
	}
	return protoToAnyMap(req.Payload.Fields)
}

func (req *WebhookRequest) GetPayloadParameter(key string) (any, bool) {
	// Just in case - I don't think we can iterate over a nil map.

	if req.Payload == nil {
		return nil, false
	}
	if req.Payload.Fields == nil {
		return nil, false
	}

	pv, ok := req.Payload.Fields[key]
	return protoToAny(pv), ok
}

// Testing
func NewTestingWebhookRequest(session, payload, pageform map[string]any) (*WebhookRequest, error) {
	return NewWebhookRequest().initTestingWebhookRequest(session, payload, pageform)
}

func (req *WebhookRequest) initTestingWebhookRequest(session, payload, pageform map[string]any) (*WebhookRequest, error) {
	// Provided for testing, normally http.Request.Context is flowed down.
	req.ctx = context.Background

	// All incoming WebhookRequests should have a session.
	req.initSessionInfo()
	req.SessionInfo.Session = uuid.New().String()

	// if session parameters are provided...
	if session != nil {
		err := req.setSessionParameters(session)
		if err != nil {
			return nil, err
		}
	}

	// if payload parameters are provided...
	if payload != nil {
		req.initPayload()
		err := req.setPayload(payload)
		if err != nil {
			return nil, err
		}
	}

	// if pageForm parameters are provided...
	if pageform != nil {
		req.initPageInfo()
		err := req.setPageFormParameters(pageform)
		if err != nil {
			return nil, err
		}
	}
	return req, nil
}

// yaquino: 2022-10-08Review this...!
func (req *WebhookRequest) TestCxHandler(out io.Writer, h HandlerFunc) (*WebhookResponse, error) {
	if req.ctx == nil {
		req.ctx = context.Background
	}
	res := req.initializeResponse()
	err := h(res, req)
	if err != nil {
		return nil, err
	}
	err = res.WriteResponse(out)
	if err != nil {
		return nil, err
	}
	return res, nil
}
<commit_msg>new proto unmarshaler<commit_after>// Copyright 2022 Google LLC
//
// 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
//
//     https://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 ezcx

import (
	"bytes"
	"context"
	"io"
	"net/http"

	"github.com/google/uuid"
	cx "google.golang.org/genproto/googleapis/cloud/dialogflow/cx/v3"
	"google.golang.org/protobuf/encoding/protojson"
	"google.golang.org/protobuf/types/known/structpb"
)

type WebhookRequest struct {
	cx.WebhookRequest
	// 2022-10-08: Replaced context.Context with func () context.Context.
	ctx func() context.Context
}

func NewWebhookRequest() *WebhookRequest {
	return new(WebhookRequest)
}

// WebhookRequest Initializations

// Initialize the PageInfo field
func (req *WebhookRequest) initPageInfo() {
	if req.PageInfo == nil {
		req.PageInfo = new(cx.PageInfo)
	}
	if req.PageInfo.FormInfo == nil {
		req.PageInfo.FormInfo = new(cx.PageInfo_FormInfo)
	}
	if req.PageInfo.FormInfo.ParameterInfo == nil {
		req.PageInfo.FormInfo.ParameterInfo = make([]*cx.PageInfo_FormInfo_ParameterInfo, 0)
	}
}

// Initialize the SessionInfo field
func (req *WebhookRequest) initSessionInfo() {
	if req.SessionInfo == nil {
		req.SessionInfo = new(cx.SessionInfo)
	}
}

// Initialize the Payload field
func (req *WebhookRequest) initPayload() {
	if req.Payload == nil {
		req.Payload = new(structpb.Struct)
	}
	if req.Payload.Fields == nil {
		req.Payload.Fields = make(map[string]*structpb.Value)
	}
}

func (req *WebhookRequest) Context() context.Context {
	return req.ctx()
}

// Sets (overrides) the PageInfo.ParameterInfos to match the provided map m
func (req *WebhookRequest) setPageFormParameters(m map[string]any) error {
	params := make([]*cx.PageInfo_FormInfo_ParameterInfo, 0)
	for k, v := range m {
		var formParameter cx.PageInfo_FormInfo_ParameterInfo
		pv, err := anyToProto(v)
		if err != nil {
			return err
		}
		formParameter.DisplayName = k
		formParameter.Value = pv
		formParameter.State = cx.PageInfo_FormInfo_ParameterInfo_FILLED
		params = append(params, &formParameter)
	}
	req.PageInfo.FormInfo.ParameterInfo = params
	return nil
}

// Sets (overrides) the SessionInfo.Parameters to match the provided map m
func (req *WebhookRequest) setSessionParameters(m map[string]any) error {
	pm, err := anyToProtoMap(m)
	if err != nil {
		return err
	}
	req.SessionInfo.Parameters = pm
	return nil
}

// Sets (overrides the SessionInfo.Parameters) to match the provided map m
func (req *WebhookRequest) setPayload(m map[string]any) error {
	pm, err := anyToProtoMap(m)
	if err != nil {
		return err
	}
	req.Payload.Fields = pm
	return nil
}

// yaquino@2022-10-11: Dialogflow CX API May include "extra" fields that may
// throw errors and interface with protojson.Unmarshal.  As per the documentation,
// these fields may be ignored. Now also pointing at req.WebhookRequest for unmarshalling..
func WebhookRequestFromReader(rd io.Reader) (*WebhookRequest, error) {
	var req WebhookRequest
	b, err := io.ReadAll(rd)
	if err != nil {
		return nil, err
	}
	unmarshaler := &protojson.UnmarshalOptions{
		AllowPartial:   true,
		DiscardUnknown: true,
	}
	err = unmarshaler.Unmarshal(b, &req.WebhookRequest)
	if err != nil {
		return nil, err
	}
	return &req, nil
}

// yaquino@2022-10-07: Refactored to flow http.Request's context to the
// WebhookRequest instance.
func WebhookRequestFromRequest(r *http.Request) (*WebhookRequest, error) {
	req, err := WebhookRequestFromReader(r.Body)
	if err != nil {
		return nil, err
	}
	return req, nil
}

func (req *WebhookRequest) ReadReader(rd io.Reader) error {
	b, err := io.ReadAll(rd)
	if err != nil {
		return err
	}
	unmarshaler := &protojson.UnmarshalOptions{
		AllowPartial:   true,
		DiscardUnknown: true,
	}
	err = unmarshaler.Unmarshal(b, &req.WebhookRequest)
	if err != nil {
		return err
	}
	return nil
}

func (req *WebhookRequest) ReadRequest(r *http.Request) error {
	return req.ReadReader(r.Body)
}

// Is this the right format??
func (req *WebhookRequest) WriteRequest(w io.Writer) error {
	m := protojson.MarshalOptions{Indent: "\t"}
	b, err := m.Marshal(&req.WebhookRequest)
	if err != nil {
		return err
	}
	r := bytes.NewReader(b)
	_, err = io.Copy(w, r)
	if err != nil {
		return err
	}
	return nil
}

func (req *WebhookRequest) InitializeResponse() *WebhookResponse {
	return req.initializeResponse()
}

func (req *WebhookRequest) initializeResponse() *WebhookResponse {
	resp := NewWebhookResponse()
	return req.copySession(resp)
}

func (req *WebhookRequest) copySession(res *WebhookResponse) *WebhookResponse {
	if res.SessionInfo == nil {
		res.SessionInfo = new(cx.SessionInfo)
	}
	res.SessionInfo.Session = req.SessionInfo.Session
	return res
}

func (req *WebhookRequest) CopyPageInfo(res *WebhookResponse) {
	if req.PageInfo != nil {
		res.PageInfo = req.PageInfo
	}
}

func (req *WebhookRequest) CopySessionInfo(res *WebhookResponse) *WebhookResponse {
	if req.SessionInfo != nil {
		res.SessionInfo = req.SessionInfo
	}
	return res
}

func (req *WebhookRequest) CopyPayload(res *WebhookResponse) *WebhookResponse {
	if req.Payload != nil {
		res.Payload = req.Payload
	}
	return res
}

func (req *WebhookRequest) GetPageFormParameters() map[string]any {
	params := make(map[string]any)

	// Just in case - I don't think we can iterate over a nil map.
	if req.PageInfo == nil {
		return nil
	}
	if req.PageInfo.FormInfo == nil {
		return nil
	}
	if req.PageInfo.FormInfo.ParameterInfo == nil {
		return nil
	}

	for _, paramInfo := range req.PageInfo.FormInfo.ParameterInfo {
		params[paramInfo.DisplayName] = protoToAny(paramInfo.Value)
	}

	return params
}

func (req *WebhookRequest) GetSessionParameters() map[string]any {
	if req.SessionInfo == nil {
		return nil
	}
	if req.SessionInfo.Parameters == nil {
		return nil
	}
	return protoToAnyMap(req.SessionInfo.Parameters)
}

func (req *WebhookRequest) GetSessionParameter(key string) (any, bool) {
	// Check if SessionInfo Parameters is nil.
	if req.SessionInfo == nil {
		return nil, false
	}
	if req.SessionInfo.Parameters == nil {
		return nil, false
	}
	pv, ok := req.SessionInfo.Parameters[key]
	return protoToAny(pv), ok
}

func (req *WebhookRequest) GetPayload() map[string]any {
	if req.Payload == nil {
		return nil
	}
	if req.Payload.Fields == nil {
		return nil
	}
	return protoToAnyMap(req.Payload.Fields)
}

func (req *WebhookRequest) GetPayloadParameter(key string) (any, bool) {
	// Just in case - I don't think we can iterate over a nil map.

	if req.Payload == nil {
		return nil, false
	}
	if req.Payload.Fields == nil {
		return nil, false
	}

	pv, ok := req.Payload.Fields[key]
	return protoToAny(pv), ok
}

// Testing
func NewTestingWebhookRequest(session, payload, pageform map[string]any) (*WebhookRequest, error) {
	return NewWebhookRequest().initTestingWebhookRequest(session, payload, pageform)
}

func (req *WebhookRequest) initTestingWebhookRequest(session, payload, pageform map[string]any) (*WebhookRequest, error) {
	// Provided for testing, normally http.Request.Context is flowed down.
	req.ctx = context.Background

	// All incoming WebhookRequests should have a session.
	req.initSessionInfo()
	req.SessionInfo.Session = uuid.New().String()

	// if session parameters are provided...
	if session != nil {
		err := req.setSessionParameters(session)
		if err != nil {
			return nil, err
		}
	}

	// if payload parameters are provided...
	if payload != nil {
		req.initPayload()
		err := req.setPayload(payload)
		if err != nil {
			return nil, err
		}
	}

	// if pageForm parameters are provided...
	if pageform != nil {
		req.initPageInfo()
		err := req.setPageFormParameters(pageform)
		if err != nil {
			return nil, err
		}
	}
	return req, nil
}

// yaquino: 2022-10-08Review this...!
func (req *WebhookRequest) TestCxHandler(out io.Writer, h HandlerFunc) (*WebhookResponse, error) {
	if req.ctx == nil {
		req.ctx = context.Background
	}
	res := req.initializeResponse()
	err := h(res, req)
	if err != nil {
		return nil, err
	}
	err = res.WriteResponse(out)
	if err != nil {
		return nil, err
	}
	return res, nil
}
<|endoftext|>


<commit_before>package arangolite

import "encoding/json"

// DATABASE

// CreateDatabase creates a new database.
type CreateDatabase struct {
	Username string                   `json:"username,omitempty"`
	Name     string                   `json:"name"`
	Extra    json.RawMessage          `json:"extra,omitempty"`
	Passwd   string                   `json:"passwd,omitempty"`
	Active   *bool                    `json:"active,omitempty"`
	Users    []map[string]interface{} `json:"users,omitempty"`
}

func (r *CreateDatabase) description() string {
	return "CREATE DATABASE"
}

func (r *CreateDatabase) path() string {
	return "/_api/database"
}

func (r *CreateDatabase) method() string {
	return "POST"
}

func (r *CreateDatabase) generate() []byte {
	m, _ := json.Marshal(r)
	return m
}

// DropDatabase deletes a database.
type DropDatabase struct {
	Name string
}

func (r *DropDatabase) description() string {
	return "DROP DATABASE"
}

func (r *DropDatabase) path() string {
	return "/_api/database/" + r.Name
}

func (r *DropDatabase) method() string {
	return "DELETE"
}

func (r *DropDatabase) generate() []byte {
	return nil
}

// COLLECTION

// CreateCollection creates a collection in database.
type CreateCollection struct {
	JournalSize    int                    `json:"journalSize,omitempty"`
	KeyOptions     map[string]interface{} `json:"keyOptions,omitempty"`
	Name           string                 `json:"name"`
	WaitForSync    *bool                  `json:"waitForSync,omitempty"`
	DoCompact      *bool                  `json:"doCompact,omitempty"`
	IsVolatile     *bool                  `json:"isVolatile,omitempty"`
	ShardKeys      []string               `json:"shardKeys,omitempty"`
	NumberOfShards int                    `json:"numberOfShards,omitempty"`
	IsSystem       *bool                  `json:"isSystem,omitempty"`
	Type           int                    `json:"type,omitempty"`
	IndexBuckets   int                    `json:"indexBuckets,omitempty"`
}

func (r *CreateCollection) description() string {
	return "CREATE COLLECTION"
}

func (r *CreateCollection) path() string {
	return "/_api/collection"
}

func (r *CreateCollection) method() string {
	return "POST"
}

func (r *CreateCollection) generate() []byte {
	m, _ := json.Marshal(r)
	return m
}

// DropCollection deletes a collection in database.
type DropCollection struct {
	Name string
}

func (r *DropCollection) description() string {
	return "DROP COLLECTION"
}

func (r *DropCollection) path() string {
	return "/_api/collection/" + r.Name
}

func (r *DropCollection) method() string {
	return "DELETE"
}

func (r *DropCollection) generate() []byte {
	return nil
}

// TruncateCollection deletes a collection in database.
type TruncateCollection struct {
	Name string
}

func (r *TruncateCollection) description() string {
	return "TRUNCATE COLLECTION"
}

func (r *TruncateCollection) path() string {
	return "/_api/collection/" + r.Name + "/truncate"
}

func (r *TruncateCollection) method() string {
	return "PUT"
}

func (r *TruncateCollection) generate() []byte {
	return nil
}

// INDEX

// CreateHashIndex creates a hash index in database.
type CreateHashIndex struct {
	CollectionName string   `json:"-"`
	Fields         []string `json:"fields,omitempty"`
	Unique         *bool    `json:"unique,omitempty"`
	Type           string   `json:"type,omitempty"`
	Sparse         *bool    `json:"sparse,omitempty"`
}

func (r *CreateHashIndex) description() string {
	return "CREATE HASH INDEX"
}

func (r *CreateHashIndex) path() string {
	return "/_api/index?collection-name=" + r.CollectionName
}

func (r *CreateHashIndex) method() string {
	return "POST"
}

func (r *CreateHashIndex) generate() []byte {
	r.Type = "hash"
	m, _ := json.Marshal(r)
	return m
}

// CACHE

// SetCacheProperties sets the query cache properties.
type SetCacheProperties struct {
	Mode       string `json:"mode,omitempty"`
	MaxResults int    `json:"maxResults,omitempty"`
}

func (r *SetCacheProperties) description() string {
	return "SET CACHE PROPERTIES"
}

func (r *SetCacheProperties) path() string {
	return "/_api/query-cache/properties"
}

func (r *SetCacheProperties) method() string {
	return "PUT"
}

func (r *SetCacheProperties) generate() []byte {
	m, _ := json.Marshal(r)
	return m
}

// GetCacheProperties retrieves the current query cache properties.
type GetCacheProperties struct{}

func (r *GetCacheProperties) description() string {
	return "GET CACHE PROPERTIES"
}

func (r *GetCacheProperties) path() string {
	return "/_api/query-cache/properties"
}

func (r *GetCacheProperties) method() string {
	return "GET"
}

func (r *GetCacheProperties) generate() []byte {
	return nil
}
<commit_msg>Create hash index request fixed.<commit_after>package arangolite

import "encoding/json"

// DATABASE

// CreateDatabase creates a new database.
type CreateDatabase struct {
	Username string                   `json:"username,omitempty"`
	Name     string                   `json:"name"`
	Extra    json.RawMessage          `json:"extra,omitempty"`
	Passwd   string                   `json:"passwd,omitempty"`
	Active   *bool                    `json:"active,omitempty"`
	Users    []map[string]interface{} `json:"users,omitempty"`
}

func (r *CreateDatabase) description() string {
	return "CREATE DATABASE"
}

func (r *CreateDatabase) path() string {
	return "/_api/database"
}

func (r *CreateDatabase) method() string {
	return "POST"
}

func (r *CreateDatabase) generate() []byte {
	m, _ := json.Marshal(r)
	return m
}

// DropDatabase deletes a database.
type DropDatabase struct {
	Name string
}

func (r *DropDatabase) description() string {
	return "DROP DATABASE"
}

func (r *DropDatabase) path() string {
	return "/_api/database/" + r.Name
}

func (r *DropDatabase) method() string {
	return "DELETE"
}

func (r *DropDatabase) generate() []byte {
	return nil
}

// COLLECTION

// CreateCollection creates a collection in database.
type CreateCollection struct {
	JournalSize    int                    `json:"journalSize,omitempty"`
	KeyOptions     map[string]interface{} `json:"keyOptions,omitempty"`
	Name           string                 `json:"name"`
	WaitForSync    *bool                  `json:"waitForSync,omitempty"`
	DoCompact      *bool                  `json:"doCompact,omitempty"`
	IsVolatile     *bool                  `json:"isVolatile,omitempty"`
	ShardKeys      []string               `json:"shardKeys,omitempty"`
	NumberOfShards int                    `json:"numberOfShards,omitempty"`
	IsSystem       *bool                  `json:"isSystem,omitempty"`
	Type           int                    `json:"type,omitempty"`
	IndexBuckets   int                    `json:"indexBuckets,omitempty"`
}

func (r *CreateCollection) description() string {
	return "CREATE COLLECTION"
}

func (r *CreateCollection) path() string {
	return "/_api/collection"
}

func (r *CreateCollection) method() string {
	return "POST"
}

func (r *CreateCollection) generate() []byte {
	m, _ := json.Marshal(r)
	return m
}

// DropCollection deletes a collection in database.
type DropCollection struct {
	Name string
}

func (r *DropCollection) description() string {
	return "DROP COLLECTION"
}

func (r *DropCollection) path() string {
	return "/_api/collection/" + r.Name
}

func (r *DropCollection) method() string {
	return "DELETE"
}

func (r *DropCollection) generate() []byte {
	return nil
}

// TruncateCollection deletes a collection in database.
type TruncateCollection struct {
	Name string
}

func (r *TruncateCollection) description() string {
	return "TRUNCATE COLLECTION"
}

func (r *TruncateCollection) path() string {
	return "/_api/collection/" + r.Name + "/truncate"
}

func (r *TruncateCollection) method() string {
	return "PUT"
}

func (r *TruncateCollection) generate() []byte {
	return nil
}

// INDEX

// CreateHashIndex creates a hash index in database.
type CreateHashIndex struct {
	CollectionName string   `json:"-"`
	Fields         []string `json:"fields,omitempty"`
	Unique         *bool    `json:"unique,omitempty"`
	Type           string   `json:"type,omitempty"`
	Sparse         *bool    `json:"sparse,omitempty"`
}

func (r *CreateHashIndex) description() string {
	return "CREATE HASH INDEX"
}

func (r *CreateHashIndex) path() string {
	return "/_api/index?collection=" + r.CollectionName
}

func (r *CreateHashIndex) method() string {
	return "POST"
}

func (r *CreateHashIndex) generate() []byte {
	r.Type = "hash"
	m, _ := json.Marshal(r)
	return m
}

// CACHE

// SetCacheProperties sets the query cache properties.
type SetCacheProperties struct {
	Mode       string `json:"mode,omitempty"`
	MaxResults int    `json:"maxResults,omitempty"`
}

func (r *SetCacheProperties) description() string {
	return "SET CACHE PROPERTIES"
}

func (r *SetCacheProperties) path() string {
	return "/_api/query-cache/properties"
}

func (r *SetCacheProperties) method() string {
	return "PUT"
}

func (r *SetCacheProperties) generate() []byte {
	m, _ := json.Marshal(r)
	return m
}

// GetCacheProperties retrieves the current query cache properties.
type GetCacheProperties struct{}

func (r *GetCacheProperties) description() string {
	return "GET CACHE PROPERTIES"
}

func (r *GetCacheProperties) path() string {
	return "/_api/query-cache/properties"
}

func (r *GetCacheProperties) method() string {
	return "GET"
}

func (r *GetCacheProperties) generate() []byte {
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"github.com/aarondl/pack"
	"log"
)

const (
	initialStackSize        = 20
	kidOffset               = 32
	stackIndexMask   uint64 = 0xFFFFFFFF
)

// bitFilter is a type used to filter versions based on their index in an array
// and an easy way to do cumulative versioning.
type bitFilter uint64

// Set sets a bit in the filter.
func (b bitFilter) Set(index uint) bitFilter {
	return bitFilter((1 << uint64(index)) | uint64(b))
}

// IsSet checks if a a bit in the filter is set.
func (b bitFilter) IsSet(index uint) bool {
	return 0 != ((1 << uint64(index)) & uint64(b))
}

// Clear turns off a bit in the filter.
func (b bitFilter) Clear(index uint) bitFilter {
	return bitFilter(^(1 << uint64(index)) & uint64(b))
}

// Add is the union of two bitFilters.
func (b bitFilter) Add(a bitFilter) bitFilter {
	return bitFilter(uint64(a) | uint64(b))
}

// versionProvider allows us to look up available versions for each package
// the array returned must be in sorted order for the best result from the
// solver as it assumes [0] is the latest version, and [1]... is less than that.
//
// GetVersions: Get the versions only from the dependency information.
// GetGraphs: Get a list of graphs showing dependency information for each
// version of the package.
type versionProvider interface {
	GetVersions(string) []*pack.Version
	GetGraph(string, *pack.Version) *depgraph
}

// stacknode helps to emulate recursion and perform safejumps.
type stacknode struct {
	kid     int
	version int
	ai      int
	current *depnode
	parent  *depnode
}

// savestate is the state of the algorithm at an activation point.
type savestate struct {
	kid     int
	version int
	si      int
	ai      int
	current *depnode
	parent  *depnode
	stack   []stacknode
}

// activation is the details of a packages activation.
type activation struct {
	name    string
	version *pack.Version
	state   *savestate
	filter  bitFilter
}

// String is used to debug activations.
func (a activation) String() string {
	var buf bytes.Buffer
	buf.WriteString(a.name)
	if a.version != nil {
		buf.WriteRune(space)
		buf.WriteString(a.version.String())
	}
	return buf.String()
}

/*
solve a dependency graph. This algorithm is a depth first search with
backjumping to resolve conflicts.
*/
func (g *depgraph) solve(vp versionProvider) error {
	if len(g.head.kids) == 0 {
		return nil
	}

	var current, parent *depnode = g.head, nil
	var stack = make([]stacknode, 0, initialStackSize) // Avoid allocations
	var si, ai, kid = -1, -1, 0
	var activations []*activation
	var active *activation
	var versions = make(map[string][]*pack.Version)
	var version *pack.Version
	var vs []*pack.Version
	var vi int
	var filter bitFilter
	var excluded int
	var ok bool
	var conflicts = make([]string, 0)
	var conflict bool

	var verbose = true // Replace by flag.

	for i := 0; i < 20; i++ {
		name := current.d.Name
		if verbose {
			log.Println("Current:", current.d)
		}

		if current == g.head {
			if kid >= len(current.kids) {
				if verbose {
					log.Println("Success!")
					log.Println(activations)
				}
				return nil
			} else {
				goto NEXT
			}
		}

		// Skip Activation if we're on any child other than 0.
		if kid != 0 {
			goto NEXT
		}

		// Fetch Versions for current.
		vs = nil
		if vs, ok = versions[name]; !ok {
			vstmp := vp.GetVersions(current.d.Name)
			vs = make([]*pack.Version, len(vstmp))
			copy(vs, vstmp)
			versions[name] = vs
			if verbose {
				log.Printf("Fetched Versions")
			}
		}

		if verbose {
			log.Println("Versions:", vs)
		}

		// Weed out versions.
		filter = 0
		excluded = 0
		for j := 0; j < len(vs); j++ {
			for _, con := range current.d.Constraints {
				if !vs[j].Satisfies(con.Operator, con.Version) {
					if verbose {
						log.Println("Removing unacceptable version:", vs[j])
					}
					filter.Set(uint(j))
					excluded++
				}
			}
		}

		if parent == g.head && len(vs) == excluded {
			return fmt.Errorf("No versions to satisfy root dependency: %v",
				current.d)
		}

		// Check for activeness. The first activation will always serve as the
		// main activation point, with the others simply being save points.
		active = nil
		for j := 0; j < len(activations); j++ {
			if activations[j].name == name {
				active = activations[j]
				break
			}
		}

		version = nil
		conflict = false
		if active != nil {
			if verbose {
				log.Println("Found activation:", active)
			}

			// Check that we comply with the currently active.
			for _, con := range current.d.Constraints {
				if !active.version.Satisfies(con.Operator, con.Version) {
					// We've found a problem.
					log.Printf("Conflict (%v): %v fails new constraint: %v%v",
						name, active.version, con.Operator.String(),
						con.Version)

					conflict = true
				}
			}

			// Add the current filter to the primary activation.
			version = active.version
			active.filter = active.filter.Add(filter)
		} else {
			if verbose {
				log.Println("Not activated:", name)
			}
			// Find a suitable version
			for ; version == nil && vi < len(vs); vi++ {
				if active != nil && active.filter.IsSet(uint(vi)) {
					continue
				}
				if len(current.d.Constraints) == 0 {
					version = vs[vi]
					break
				}
				for _, con := range current.d.Constraints {
					if vs[vi].Satisfies(con.Operator, con.Version) {
						version = vs[vi]
						break
					}
				}
			}

			if version == nil {
				if verbose {
					log.Printf("Conflict (%v): has no usable versions %v", name, vs)
				}
				// No version could be found, this is a conflict of sorts.
				conflict = true
			}
		}

		// If there's a conflict
		if conflict {
			conflicts = append(conflicts, name)
			// If we cannot climb the stack any further, go back to a save
			// point if one exists.
			if parent == g.head {
				if len(conflicts) == 0 {
					// No conflicts exist to jump back to.
					return fmt.Errorf("We've tried everything mate: %v", conflicts)
				}
				name = conflicts[0]
				conflicts = conflicts[1:]
				var st *savestate
				for i := 0; i < len(activations); i++ {
					if activations[i].name == name {
						st = activations[i].state
						break
					}
				}
				if st == nil {
					return fmt.Errorf("Failed to find an activation of a conflict (%v)? %v", name, activations)
				}
				current = st.current
				parent = st.parent
				if verbose {
					log.Println("Conflict! Restoring:", current.d.Name)
				}
				ai = st.ai
				vi = st.version
				vi++
				stack = st.stack
				si = st.si
				kid = 0
				if verbose {
					log.Println(activations)
					log.Println(activations[:ai])
					log.Println("Snipping activations back to:", ai) // TODO: REMOVE
				}
				activations = activations[:ai]
				continue
			}

			// We can still climb the stack, try it.
			sn := stack[si]
			parent = sn.parent
			current = sn.current
			if verbose {
				log.Println("Conflict! Popping:", current.d.Name)
			}
			ai = sn.ai
			vi = sn.version
			vi++
			stack = stack[:len(stack)-1]
			si--
			kid = 0
			if verbose {
				log.Println(activations)
				log.Println(activations[:ai])
				log.Println("Snipping activations back to:", ai) // TODO: REMOVE
			}
			activations = activations[:ai]
			continue
		}

		// Add ourselves to the list of activators.
		ai++
		activations = append(activations, &activation{
			name:    name,
			version: version,
			filter:  filter,
			state: &savestate{
				kid:     kid,
				version: vi,
				si:      si,
				ai:      ai,
				current: current,
				parent:  parent,
				stack:   make([]stacknode, len(stack)),
			},
		})
		copy(activations[len(activations)-1].state.stack, stack)
		current.v = version

		if verbose {
			log.Printf("Added: %v %v to activations", name, version)
			log.Println("Activations:", activations)
		}

		if verbose {
			log.Println("Fetching Dependencies for:", name)
		}

		current.kids = vp.GetGraph(name, version).head.kids
		if verbose {
			var b bytes.Buffer
			for _, dep := range current.kids {
				b.WriteString(dep.d.String())
				b.WriteRune(space)
			}
			log.Println("Got dependencies:", b.String())
		}

	NEXT:
		// Push current on to stack, go into child.
		if kid < len(current.kids) {
			if verbose {
				log.Println("Pushing:", name, kid)
			}
			stack = append(stack, stacknode{
				kid:     kid,
				version: vi,
				ai:      ai,
				current: current,
				parent:  parent,
			})
			parent = current
			current = current.kids[kid]
			ai = len(activations) - 1
			kid = 0
			vi = 0
			si++
			continue
		}

		// Pop off the stack back to parent.
		sn := stack[si]
		parent = sn.parent
		current = sn.current
		if verbose {
			log.Println("Popping:", current.d.Name)
		}
		kid = sn.kid
		vi = sn.version
		ai = sn.ai
		stack = stack[:len(stack)-1]
		kid++
		si--

		// Try activating:
		// If activated:
		//  If conflict:
		//    backjump to first activated parent?
		// Else:
		//  Create activation with list of versions/dependencies.
		// Remove non-compatible versions with the current node.
		// Choose highest version as current activated.
	}

	return nil
}

/*
	var verbose = true // Move to flag

	var stack = make([]stacknode, 0, initialStackSize) // Avoid allocations
	var index = 0
	var kid, version int
	var backjump *savestate
	var current *depnode
	var vs []*pack.Version
	var active = make(map[string]*activation)

	current = g.head

	for i := 0; i < 40; i++ {
		if verbose {
			log.Printf("Eval: %s (%v, %v)\n", current.d.Name, kid, version)
		}

		// Have we run out of dependencies to resolve?
		if kid >= len(current.kids) {
			if verbose {
				log.Println("Ran out of children...")
			}
			// Jump up stack.
			if index > 0 {
				index--
				current = stack[index].depnode
				//version = stack[index].version
				stack[index].kid++
				kid = stack[index].kid
				if verbose {
					log.Printf("Pop: %s (%v, %v)\n", current.d.Name,
						kid, version)
				}
				continue
			}
			if verbose {
				log.Println("Nothing left to do, should be solved.")
			}
			// We did it!!!!
			return true
		}

		// Try to activate child
		curkid := current.kids[kid]
		name := curkid.d.Name
		log.Println("Attempting child activation:", name)

		// Check if already activated
		if act, ok := active[name]; ok && act.v != nil {
			var found bool
			for _, con := range curkid.d.Constraints {
				if act.v.Satisfies(con.Operator, con.Version) {
					found = true
					break
				}
			}

			if found {
				// Add ourselves to the activators list.
				save := &savestate{
					kid, version, index, current,
					make([]stacknode, index+1),
				}
				copy(save.stack, stack)
				act.states = append(act.states, save)

				if verbose {
					log.Println(name, "satisfied by previous activation:",
						act.v, act.states)
				}
			} else {
				// Backjump
				backjump = act.states[len(act.states)-1]
				if verbose {
					log.Printf("Found conflict: %s (%v)\n", name, act.v)
					log.Print("Previous states: ")
					for _, a := range act.states {
						log.Printf("%v ", a)
					}
				}
				act.states = act.states[:len(act.states)-1]
				act.v = nil

				current, kid, version, index = backjump.current,
					backjump.kid, backjump.version, backjump.index
				copy(stack, backjump.stack)
				if verbose {
					log.Println("Backjumping:", index, kid)
				}
				version++
				continue
			}
		}

		// Get versions
		vs = vp.GetVersions(name)
		if verbose {
			log.Printf("Versions: %s %v\n", name, vs)
			log.Println("Iterating from:", version)
		}
		// Each version
		for ; version < len(vs); version++ {
			// Each constraint
			ver := vs[version]
			for _, con := range curkid.d.Constraints {
				if ver.Satisfies(con.Operator, con.Version) {
					if verbose {
						log.Println("Satisfactory Version:", curkid.d, ver)
					}
					curkid.v = ver
				}
				if curkid.v != nil {
					log.Println("No need for more constraint checks... Breaking.")
					break
				}
			}
			if len(curkid.d.Constraints) == 0 {
				curkid.v = ver
			}
			if curkid.v != nil {
				log.Println("No need to check more versions... Breaking")
				break
			}
		}

		if curkid.v == nil {
			// No version found to satisfy.
			if verbose {
				log.Println("No versions available to satisfy:", curkid.d)
			}
			return false
		} else {
			// Activate
			if verbose {
				log.Printf("Activating: %s %v (%v, %v)\n",
					curkid.d.Name, curkid.v, version, index)
			}

			// Add save state info to activation
			save := &savestate{
				kid, version, index, current,
				make([]stacknode, index+1),
			}
			copy(save.stack, stack)

			if act, ok := active[name]; ok {
				act.states = []*savestate{save}
				act.v = curkid.v
			} else {
				active[name] = &activation{[]*savestate{save}, curkid.v}
			}

			// Pull in child dependencies on activation.
			graphs := vp.GetGraphs(name)
			found := false
			for i := 0; i < len(graphs); i++ {
				if graphs[i].head.v.Satisfies(pack.Equal, curkid.v) {
					found = true
					curkid.kids = graphs[i].head.kids
					if verbose {
						log.Println("Setting kids:", len(curkid.kids))
					}
					break
				}
			}

			if !found {
				if verbose {
					log.Println("Dependency graph missing for: %v %v",
						curkid.d.Name, curkid.v)
				}
				return false
			}
		}

		if len(curkid.kids) > 0 {
			// Push current on to stack, make the curkid the new current.
			if verbose {
				log.Println("Has kids:", len(curkid.kids))
				log.Printf("Push: %s (%v, %v)\n", current.d.Name, kid, version)
			}
			stack = append(stack, stacknode{kid, version, current})
			kid = 0
			version = 0
			current = curkid
			index++
		} else {
			// Continue through all kids.
			kid++
			if verbose {
				log.Println("Next kid:", kid)
			}
		}
	}

	return false
}*/
<commit_msg>Clean up the ugliest of the messes.<commit_after>package main

import (
	"bytes"
	"fmt"
	"github.com/aarondl/pack"
	"log"
)

const (
	initialStackSize        = 20
	kidOffset               = 32
	stackIndexMask   uint64 = 0xFFFFFFFF
)

// bitFilter is a type used to filter versions based on their index in an array
// and an easy way to do cumulative versioning.
type bitFilter uint64

// Set sets a bit in the filter.
func (b bitFilter) Set(index uint) bitFilter {
	return bitFilter((1 << uint64(index)) | uint64(b))
}

// IsSet checks if a a bit in the filter is set.
func (b bitFilter) IsSet(index uint) bool {
	return 0 != ((1 << uint64(index)) & uint64(b))
}

// Clear turns off a bit in the filter.
func (b bitFilter) Clear(index uint) bitFilter {
	return bitFilter(^(1 << uint64(index)) & uint64(b))
}

// Add is the union of two bitFilters.
func (b bitFilter) Add(a bitFilter) bitFilter {
	return bitFilter(uint64(a) | uint64(b))
}

// versionProvider allows us to look up available versions for each package
// the array returned must be in sorted order for the best result from the
// solver as it assumes [0] is the latest version, and [1]... is less than that.
//
// GetVersions: Get the versions only from the dependency information.
// GetGraphs: Get a list of graphs showing dependency information for each
// version of the package.
type versionProvider interface {
	GetVersions(string) []*pack.Version
	GetGraph(string, *pack.Version) *depgraph
}

// stacknode helps to emulate recursion and perform safejumps.
type stacknode struct {
	kid     int
	version int
	ai      int
	current *depnode
	parent  *depnode
}

// savestate is the state of the algorithm at an activation point.
type savestate struct {
	kid     int
	version int
	si      int
	ai      int
	current *depnode
	parent  *depnode
	stack   []stacknode
}

// activation is the details of a packages activation.
type activation struct {
	name    string
	version *pack.Version
	state   *savestate
	filter  bitFilter
}

// String is used to debug activations.
func (a activation) String() string {
	var buf bytes.Buffer
	buf.WriteString(a.name)
	if a.version != nil {
		buf.WriteRune(space)
		buf.WriteString(a.version.String())
	}
	return buf.String()
}

/*
solve a dependency graph. This algorithm is a depth first search with
backjumping to resolve conflicts.
*/
func (g *depgraph) solve(vp versionProvider) error {
	if len(g.head.kids) == 0 {
		return nil
	}

	var current, parent *depnode = g.head, nil
	var stack = make([]stacknode, 0, initialStackSize) // Avoid allocations
	var si, ai, kid = -1, -1, 0
	var activations []*activation
	var active *activation
	var versions = make(map[string][]*pack.Version)
	var version *pack.Version
	var vs []*pack.Version
	var vi int
	var filter bitFilter
	var excluded int
	var ok bool
	var conflicts = make([]string, 0)
	var conflict bool

	var verbose = true // Replace by flag.

	for i := 0; i < 20; i++ {
		name := current.d.Name
		if verbose {
			log.Println("Current:", current.d)
		}

		if current == g.head {
			if kid >= len(current.kids) {
				if verbose {
					log.Println("Success!")
					log.Println(activations)
				}
				return nil
			} else {
				goto NEXT
			}
		}

		// Skip Activation if we're on any child other than 0.
		if kid != 0 {
			goto NEXT
		}

		// Fetch Versions for current.
		vs = nil
		if vs, ok = versions[name]; !ok {
			vstmp := vp.GetVersions(current.d.Name)
			vs = make([]*pack.Version, len(vstmp))
			copy(vs, vstmp)
			versions[name] = vs
			if verbose {
				log.Printf("Fetched Versions")
			}
		}

		if verbose {
			log.Println("Versions:", vs)
		}

		// Weed out versions.
		filter = 0
		excluded = 0
		for j := 0; j < len(vs); j++ {
			for _, con := range current.d.Constraints {
				if !vs[j].Satisfies(con.Operator, con.Version) {
					if verbose {
						log.Println("Removing unacceptable version:", vs[j])
					}
					filter.Set(uint(j))
					excluded++
				}
			}
		}

		if parent == g.head && len(vs) == excluded {
			return fmt.Errorf("No versions to satisfy root dependency: %v",
				current.d)
		}

		// Check for activeness. The first activation will always serve as the
		// main activation point, with the others simply being save points.
		active = nil
		for j := 0; j < len(activations); j++ {
			if activations[j].name == name {
				active = activations[j]
				break
			}
		}

		version = nil
		conflict = false
		if active != nil {
			if verbose {
				log.Println("Found activation:", active)
			}

			// Check that we comply with the currently active.
			for _, con := range current.d.Constraints {
				if !active.version.Satisfies(con.Operator, con.Version) {
					// We've found a problem.
					log.Printf("Conflict (%v): %v fails new constraint: %v%v",
						name, active.version, con.Operator.String(),
						con.Version)

					conflict = true
					break
				}
			}

			// Add the current filter to the primary activation.
			version = active.version
			active.filter = active.filter.Add(filter)
		} else {
			if verbose {
				log.Println("Not activated:", name)
			}
			// Find a suitable version
			for ; version == nil && vi < len(vs); vi++ {
				if active != nil && active.filter.IsSet(uint(vi)) {
					continue
				}
				if len(current.d.Constraints) == 0 {
					version = vs[vi]
					break
				}
				for _, con := range current.d.Constraints {
					if vs[vi].Satisfies(con.Operator, con.Version) {
						version = vs[vi]
						break
					}
				}
			}

			if version == nil {
				if verbose {
					log.Printf("Conflict (%v): has no usable versions %v",
						name, vs)
				}
				// No version could be found, this is a conflict of sorts.
				conflict = true
			}
		}

		if conflict {
			conflicts = append(conflicts, name)
			// If we cannot climb the stack any further, go back to a save
			// point if one exists.
			if parent == g.head {
				if len(conflicts) == 0 {
					// No conflicts exist to jump back to.
					return fmt.Errorf("We've tried everything mate: %v",
						conflicts)
				}
				name = conflicts[0]
				conflicts = conflicts[1:]
				var st *savestate
				for i := 0; i < len(activations); i++ {
					if activations[i].name == name {
						st = activations[i].state
						break
					}
				}
				if st == nil {
					return fmt.Errorf("Conflict's activation not found: %v %v",
						name, activations)
				}
				current = st.current
				parent = st.parent
				if verbose {
					log.Println("Conflict! Restoring:", current.d.Name)
				}
				ai = st.ai
				vi = st.version
				vi++
				stack = st.stack
				si = st.si
				kid = 0
				activations = activations[:ai]
				if verbose {
					log.Println("Activations:", activations)
				}
				continue
			}

			// We can still climb the stack, try it.
			sn := stack[si]
			parent = sn.parent
			current = sn.current
			if verbose {
				log.Println("Conflict! Popping:", current.d.Name)
			}
			ai = sn.ai
			vi = sn.version
			vi++
			stack = stack[:len(stack)-1]
			si--
			kid = 0
			activations = activations[:ai]
			if verbose {
				log.Println("Activations:", activations)
			}
			continue
		}

		// Add ourselves to the list of activators.
		ai++
		activations = append(activations, &activation{
			name:    name,
			version: version,
			filter:  filter,
			state: &savestate{
				kid:     kid,
				version: vi,
				si:      si,
				ai:      ai,
				current: current,
				parent:  parent,
				stack:   make([]stacknode, len(stack)),
			},
		})
		copy(activations[len(activations)-1].state.stack, stack)
		current.v = version

		if verbose {
			log.Printf("Added: %v %v to activations", name, version)
			log.Println("Activations:", activations)
		}

		if verbose {
			log.Println("Fetching Dependencies for:", name)
		}

		current.kids = vp.GetGraph(name, version).head.kids
		if verbose {
			var b bytes.Buffer
			for _, dep := range current.kids {
				b.WriteString(dep.d.String())
				b.WriteRune(space)
			}
			log.Println("Got dependencies:", b.String())
		}

	NEXT:
		// Push current on to stack, go into child.
		if kid < len(current.kids) {
			if verbose {
				log.Println("Pushing:", name, kid)
			}
			stack = append(stack, stacknode{
				kid:     kid,
				version: vi,
				ai:      ai,
				current: current,
				parent:  parent,
			})
			parent = current
			current = current.kids[kid]
			ai = len(activations) - 1
			kid = 0
			vi = 0
			si++
			continue
		}

		// Pop off the stack back to parent.
		sn := stack[si]
		parent = sn.parent
		current = sn.current
		if verbose {
			log.Println("Popping:", current.d.Name)
		}
		kid = sn.kid
		vi = sn.version
		ai = sn.ai
		stack = stack[:len(stack)-1]
		kid++
		si--
	}

	return nil
}
<|endoftext|>


<commit_before>package whois

import (
	"mime"
	"net/http"
	"time"
)

// Response represents a whois response from a server.
type Response struct {
	Query       string
	Host        string
	FetchedAt   time.Time
	ContentType string
	Charset     string
	Body        []byte
}

// NewResponse initializes a new whois response.
func NewResponse(query, host string) *Response {
	return &Response{
		Query:     query,
		Host:      host,
		FetchedAt: time.Now(),
	}
}

// String returns the response body.
func (res *Response) String() string {
	return string(res.Body)
}

// DetectContentType detects and sets the response content type and charset.
func (res *Response) DetectContentType(mt string) {
	// Sensible defaults
	res.ContentType = "text/plain"
	res.Charset = "utf-8"

	// Autodetect if not passed a Content-Type header
	if mt == "" {
		mt = http.DetectContentType(res.Body)
	}

	// Content type (e.g. text/plan or text/html)
	ct, mh, err := mime.ParseMediaType(mt)
	if err != nil {
		return
	}
	res.ContentType = ct

	// Character set (e.g. utf-8)
	cs, ok := mh["charset"]
	if !ok {
		return
	}
	res.Charset = cs
}

// Header returns a stringproto header representing the response.
func (res *Response) Header() http.Header {
	h := make(http.Header)
	h.Set("Query", res.Query)
	h.Set("Host", res.Host)
	h.Set("Fetched-At", res.FetchedAt.Format(time.RFC3339))
	h.Set("Content-Type", res.contentType())
	return h
}

func (res *Response) contentType() string {
	return mime.FormatMediaType(res.ContentType, map[string]string{"charset": res.Charset})
}
<commit_msg>Response.ContentType -> MediaType; promoted ContentType() to exported method.<commit_after>package whois

import (
	"mime"
	"net/http"
	"time"
)

// Response represents a whois response from a server.
type Response struct {
	Query     string
	Host      string
	FetchedAt time.Time
	MediaType string
	Charset   string
	Body      []byte
}

// NewResponse initializes a new whois response.
func NewResponse(query, host string) *Response {
	return &Response{
		Query:     query,
		Host:      host,
		FetchedAt: time.Now(),
	}
}

// String returns the response body.
func (res *Response) String() string {
	return string(res.Body)
}

// DetectContentType detects and sets the response content type and charset.
func (res *Response) DetectContentType(mt string) {
	// Sensible defaults
	res.MediaType = "text/plain"
	res.Charset = "utf-8"

	// Autodetect if not passed a Content-Type header
	if mt == "" {
		mt = http.DetectContentType(res.Body)
	}

	// Content type (e.g. text/plan or text/html)
	mt, params, err := mime.ParseMediaType(mt)
	if err != nil {
		return
	}
	res.MediaType = mt

	// Character set (e.g. utf-8)
	cs, ok := params["charset"]
	if !ok {
		return
	}
	res.Charset = cs
}

// Header returns a stringproto header representing the response.
func (res *Response) Header() http.Header {
	h := make(http.Header)
	h.Set("Query", res.Query)
	h.Set("Host", res.Host)
	h.Set("Fetched-At", res.FetchedAt.Format(time.RFC3339))
	h.Set("Content-Type", res.ContentType())
	return h
}

// ContentType returns an RFC 2045 compatible internet media type string.
func (res *Response) ContentType() string {
	return mime.FormatMediaType(res.MediaType, map[string]string{"charset": res.Charset})
}
<|endoftext|>