<commit_before>package handler

import (
	"context"
	"fmt"
	"github.com/Comcast/webpa-common/logging"
	"github.com/Comcast/webpa-common/secure"
	"net/http"
	"os"
)

// AuthorizationHandler provides decoration for http.Handler instances and will
// ensure that requests pass the validator.  Note that secure.Validators is a Validator
// implementation that allows chaining validators together via logical OR.
type AuthorizationHandler struct {
	HeaderName          string
	ForbiddenStatusCode int
	Validator           secure.Validator
	Logger              logging.Logger
}

// headerName returns the authorization header to use, either a.HeaderName
// or secure.AuthorizationHeader if no header is supplied
func (a AuthorizationHandler) headerName() string {
	if len(a.HeaderName) > 0 {
		return a.HeaderName
	}

	return secure.AuthorizationHeader
}

// forbiddenStatusCode returns a.ForbiddenStatusCode if supplied, otherwise
// http.StatusForbidden is returned
func (a AuthorizationHandler) forbiddenStatusCode() int {
	if a.ForbiddenStatusCode > 0 {
		return a.ForbiddenStatusCode
	}

	return http.StatusForbidden
}

func (a AuthorizationHandler) logger() logging.Logger {
	if a.Logger != nil {
		return a.Logger
	}

	return &logging.LoggerWriter{os.Stdout}
}

// Decorate provides an Alice-compatible constructor that validates requests
// using the configuration specified.
func (a AuthorizationHandler) Decorate(delegate http.Handler) http.Handler {
	// if there is no validator, there's no point in decorating anything
	if a.Validator == nil {
		return delegate
	}

	headerName := a.headerName()
	forbiddenStatusCode := a.forbiddenStatusCode()
	logger := a.logger()

	return http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
		headerValue := request.Header.Get(headerName)
		if len(headerValue) == 0 {
			message := fmt.Sprintf("No %s header", headerName)
			logger.Error(message)
			WriteJsonError(response, forbiddenStatusCode, message)
			return
		}

		token, err := secure.ParseAuthorization(headerValue)
		if err != nil {
			message := fmt.Sprintf("Invalid authorization header [%s]: %s", headerName, err.Error())
			logger.Error(message)
			WriteJsonError(response, forbiddenStatusCode, message)
			return
		}

		ctx := *new(context.Context)
		ctx = context.WithValue(ctx, "method", request.Method)
		ctx = context.WithValue(ctx, "path", request.URL.path)

		valid, err := a.Validator.Validate(ctx, token)
		if err != nil {
			logger.Error("Validation error: %s", err.Error())
		} else if valid {
			// if any validator approves, stop and invoke the delegate
			delegate.ServeHTTP(response, request)
			return
		}

		logger.Error("Request denied: %s", request)
		response.WriteHeader(forbiddenStatusCode)
	})
}
<commit_msg>bug fix<commit_after>package handler

import (
	"context"
	"fmt"
	"github.com/Comcast/webpa-common/logging"
	"github.com/Comcast/webpa-common/secure"
	"net/http"
	"os"
)

// AuthorizationHandler provides decoration for http.Handler instances and will
// ensure that requests pass the validator.  Note that secure.Validators is a Validator
// implementation that allows chaining validators together via logical OR.
type AuthorizationHandler struct {
	HeaderName          string
	ForbiddenStatusCode int
	Validator           secure.Validator
	Logger              logging.Logger
}

// headerName returns the authorization header to use, either a.HeaderName
// or secure.AuthorizationHeader if no header is supplied
func (a AuthorizationHandler) headerName() string {
	if len(a.HeaderName) > 0 {
		return a.HeaderName
	}

	return secure.AuthorizationHeader
}

// forbiddenStatusCode returns a.ForbiddenStatusCode if supplied, otherwise
// http.StatusForbidden is returned
func (a AuthorizationHandler) forbiddenStatusCode() int {
	if a.ForbiddenStatusCode > 0 {
		return a.ForbiddenStatusCode
	}

	return http.StatusForbidden
}

func (a AuthorizationHandler) logger() logging.Logger {
	if a.Logger != nil {
		return a.Logger
	}

	return &logging.LoggerWriter{os.Stdout}
}

// Decorate provides an Alice-compatible constructor that validates requests
// using the configuration specified.
func (a AuthorizationHandler) Decorate(delegate http.Handler) http.Handler {
	// if there is no validator, there's no point in decorating anything
	if a.Validator == nil {
		return delegate
	}

	headerName := a.headerName()
	forbiddenStatusCode := a.forbiddenStatusCode()
	logger := a.logger()

	return http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
		headerValue := request.Header.Get(headerName)
		if len(headerValue) == 0 {
			message := fmt.Sprintf("No %s header", headerName)
			logger.Error(message)
			WriteJsonError(response, forbiddenStatusCode, message)
			return
		}

		token, err := secure.ParseAuthorization(headerValue)
		if err != nil {
			message := fmt.Sprintf("Invalid authorization header [%s]: %s", headerName, err.Error())
			logger.Error(message)
			WriteJsonError(response, forbiddenStatusCode, message)
			return
		}

		ctx := *new(context.Context)
		ctx = context.WithValue(ctx, "method", request.Method)
		ctx = context.WithValue(ctx, "path", request.URL.Path)

		valid, err := a.Validator.Validate(ctx, token)
		if err != nil {
			logger.Error("Validation error: %s", err.Error())
		} else if valid {
			// if any validator approves, stop and invoke the delegate
			delegate.ServeHTTP(response, request)
			return
		}

		logger.Error("Request denied: %s", request)
		response.WriteHeader(forbiddenStatusCode)
	})
}
<|endoftext|>


<commit_before>// SPDX-License-Identifier: MIT

package ast

import (
	"github.com/caixw/apidoc/v7/core"
	"github.com/caixw/apidoc/v7/internal/locale"
	"github.com/caixw/apidoc/v7/internal/token"
)

// ErrNoDocFormat 表示内容并不是一个文档格式
//
// 比如普通的注释内容等。
var ErrNoDocFormat = locale.NewError(locale.ErrIsNotAPIDoc)

// 表示支持的各种数据类型
const (
	TypeNone   string = "" // 空值表示不输出任何内容，仅用于 Request
	TypeBool          = "bool"
	TypeObject        = "object"
	TypeNumber        = "number"
	TypeString        = "string"
)

// 富文本可用的类型
const (
	RichtextTypeHTML     = "html"
	RichtextTypeMarkdown = "markdown"
)

type (
	// APIDoc 对应 apidoc 元素
	APIDoc struct {
		token.BaseTag
		URI      core.URI `apidoc:"-"`
		RootName struct{} `apidoc:"apidoc,meta,usage-apidoc"`

		// 程序的版本号
		//
		// 同时也作为文档格式的版本号。客户端可以依此值确定文档格式。
		// 仅用于输出，文档中不需要指定此值。
		APIDoc *APIDocVersionAttribute `apidoc:"apidoc,attr,usage-apidoc-apidoc,omitempty"`

		// 文档内容的区域信息
		// 如果存在此值，客户端应该尽量根据此值显示相应的界面语言。
		Lang *Attribute `apidoc:"lang,attr,usage-apidoc-lang,omitempty"`

		// 文档的图标
		//
		// 如果采用默认的 xsl 转换，会替换掉页面上的图标和 favicon 图标
		Logo *Attribute `apidoc:"logo,attr,usage-apidoc-logo,omitempty"`

		Created     *DateAttribute    `apidoc:"created,attr,usage-apidoc-created,omitempty"` // 文档的生成时间
		Version     *VersionAttribute `apidoc:"version,attr,usage-apidoc-version,omitempty"` // 文档的版本
		Title       *Element          `apidoc:"title,elem,usage-apidoc-title"`
		Description *Richtext         `apidoc:"description,elem,usage-apidoc-description,omitempty"`
		Contact     *Contact          `apidoc:"contact,elem,usage-apidoc-contact,omitempty"`
		License     *Link             `apidoc:"license,elem,usage-apidoc-license,omitempty"` // 版本信息
		Tags        []*Tag            `apidoc:"tag,elem,usage-apidoc-tags,omitempty"`        // 所有的标签
		Servers     []*Server         `apidoc:"server,elem,usage-apidoc-servers,omitempty"`
		Apis        []*API            `apidoc:"api,elem,usage-apidoc-apis,omitempty"`

		// 公共的报头，所有 API 默认都采用此报头
		Headers []*Param `apidoc:"header,elem,usage-apidoc-headers,omitempty"`

		// 表示所有 API 都有可能返回的内容
		Responses []*Request `apidoc:"response,elem,usage-apidoc-responses,omitempty"`

		// 表示所有接口都支持的文档类型
		Mimetypes []*Element `apidoc:"mimetype,elem,usage-apidoc-mimetypes"`
	}

	// API 表示 <api> 顶层元素
	API struct {
		token.BaseTag
		RootName struct{} `apidoc:"api,meta,usage-apidoc"`

		Version     *VersionAttribute `apidoc:"version,attr,usage-api-version,omitempty"`
		Method      *MethodAttribute  `apidoc:"method,attr,usage-api-method"`
		ID          *Attribute        `apidoc:"id,attr,usage-api-id,omitempty"`
		Path        *Path             `apidoc:"path,elem,usage-api-path"`
		Summary     *Attribute        `apidoc:"summary,attr,usage-api-summary,omitempty"`
		Description *Richtext         `apidoc:"description,elem,usage-api-description,omitempty"`
		Requests    []*Request        `apidoc:"request,elem,usage-api-requests,omitempty"` // 不同的 mimetype 可能会定义不同
		Responses   []*Request        `apidoc:"response,elem,usage-api-responses,omitempty"`
		Callback    *Callback         `apidoc:"callback,elem,usage-api-callback,omitempty"`
		Deprecated  *VersionAttribute `apidoc:"deprecated,attr,usage-api-deprecated,omitempty"`
		Headers     []*Param          `apidoc:"header,elem,usage-api-headers,omitempty"`

		Tags    []*Element `apidoc:"tag,elem,usage-api-tags,omitempty"`
		Servers []*Element `apidoc:"server,elem,usage-api-servers,omitempty"`

		URI core.URI `apidoc:"-"`
		doc *APIDoc
	}

	// Link 表示一个链接
	Link struct {
		token.BaseTag
		RootName struct{} `apidoc:"link,meta,usage-link"`

		Text *Attribute `apidoc:"text,attr,usage-link-text"`
		URL  *Attribute `apidoc:"url,attr,usage-link-url"`
	}

	// Contact 描述联系方式
	Contact struct {
		token.BaseTag
		RootName struct{} `apidoc:"contact,meta,usage-contact"`

		Name  *Attribute `apidoc:"name,attr,usage-contact-name"`
		URL   *Element   `apidoc:"url,elem,usage-contact-url,omitempty"`
		Email *Element   `apidoc:"email,elem,usage-contact-email,omitempty"`
	}

	// Callback 描述回调信息
	Callback struct {
		token.BaseTag
		RootName struct{} `apidoc:"callback,meta,usage-callback"`

		Method      *MethodAttribute  `apidoc:"method,attr,usage-callback-method"`
		Path        *Path             `apidoc:"path,elem,usage-callback-path,omitempty"`
		Summary     *Attribute        `apidoc:"summary,attr,usage-callback-summary,omitempty"`
		Description *Richtext         `apidoc:"description,elem,usage-callback-description,omitempty"`
		Deprecated  *VersionAttribute `apidoc:"deprecated,attr,usage-callback-deprecated,omitempty"`
		Responses   []*Request        `apidoc:"response,elem,usage-callback-responses,omitempty"`
		Requests    []*Request        `apidoc:"request,elem,usage-callback-requests"` // 至少一个
		Headers     []*Param          `apidoc:"header,elem,usage-callback-headers,omitempty"`
	}

	// Enum 表示枚举值
	Enum struct {
		token.BaseTag
		RootName struct{} `apidoc:"enum,meta,usage-enum"`

		Deprecated  *VersionAttribute `apidoc:"deprecated,attr,usage-enum-deprecated,omitempty"`
		Value       *Attribute        `apidoc:"value,attr,usage-enum-value"`
		Summary     *Attribute        `apidoc:"summary,attr,usage-enum-summary,omitempty"`
		Description *Richtext         `apidoc:"description,elem,usage-enum-description,omitempty"`
	}

	// Example 示例代码
	Example struct {
		token.BaseTag
		RootName struct{} `apidoc:"example,meta,usage-example"`

		Mimetype *Attribute `apidoc:"mimetype,attr,usage-example-mimetype"`
		Content  *CData     `apidoc:",cdata,usage-example-content"`
		Summary  *Attribute `apidoc:"summary,attr,usage-example-summary,omitempty"`
	}

	// Param 表示参数类型
	Param struct {
		token.BaseTag
		RootName struct{} `apidoc:"param,meta,usage-param"`

		XML
		Name        *Attribute        `apidoc:"name,attr,usage-param-name"`
		Type        *TypeAttribute    `apidoc:"type,attr,usage-param-type"`
		Deprecated  *VersionAttribute `apidoc:"deprecated,attr,usage-param-deprecated,omitempty"`
		Default     *Attribute        `apidoc:"default,attr,usage-param-default,omitempty"`
		Optional    *BoolAttribute    `apidoc:"optional,attr,usage-param-optional,omitempty"`
		Array       *BoolAttribute    `apidoc:"array,attr,usage-param-array,omitempty"`
		Items       []*Param          `apidoc:"param,elem,usage-param-items,omitempty"`
		Summary     *Attribute        `apidoc:"summary,attr,usage-param-summary,omitempty"`
		Enums       []*Enum           `apidoc:"enum,elem,usage-param-enums,omitempty"`
		Description *Richtext         `apidoc:"description,elem,usage-param-description,omitempty"`

		// 数组参数是否展开
		//
		// 数组可以有以下两种展示方式：
		//  1. k=1&k=2
		//  2. k=1,2
		// 1 为默认方式，ArrayStyle 为 true，则展示为第二种方式
		// 该参数目前仅在查询参数中启作用
		ArrayStyle *BoolAttribute `apidoc:"array-style,attr,usage-param-array-style,omitempty"`
	}

	// Path 路径信息
	Path struct {
		token.BaseTag
		RootName struct{} `apidoc:"path,meta,usage-path"`

		Path    *Attribute `apidoc:"path,attr,usage-path-path"`
		Params  []*Param   `apidoc:"param,elem,usage-path-params,omitempty"`
		Queries []*Param   `apidoc:"query,elem,usage-path-queries,omitempty"`
	}

	// Request 请求内容
	Request struct {
		token.BaseTag
		RootName struct{} `apidoc:"request,meta,usage-request"`

		XML
		// 一般无用，但是用于描述 XML 对象时，可以用来表示顶层元素的名称
		Name *Attribute `apidoc:"name,attr,usage-request-name,omitempty"`

		Type        *TypeAttribute    `apidoc:"type,attr,usage-request-type,omitempty"`
		Deprecated  *VersionAttribute `apidoc:"deprecated,attr,usage-request-deprecated,omitempty"`
		Enums       []*Enum           `apidoc:"enum,elem,usage-request-enums,omitempty"`
		Array       *BoolAttribute    `apidoc:"array,attr,usage-request-array,omitempty"`
		Items       []*Param          `apidoc:"param,elem,usage-request-items,omitempty"`
		Summary     *Attribute        `apidoc:"summary,attr,usage-request-summary,omitempty"`
		Status      *StatusAttribute  `apidoc:"status,attr,usage-request-status,omitempty"`
		Mimetype    *Attribute        `apidoc:"mimetype,attr,usage-request-mimetype,omitempty"`
		Examples    []*Example        `apidoc:"example,elem,usage-request-examples,omitempty"`
		Headers     []*Param          `apidoc:"header,elem,usage-request-headers,omitempty"` // 当前独有的报头，公用的可以放在 API 中
		Description *Richtext         `apidoc:"description,elem,usage-request-description,omitempty"`
	}

	// Richtext 富文本内容
	Richtext struct {
		token.BaseTag
		RootName struct{} `apidoc:"richtext,meta,usage-richtext"`

		Type *Attribute `apidoc:"type,attr,usage-richtext-type"` // 文档类型，可以是 html 或是 markdown
		Text *CData     `apidoc:",cdata,usage-richtext-text"`
	}

	// Tag 标签内容
	Tag struct {
		token.BaseTag
		RootName struct{} `apidoc:"tag,meta,usage-tag"`

		Name       *Attribute        `apidoc:"name,attr,usage-tag-name"`   // 标签的唯一 ID
		Title      *Attribute        `apidoc:"title,attr,usage-tag-title"` // 显示的名称
		Deprecated *VersionAttribute `apidoc:"deprecated,attr,usage-tag-deprecated,omitempty"`
	}

	// Server 服务信息
	Server struct {
		token.BaseTag
		RootName struct{} `apidoc:"server,meta,usage-server"`

		Name        *Attribute        `apidoc:"name,attr,usage-server-name"` // 字面名称，需要唯一
		URL         *Attribute        `apidoc:"url,attr,usage-server-url"`
		Deprecated  *VersionAttribute `apidoc:"deprecated,attr,usage-server-deprecated,omitempty"`
		Summary     *Attribute        `apidoc:"summary,attr,usage-server-summary,omitempty"`
		Description *Richtext         `apidoc:"description,elem,usage-server-description,omitempty"`
	}

	// XML 仅作用于 XML 的几个属性
	XML struct {
		XMLAttr     *BoolAttribute `apidoc:"xml-attr,attr,usage-xml-attr,omitempty"`        // 作为父元素的 XML 属性存在
		XMLExtract  *BoolAttribute `apidoc:"xml-extract,attr,usage-xml-extract,omitempty"`  // 提取当前内容作为父元素的内容
		XMLNS       *Attribute     `apidoc:"xml-ns,attr,usage-xml-ns,omitempty"`            // 命名空间
		XMLNSPrefix *Attribute     `apidoc:"xml-ns-prefix,attr,usage-xml-prefix,omitempty"` // 命名空间前缀
		XMLWrapped  *Attribute     `apidoc:"xml-wrapped,attr,usage-xml-wrapped,omitempty"`  // 如果当前元素是数组，是否将其包含在 wrapped 中
	}
)

// V 返回当前富文本中的内容
func (r *Richtext) V() string {
	if r == nil || r.Text == nil {
		return ""
	}
	return r.Text.Value.Value
}

// Param 转换成 Param 对象
//
// Request 可以说是 Param 的超级，两者在大部分情况下能用。
func (r *Request) Param() *Param {
	if r == nil {
		return nil
	}

	return &Param{
		XML:         r.XML,
		Name:        r.Name,
		Type:        r.Type,
		Deprecated:  r.Deprecated,
		Optional:    &BoolAttribute{Value: Bool{Value: true}},
		Array:       r.Array,
		Items:       r.Items,
		Summary:     r.Summary,
		Enums:       r.Enums,
		Description: r.Description,
	}
}

// DeleteURI 删除与 uri 相关的文档内容
func (doc *APIDoc) DeleteURI(uri core.URI) {
	for index, api := range doc.Apis {
		if api.URI == uri {
			doc.Apis = append(doc.Apis[:index], doc.Apis[index+1:]...)
		}
	}

	if doc.URI == uri {
		*doc = APIDoc{
			Apis: doc.Apis,
		}
	}
}
<commit_msg>fix(internal/ast): 修正 API 说明文字引用错误<commit_after>// SPDX-License-Identifier: MIT

package ast

import (
	"github.com/caixw/apidoc/v7/core"
	"github.com/caixw/apidoc/v7/internal/locale"
	"github.com/caixw/apidoc/v7/internal/token"
)

// ErrNoDocFormat 表示内容并不是一个文档格式
//
// 比如普通的注释内容等。
var ErrNoDocFormat = locale.NewError(locale.ErrIsNotAPIDoc)

// 表示支持的各种数据类型
const (
	TypeNone   string = "" // 空值表示不输出任何内容，仅用于 Request
	TypeBool          = "bool"
	TypeObject        = "object"
	TypeNumber        = "number"
	TypeString        = "string"
)

// 富文本可用的类型
const (
	RichtextTypeHTML     = "html"
	RichtextTypeMarkdown = "markdown"
)

type (
	// APIDoc 对应 apidoc 元素
	APIDoc struct {
		token.BaseTag
		URI      core.URI `apidoc:"-"`
		RootName struct{} `apidoc:"apidoc,meta,usage-apidoc"`

		// 程序的版本号
		//
		// 同时也作为文档格式的版本号。客户端可以依此值确定文档格式。
		// 仅用于输出，文档中不需要指定此值。
		APIDoc *APIDocVersionAttribute `apidoc:"apidoc,attr,usage-apidoc-apidoc,omitempty"`

		// 文档内容的区域信息
		// 如果存在此值，客户端应该尽量根据此值显示相应的界面语言。
		Lang *Attribute `apidoc:"lang,attr,usage-apidoc-lang,omitempty"`

		// 文档的图标
		//
		// 如果采用默认的 xsl 转换，会替换掉页面上的图标和 favicon 图标
		Logo *Attribute `apidoc:"logo,attr,usage-apidoc-logo,omitempty"`

		Created     *DateAttribute    `apidoc:"created,attr,usage-apidoc-created,omitempty"` // 文档的生成时间
		Version     *VersionAttribute `apidoc:"version,attr,usage-apidoc-version,omitempty"` // 文档的版本
		Title       *Element          `apidoc:"title,elem,usage-apidoc-title"`
		Description *Richtext         `apidoc:"description,elem,usage-apidoc-description,omitempty"`
		Contact     *Contact          `apidoc:"contact,elem,usage-apidoc-contact,omitempty"`
		License     *Link             `apidoc:"license,elem,usage-apidoc-license,omitempty"` // 版本信息
		Tags        []*Tag            `apidoc:"tag,elem,usage-apidoc-tags,omitempty"`        // 所有的标签
		Servers     []*Server         `apidoc:"server,elem,usage-apidoc-servers,omitempty"`
		Apis        []*API            `apidoc:"api,elem,usage-apidoc-apis,omitempty"`

		// 公共的报头，所有 API 默认都采用此报头
		Headers []*Param `apidoc:"header,elem,usage-apidoc-headers,omitempty"`

		// 表示所有 API 都有可能返回的内容
		Responses []*Request `apidoc:"response,elem,usage-apidoc-responses,omitempty"`

		// 表示所有接口都支持的文档类型
		Mimetypes []*Element `apidoc:"mimetype,elem,usage-apidoc-mimetypes"`
	}

	// API 表示 <api> 顶层元素
	API struct {
		token.BaseTag
		RootName struct{} `apidoc:"api,meta,usage-api"`

		Version     *VersionAttribute `apidoc:"version,attr,usage-api-version,omitempty"`
		Method      *MethodAttribute  `apidoc:"method,attr,usage-api-method"`
		ID          *Attribute        `apidoc:"id,attr,usage-api-id,omitempty"`
		Path        *Path             `apidoc:"path,elem,usage-api-path"`
		Summary     *Attribute        `apidoc:"summary,attr,usage-api-summary,omitempty"`
		Description *Richtext         `apidoc:"description,elem,usage-api-description,omitempty"`
		Requests    []*Request        `apidoc:"request,elem,usage-api-requests,omitempty"` // 不同的 mimetype 可能会定义不同
		Responses   []*Request        `apidoc:"response,elem,usage-api-responses,omitempty"`
		Callback    *Callback         `apidoc:"callback,elem,usage-api-callback,omitempty"`
		Deprecated  *VersionAttribute `apidoc:"deprecated,attr,usage-api-deprecated,omitempty"`
		Headers     []*Param          `apidoc:"header,elem,usage-api-headers,omitempty"`

		Tags    []*Element `apidoc:"tag,elem,usage-api-tags,omitempty"`
		Servers []*Element `apidoc:"server,elem,usage-api-servers,omitempty"`

		URI core.URI `apidoc:"-"`
		doc *APIDoc
	}

	// Link 表示一个链接
	Link struct {
		token.BaseTag
		RootName struct{} `apidoc:"link,meta,usage-link"`

		Text *Attribute `apidoc:"text,attr,usage-link-text"`
		URL  *Attribute `apidoc:"url,attr,usage-link-url"`
	}

	// Contact 描述联系方式
	Contact struct {
		token.BaseTag
		RootName struct{} `apidoc:"contact,meta,usage-contact"`

		Name  *Attribute `apidoc:"name,attr,usage-contact-name"`
		URL   *Element   `apidoc:"url,elem,usage-contact-url,omitempty"`
		Email *Element   `apidoc:"email,elem,usage-contact-email,omitempty"`
	}

	// Callback 描述回调信息
	Callback struct {
		token.BaseTag
		RootName struct{} `apidoc:"callback,meta,usage-callback"`

		Method      *MethodAttribute  `apidoc:"method,attr,usage-callback-method"`
		Path        *Path             `apidoc:"path,elem,usage-callback-path,omitempty"`
		Summary     *Attribute        `apidoc:"summary,attr,usage-callback-summary,omitempty"`
		Description *Richtext         `apidoc:"description,elem,usage-callback-description,omitempty"`
		Deprecated  *VersionAttribute `apidoc:"deprecated,attr,usage-callback-deprecated,omitempty"`
		Responses   []*Request        `apidoc:"response,elem,usage-callback-responses,omitempty"`
		Requests    []*Request        `apidoc:"request,elem,usage-callback-requests"` // 至少一个
		Headers     []*Param          `apidoc:"header,elem,usage-callback-headers,omitempty"`
	}

	// Enum 表示枚举值
	Enum struct {
		token.BaseTag
		RootName struct{} `apidoc:"enum,meta,usage-enum"`

		Deprecated  *VersionAttribute `apidoc:"deprecated,attr,usage-enum-deprecated,omitempty"`
		Value       *Attribute        `apidoc:"value,attr,usage-enum-value"`
		Summary     *Attribute        `apidoc:"summary,attr,usage-enum-summary,omitempty"`
		Description *Richtext         `apidoc:"description,elem,usage-enum-description,omitempty"`
	}

	// Example 示例代码
	Example struct {
		token.BaseTag
		RootName struct{} `apidoc:"example,meta,usage-example"`

		Mimetype *Attribute `apidoc:"mimetype,attr,usage-example-mimetype"`
		Content  *CData     `apidoc:",cdata,usage-example-content"`
		Summary  *Attribute `apidoc:"summary,attr,usage-example-summary,omitempty"`
	}

	// Param 表示参数类型
	Param struct {
		token.BaseTag
		RootName struct{} `apidoc:"param,meta,usage-param"`

		XML
		Name        *Attribute        `apidoc:"name,attr,usage-param-name"`
		Type        *TypeAttribute    `apidoc:"type,attr,usage-param-type"`
		Deprecated  *VersionAttribute `apidoc:"deprecated,attr,usage-param-deprecated,omitempty"`
		Default     *Attribute        `apidoc:"default,attr,usage-param-default,omitempty"`
		Optional    *BoolAttribute    `apidoc:"optional,attr,usage-param-optional,omitempty"`
		Array       *BoolAttribute    `apidoc:"array,attr,usage-param-array,omitempty"`
		Items       []*Param          `apidoc:"param,elem,usage-param-items,omitempty"`
		Summary     *Attribute        `apidoc:"summary,attr,usage-param-summary,omitempty"`
		Enums       []*Enum           `apidoc:"enum,elem,usage-param-enums,omitempty"`
		Description *Richtext         `apidoc:"description,elem,usage-param-description,omitempty"`

		// 数组参数是否展开
		//
		// 数组可以有以下两种展示方式：
		//  1. k=1&k=2
		//  2. k=1,2
		// 1 为默认方式，ArrayStyle 为 true，则展示为第二种方式
		// 该参数目前仅在查询参数中启作用
		ArrayStyle *BoolAttribute `apidoc:"array-style,attr,usage-param-array-style,omitempty"`
	}

	// Path 路径信息
	Path struct {
		token.BaseTag
		RootName struct{} `apidoc:"path,meta,usage-path"`

		Path    *Attribute `apidoc:"path,attr,usage-path-path"`
		Params  []*Param   `apidoc:"param,elem,usage-path-params,omitempty"`
		Queries []*Param   `apidoc:"query,elem,usage-path-queries,omitempty"`
	}

	// Request 请求内容
	Request struct {
		token.BaseTag
		RootName struct{} `apidoc:"request,meta,usage-request"`

		XML
		// 一般无用，但是用于描述 XML 对象时，可以用来表示顶层元素的名称
		Name *Attribute `apidoc:"name,attr,usage-request-name,omitempty"`

		Type        *TypeAttribute    `apidoc:"type,attr,usage-request-type,omitempty"`
		Deprecated  *VersionAttribute `apidoc:"deprecated,attr,usage-request-deprecated,omitempty"`
		Enums       []*Enum           `apidoc:"enum,elem,usage-request-enums,omitempty"`
		Array       *BoolAttribute    `apidoc:"array,attr,usage-request-array,omitempty"`
		Items       []*Param          `apidoc:"param,elem,usage-request-items,omitempty"`
		Summary     *Attribute        `apidoc:"summary,attr,usage-request-summary,omitempty"`
		Status      *StatusAttribute  `apidoc:"status,attr,usage-request-status,omitempty"`
		Mimetype    *Attribute        `apidoc:"mimetype,attr,usage-request-mimetype,omitempty"`
		Examples    []*Example        `apidoc:"example,elem,usage-request-examples,omitempty"`
		Headers     []*Param          `apidoc:"header,elem,usage-request-headers,omitempty"` // 当前独有的报头，公用的可以放在 API 中
		Description *Richtext         `apidoc:"description,elem,usage-request-description,omitempty"`
	}

	// Richtext 富文本内容
	Richtext struct {
		token.BaseTag
		RootName struct{} `apidoc:"richtext,meta,usage-richtext"`

		Type *Attribute `apidoc:"type,attr,usage-richtext-type"` // 文档类型，可以是 html 或是 markdown
		Text *CData     `apidoc:",cdata,usage-richtext-text"`
	}

	// Tag 标签内容
	Tag struct {
		token.BaseTag
		RootName struct{} `apidoc:"tag,meta,usage-tag"`

		Name       *Attribute        `apidoc:"name,attr,usage-tag-name"`   // 标签的唯一 ID
		Title      *Attribute        `apidoc:"title,attr,usage-tag-title"` // 显示的名称
		Deprecated *VersionAttribute `apidoc:"deprecated,attr,usage-tag-deprecated,omitempty"`
	}

	// Server 服务信息
	Server struct {
		token.BaseTag
		RootName struct{} `apidoc:"server,meta,usage-server"`

		Name        *Attribute        `apidoc:"name,attr,usage-server-name"` // 字面名称，需要唯一
		URL         *Attribute        `apidoc:"url,attr,usage-server-url"`
		Deprecated  *VersionAttribute `apidoc:"deprecated,attr,usage-server-deprecated,omitempty"`
		Summary     *Attribute        `apidoc:"summary,attr,usage-server-summary,omitempty"`
		Description *Richtext         `apidoc:"description,elem,usage-server-description,omitempty"`
	}

	// XML 仅作用于 XML 的几个属性
	XML struct {
		XMLAttr     *BoolAttribute `apidoc:"xml-attr,attr,usage-xml-attr,omitempty"`        // 作为父元素的 XML 属性存在
		XMLExtract  *BoolAttribute `apidoc:"xml-extract,attr,usage-xml-extract,omitempty"`  // 提取当前内容作为父元素的内容
		XMLNS       *Attribute     `apidoc:"xml-ns,attr,usage-xml-ns,omitempty"`            // 命名空间
		XMLNSPrefix *Attribute     `apidoc:"xml-ns-prefix,attr,usage-xml-prefix,omitempty"` // 命名空间前缀
		XMLWrapped  *Attribute     `apidoc:"xml-wrapped,attr,usage-xml-wrapped,omitempty"`  // 如果当前元素是数组，是否将其包含在 wrapped 中
	}
)

// V 返回当前富文本中的内容
func (r *Richtext) V() string {
	if r == nil || r.Text == nil {
		return ""
	}
	return r.Text.Value.Value
}

// Param 转换成 Param 对象
//
// Request 可以说是 Param 的超级，两者在大部分情况下能用。
func (r *Request) Param() *Param {
	if r == nil {
		return nil
	}

	return &Param{
		XML:         r.XML,
		Name:        r.Name,
		Type:        r.Type,
		Deprecated:  r.Deprecated,
		Optional:    &BoolAttribute{Value: Bool{Value: true}},
		Array:       r.Array,
		Items:       r.Items,
		Summary:     r.Summary,
		Enums:       r.Enums,
		Description: r.Description,
	}
}

// DeleteURI 删除与 uri 相关的文档内容
func (doc *APIDoc) DeleteURI(uri core.URI) {
	for index, api := range doc.Apis {
		if api.URI == uri {
			doc.Apis = append(doc.Apis[:index], doc.Apis[index+1:]...)
		}
	}

	if doc.URI == uri {
		*doc = APIDoc{
			Apis: doc.Apis,
		}
	}
}
<|endoftext|>


<commit_before>package index

// #cgo  CFLAGS:-mpopcnt

import (
	"fmt"
	"log"

	"tux21b.org/v1/gocql"
)

type CassandraStorage struct {
	db *gocql.Session
}

func BuildSchema() {
	/*
			   "CREATE KEYSPACE IF NOT EXISTS hotbox WITH strategy_class = SimpleStrategy AND strategy_options:replication_factor = 1"
		       create keyspace if not exists hotbox with replication = { 'class': 'SimpleStrategy', 'replication_factor' : 1} and durable_writes = true;
			   CREATE TABLE IF NOT EXISTS bitmap ( bitmap_id bigint, db varchar, frame varchar, slice int, filter int, ChunkKey bigint,   BlockIndex int,   block bigint,    PRIMARY KEY ((bitmap_id, db, frame,slice),ChunkKey,BlockIndex) )
			   "
	*/

}
func NewCassStorage(host, keyspace string) Storage {
	obj := new(CassandraStorage)
	//cluster := gocql.NewCluster("127.0.0.1")
	cluster := gocql.NewCluster(host)
	cluster.Keyspace = keyspace
	cluster.Consistency = gocql.Quorum
	//cluster.ProtoVersion = 1
	// cluster.CQLVersion = "3.0.0"
	session, err := cluster.CreateSession()
	if err != nil {
		log.Fatal(err)
	}

	err = session.Query(fmt.Sprintf("USE %s", keyspace)).Exec()
	if err != nil {
	}
	obj.db = session
	return obj
}

func (c *CassandraStorage) Fetch(bitmap_id uint64, db string, frame string, slice int) (IBitmap, uint64) {
	var dumb = COUNTERMASK
	last_key := int64(dumb)
	marker := int64(dumb)
	var id = int64(bitmap_id)

	var (
		chunk            *Chunk
		chunk_key, block int64
		block_index      uint32
		s8               uint8
		filter           int
	)
	log.Println("FETCHING ", bitmap_id, db, slice)

	bitmap := CreateRBBitmap()
	iter := c.db.Query("SELECT filter,Chunkkey,BlockIndex,block FROM bitmap WHERE bitmap_id=? AND db=? AND frame=? AND slice=? ", id, db, frame, slice).Iter()
	count := int64(0)

	for iter.Scan(&filter, &chunk_key, &block_index, &block) {
		s8 = uint8(block_index)
		if chunk_key != marker {
			if chunk_key != last_key {
				chunk = &Chunk{uint64(chunk_key), BlockArray{}}
				bitmap.AddChunk(chunk)
			}
			chunk.Value.Block[s8] = uint64(block)

		} else {
			count = block
		}
		last_key = chunk_key

	}
	bitmap.SetCount(uint64(count))
	return bitmap, uint64(filter)
}

func (c *CassandraStorage) Store(id int64, db string, frame string, slice int, filter uint64, bitmap *Bitmap) error {
	for i := bitmap.Min(); !i.Limit(); i = i.Next() {
		var chunk = i.Item()
		for idx, block := range chunk.Value.Block {
			block_index := int32(idx)
			iblock := int64(block)
			if iblock != 0 {
				c.StoreBlock(id, db, frame, slice, filter, int64(chunk.Key), block_index, iblock)
			}
		}
	}
	cnt := int64(BitCount(bitmap))

	var dumb = COUNTERMASK
	COUNTER_KEY := int64(dumb)

	c.StoreBlock(id, db, frame, slice, filter, COUNTER_KEY, 0, cnt)
	return nil
}

func (c *CassandraStorage) StoreBlock(id int64, db string, frame string, slice int, filter uint64, chunk int64, block_index int32, block int64) error {

	if err := c.db.Query(`
        INSERT INTO bitmap ( bitmap_id, db, frame, slice , filter, ChunkKey, BlockIndex, block) VALUES (?,?,?,?,?,?,?,?);`, id, db, frame, slice, int(filter), chunk, block_index, block).Exec(); err != nil {
		log.Println(err)
		log.Println("INSERT ", id, chunk, block_index)
		return err
	}
	return nil
}
<commit_msg>removed some logging<commit_after>package index

// #cgo  CFLAGS:-mpopcnt

import (
	"fmt"
	"log"

	"tux21b.org/v1/gocql"
)

type CassandraStorage struct {
	db *gocql.Session
}

func BuildSchema() {
	/*
			   "CREATE KEYSPACE IF NOT EXISTS hotbox WITH strategy_class = SimpleStrategy AND strategy_options:replication_factor = 1"
		       create keyspace if not exists hotbox with replication = { 'class': 'SimpleStrategy', 'replication_factor' : 1} and durable_writes = true;
			   CREATE TABLE IF NOT EXISTS bitmap ( bitmap_id bigint, db varchar, frame varchar, slice int, filter int, ChunkKey bigint,   BlockIndex int,   block bigint,    PRIMARY KEY ((bitmap_id, db, frame,slice),ChunkKey,BlockIndex) )
			   "
	*/

}
func NewCassStorage(host, keyspace string) Storage {
	obj := new(CassandraStorage)
	//cluster := gocql.NewCluster("127.0.0.1")
	cluster := gocql.NewCluster(host)
	cluster.Keyspace = keyspace
	cluster.Consistency = gocql.Quorum
	//cluster.ProtoVersion = 1
	// cluster.CQLVersion = "3.0.0"
	session, err := cluster.CreateSession()
	if err != nil {
		log.Fatal(err)
	}

	err = session.Query(fmt.Sprintf("USE %s", keyspace)).Exec()
	if err != nil {
	}
	obj.db = session
	return obj
}

func (c *CassandraStorage) Fetch(bitmap_id uint64, db string, frame string, slice int) (IBitmap, uint64) {
	var dumb = COUNTERMASK
	last_key := int64(dumb)
	marker := int64(dumb)
	var id = int64(bitmap_id)

	var (
		chunk            *Chunk
		chunk_key, block int64
		block_index      uint32
		s8               uint8
		filter           int
	)

	bitmap := CreateRBBitmap()
	iter := c.db.Query("SELECT filter,Chunkkey,BlockIndex,block FROM bitmap WHERE bitmap_id=? AND db=? AND frame=? AND slice=? ", id, db, frame, slice).Iter()
	count := int64(0)

	for iter.Scan(&filter, &chunk_key, &block_index, &block) {
		s8 = uint8(block_index)
		if chunk_key != marker {
			if chunk_key != last_key {
				chunk = &Chunk{uint64(chunk_key), BlockArray{}}
				bitmap.AddChunk(chunk)
			}
			chunk.Value.Block[s8] = uint64(block)

		} else {
			count = block
		}
		last_key = chunk_key

	}
	bitmap.SetCount(uint64(count))
	return bitmap, uint64(filter)
}

func (c *CassandraStorage) Store(id int64, db string, frame string, slice int, filter uint64, bitmap *Bitmap) error {
	for i := bitmap.Min(); !i.Limit(); i = i.Next() {
		var chunk = i.Item()
		for idx, block := range chunk.Value.Block {
			block_index := int32(idx)
			iblock := int64(block)
			if iblock != 0 {
				c.StoreBlock(id, db, frame, slice, filter, int64(chunk.Key), block_index, iblock)
			}
		}
	}
	cnt := int64(BitCount(bitmap))

	var dumb = COUNTERMASK
	COUNTER_KEY := int64(dumb)

	c.StoreBlock(id, db, frame, slice, filter, COUNTER_KEY, 0, cnt)
	return nil
}

func (c *CassandraStorage) StoreBlock(id int64, db string, frame string, slice int, filter uint64, chunk int64, block_index int32, block int64) error {

	if err := c.db.Query(`
        INSERT INTO bitmap ( bitmap_id, db, frame, slice , filter, ChunkKey, BlockIndex, block) VALUES (?,?,?,?,?,?,?,?);`, id, db, frame, slice, int(filter), chunk, block_index, block).Exec(); err != nil {
		log.Println(err)
		log.Println("INSERT ", id, chunk, block_index)
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package srtp

/*
#cgo pkg-config: libsrtp2

#include "srtp.h"

*/
import "C"
import (
	"fmt"
	"unsafe"
)

func init() {
	C.srtp_init()
}

type Session struct {
	rawSession *_Ctype_srtp_t
}

func New(ClientWriteKey, ServerWriteKey []byte, profile string) *Session {
	rawClientWriteKey := C.CBytes(ClientWriteKey)
	rawServerWriteKey := C.CBytes(ServerWriteKey)
	rawProfile := C.CString(profile)
	defer func() {
		C.free(unsafe.Pointer(rawClientWriteKey))
		C.free(unsafe.Pointer(rawServerWriteKey))
		C.free(unsafe.Pointer(rawProfile))
	}()

	if sess := C.srtp_create_session(rawClientWriteKey, rawServerWriteKey, rawProfile); sess != nil {
		return &Session{
			rawSession: sess,
		}
	}

	return nil
}

func (s *Session) DecryptPacket(encryted []byte) (ok bool, unencryted []byte) {
	rawIn := C.CBytes(encryted)
	defer C.free(unsafe.Pointer(rawIn))

	if rawPacket := C.srtp_decrypt_packet(s.rawSession, rawIn, C.int(len(encryted))); rawPacket != nil {
		fmt.Println(rawPacket)
		return true, C.GoBytes(rawPacket.data, rawPacket.len)
	}

	return ok, unencryted
}
<commit_msg>Don't print packet after decrypt<commit_after>package srtp

/*
#cgo pkg-config: libsrtp2

#include "srtp.h"

*/
import "C"
import (
	"unsafe"
)

func init() {
	C.srtp_init()
}

type Session struct {
	rawSession *_Ctype_srtp_t
}

func New(ClientWriteKey, ServerWriteKey []byte, profile string) *Session {
	rawClientWriteKey := C.CBytes(ClientWriteKey)
	rawServerWriteKey := C.CBytes(ServerWriteKey)
	rawProfile := C.CString(profile)
	defer func() {
		C.free(unsafe.Pointer(rawClientWriteKey))
		C.free(unsafe.Pointer(rawServerWriteKey))
		C.free(unsafe.Pointer(rawProfile))
	}()

	if sess := C.srtp_create_session(rawClientWriteKey, rawServerWriteKey, rawProfile); sess != nil {
		return &Session{
			rawSession: sess,
		}
	}

	return nil
}

func (s *Session) DecryptPacket(encryted []byte) (ok bool, unencryted []byte) {
	rawIn := C.CBytes(encryted)
	defer C.free(unsafe.Pointer(rawIn))

	if rawPacket := C.srtp_decrypt_packet(s.rawSession, rawIn, C.int(len(encryted))); rawPacket != nil {
		return true, C.GoBytes(rawPacket.data, rawPacket.len)
	}

	return ok, unencryted
}
<|endoftext|>


<commit_before>// Copyright 2016 The Prometheus Authors
// 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 frankenstein

import (
	"sort"

	"github.com/prometheus/common/model"
	"github.com/prometheus/prometheus/storage/local"
	"github.com/prometheus/prometheus/storage/metric"
)

// This is a struct and not just a renamed type because otherwise the Metric
// field and Metric() methods would clash.
type sampleStreamIterator struct {
	ss *model.SampleStream
}

func (it sampleStreamIterator) Metric() model.Metric {
	return it.ss.Metric
}

func (it sampleStreamIterator) ValueAtOrBeforeTime(ts model.Time) model.SamplePair {
	// TODO: This is a naive inefficient approach - in reality, queries go mostly
	// linearly through iterators, and we will want to make successive calls to
	// this method more efficient by taking into account the last result index
	// somehow (similarly to how it's done in Prometheus's
	// memorySeriesIterators).
	i := sort.Search(len(it.ss.Values), func(n int) bool {
		return it.ss.Values[n].Timestamp.After(ts)
	})
	if i == 0 {
		return local.ZeroSamplePair
	}
	return it.ss.Values[i]
}

func (it sampleStreamIterator) RangeValues(in metric.Interval) []model.SamplePair {
	n := len(it.ss.Values)
	start := sort.Search(n, func(i int) bool {
		return !it.ss.Values[i].Timestamp.Before(in.OldestInclusive)
	})
	end := sort.Search(n, func(i int) bool {
		return it.ss.Values[i].Timestamp.After(in.NewestInclusive)
	})

	if start == n {
		return nil
	}

	return it.ss.Values[start:end]
}
<commit_msg>Fix iterator index-out-of-bounds error.<commit_after>// Copyright 2016 The Prometheus Authors
// 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 frankenstein

import (
	"sort"

	"github.com/prometheus/common/model"
	"github.com/prometheus/prometheus/storage/local"
	"github.com/prometheus/prometheus/storage/metric"
)

// This is a struct and not just a renamed type because otherwise the Metric
// field and Metric() methods would clash.
type sampleStreamIterator struct {
	ss *model.SampleStream
}

func (it sampleStreamIterator) Metric() model.Metric {
	return it.ss.Metric
}

func (it sampleStreamIterator) ValueAtOrBeforeTime(ts model.Time) model.SamplePair {
	// TODO: This is a naive inefficient approach - in reality, queries go mostly
	// linearly through iterators, and we will want to make successive calls to
	// this method more efficient by taking into account the last result index
	// somehow (similarly to how it's done in Prometheus's
	// memorySeriesIterators).
	i := sort.Search(len(it.ss.Values), func(n int) bool {
		return it.ss.Values[n].Timestamp.After(ts)
	})
	if i == 0 {
		return local.ZeroSamplePair
	}
	return it.ss.Values[i-1]
}

func (it sampleStreamIterator) RangeValues(in metric.Interval) []model.SamplePair {
	n := len(it.ss.Values)
	start := sort.Search(n, func(i int) bool {
		return !it.ss.Values[i].Timestamp.Before(in.OldestInclusive)
	})
	end := sort.Search(n, func(i int) bool {
		return it.ss.Values[i].Timestamp.After(in.NewestInclusive)
	})

	if start == n {
		return nil
	}

	return it.ss.Values[start:end]
}
<|endoftext|>


<commit_before>package imgscale

import (
	"encoding/json"
	"fmt"
	"os"
	"regexp"
	"strings"
)

type Format struct {
	Prefix    string
	Height    uint
	Ratio     float64
	Thumbnail bool
}

type Config struct {
	Path    string
	Prefix  string
	Formats []*Format
	Exts    []string
	Comment string
}

func configure(config *Config) *handler {
	for _, ext := range config.Exts {
		if _, ok := supportedExts[ext]; !ok {
			panic(fmt.Sprintf("Extension '%s' not supported", ext))
		}
	}

	prefixes := make([]string, len(config.Formats))
	formats := make(map[string]*Format)
	for i, format := range config.Formats {
		prefixes[i] = format.Prefix
		formats[format.Prefix] = format
	}

	path := fmt.Sprintf("/%s/(?P<format>%s)/(?P<filename>.+)\\.(?P<ext>%s)", config.Prefix, strings.Join(prefixes, "|"), strings.Join(config.Exts, "|"))
	h := handler{formats: formats, config: config, regexp: regexp.MustCompile(path), supportedExts: supportedExts}
	h.SetValidator(defaultValidator{})
	return &h
}

func LoadConfig(filename string) *Config {
	file, err := os.Open(filename)
	if err != nil {
		panic(err)
	}
	defer file.Close()
	decoder := json.NewDecoder(file)
	conf := Config{}
	err = decoder.Decode(&conf)
	if err != nil {
		panic(err)
	}
	return &conf
}
<commit_msg>Format Prefix needs to be unique<commit_after>package imgscale

import (
	"encoding/json"
	"fmt"
	"os"
	"regexp"
	"strings"
)

type Format struct {
	Prefix    string
	Height    uint
	Ratio     float64
	Thumbnail bool
}

type Config struct {
	Path    string
	Prefix  string
	Formats []*Format
	Exts    []string
	Comment string
}

func configure(config *Config) *handler {
	for _, ext := range config.Exts {
		if _, ok := supportedExts[ext]; !ok {
			panic(fmt.Sprintf("Extension '%s' not supported", ext))
		}
	}

	prefixes := make([]string, len(config.Formats))
	formats := make(map[string]*Format)
	for i, format := range config.Formats {
		if _, exists := formats[format.Prefix]; exists {
			panic(fmt.Sprintf("You can not have same prefix '%s' for 2 different formats", format.Prefix))
		}
		prefixes[i] = format.Prefix
		formats[format.Prefix] = format
	}

	path := fmt.Sprintf("/%s/(?P<format>%s)/(?P<filename>.+)\\.(?P<ext>%s)", config.Prefix, strings.Join(prefixes, "|"), strings.Join(config.Exts, "|"))
	h := handler{formats: formats, config: config, regexp: regexp.MustCompile(path), supportedExts: supportedExts}
	h.SetValidator(defaultValidator{})
	return &h
}

func LoadConfig(filename string) *Config {
	file, err := os.Open(filename)
	if err != nil {
		panic(err)
	}
	defer file.Close()
	decoder := json.NewDecoder(file)
	conf := Config{}
	err = decoder.Decode(&conf)
	if err != nil {
		panic(err)
	}
	return &conf
}
<|endoftext|>


<commit_before><commit_msg>log polish<commit_after><|endoftext|>


<commit_before><commit_msg>Add Pai#Suit<commit_after><|endoftext|>


<commit_before>/*
Copyright (c) 2016, Fabrizio Soppelsa
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

* Neither the name of ansible-swarm nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

=============================================================================

Ansible docker_swarm module
Requires Ansible 2.2+
go get github.com/docker/engine-api/types/swarm
go get github.com/docker/engine-api/client
go get github.com/foppelsa/ansible
*/

package main

import (
	"encoding/json"
	"github.com/docker/engine-api/client"
	"github.com/docker/engine-api/types/swarm"
	"github.com/docker/go-connections/tlsconfig"
	"github.com/fsoppelsa/ansible"
	"golang.org/x/net/context"
	"net/http"
	"os"
	"path/filepath"
)

/*
  Sample:

    - name: Operate swarm clusters and nodes
      docker_swarm:
        role: "master"|"slave"
        operation: "init"|"join"|"leave"|"update"|"promote"|"demote"
        detach: yes
		docker_url: "tcp://192.168.99.101:2376"
		join_url: ["tcp://192.168.99.100:3376"] # array of strings
        use_tls: encrypt
		tls_path: "/path/to/"
      register: swarm_result

*/

type ModuleArgs struct {
	Role       string
	Operation  string
	Detach     bool
	Docker_url string
	Join_url   []string
	Use_tls    string
	Tls_path   string
}

func connectEngine(args *ModuleArgs) *client.Client {
	var c *http.Client
	var response ansible.Response

	securityOptions := tlsconfig.Options{
		CAFile:             filepath.Join(args.Tls_path, "ca.pem"),
		CertFile:           filepath.Join(args.Tls_path, "cert.pem"),
		KeyFile:            filepath.Join(args.Tls_path, "key.pem"),
		InsecureSkipVerify: true,
	}

	tlsc, err := tlsconfig.Client(securityOptions)
	if err != nil {
		response.Msg = "TLS configuration error: " + args.Tls_path
		ansible.FailJson(response)
	}

	c = &http.Client{
		Transport: &http.Transport{
			TLSClientConfig: tlsc,
		},
	}

	defaultHeaders := map[string]string{"User-Agent": "engine-api-cli-1.0"}
	// v1.24 = engine 1.12
	cli, err := client.NewClient(args.Docker_url, "v1.24", c, defaultHeaders)
	if err != nil {
		response.Msg = "Impossible to connect to Docker Engine: " + args.Docker_url
		ansible.FailJson(response)
	}

	return cli
}

func initSwarm(cli *client.Client) string {
	var response ansible.Response

	swarm, err := cli.SwarmInit(context.Background(), swarm.InitRequest{
		ListenAddr:      "0.0.0.0:2377",
		ForceNewCluster: true,
		/*
			XXX
			Spec: {
				AcceptancePolicy: []Policies{
					Policy: {
						Role:       "manager",
						Autoaccept: true,
					},
				},
			},
		*/
	})
	if err != nil {
		response.Msg = "ERROR: Swarm init: " + swarm
		ansible.FailJson(response)
	}
	return swarm
}

func joinCluster(cli *client.Client, addr []string, role string) string {
	var response ansible.Response
	var isManager bool

	if role == "master" {
		isManager = true
	} else {
		isManager = false
	}

	err := cli.SwarmJoin(context.Background(), swarm.JoinRequest{
		RemoteAddrs: addr,
		Manager:     isManager,
	})
	if err != nil {
		response.Msg = "ERROR: Swarm join: " + role
		ansible.FailJson(response)
	}

	return "ok"
}

func leaveCluster(cli *client.Client) error {

}

func promoteNode(cli *client.Client) error {

}

func demoteNode(cli *client.Client) error {

}

func updateSwarm(cli *client.Client) error {

}

func main() {
	var response ansible.Response
	var moduleArgs ModuleArgs

	text := ansible.ParseVariables(os.Args)

	if err := json.Unmarshal(text, &moduleArgs); err != nil {
		response.Msg = "Configuration file not valid JSON: " + os.Args[1]
		ansible.FailJson(response)
	}

	cli := connectEngine(&moduleArgs)

	if moduleArgs.Role == "master" {
		// Init cluster
		if moduleArgs.Operation == "init" {
			swarm := initSwarm(cli)
			response.Msg = swarm
			ansible.ExitJson(response)
		}
		// Join as a master
		if moduleArgs.Operation == "join" {
			swarm := joinCluster(cli, moduleArgs.Join_url, "master")
			response.Msg = swarm
			ansible.ExitJson(response)
		}
	} else if moduleArgs.Role == "slave" {
		// Join as a slave
		if moduleArgs.Operation == "join" {
			swarm := joinCluster(cli, moduleArgs.Join_url, "node")
			response.Msg = swarm
			ansible.ExitJson(response)
		}

	}
}
<commit_msg>Definition *Node<commit_after>/*
Copyright (c) 2016, Fabrizio Soppelsa
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

* Neither the name of ansible-swarm nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

=============================================================================

Ansible docker_swarm module
Requires Ansible 2.2+
go get github.com/docker/engine-api/types/swarm
go get github.com/docker/engine-api/client
go get github.com/foppelsa/ansible
*/

package main

import (
	"encoding/json"
	"github.com/docker/engine-api/client"
	"github.com/docker/engine-api/types/swarm"
	"github.com/docker/go-connections/tlsconfig"
	"github.com/fsoppelsa/ansible"
	"golang.org/x/net/context"
	"net/http"
	"os"
	"path/filepath"
)

/*
  Sample:

    - name: Operate swarm clusters and nodes
      docker_swarm:
        role: "master"|"slave"
        operation: "init"|"join"|"leave"|"update"|"promote"|"demote"
        detach: yes
		docker_url: "tcp://192.168.99.101:2376"
		join_url: ["tcp://192.168.99.100:3376"] # array of strings
        use_tls: encrypt
		tls_path: "/path/to/"
      register: swarm_result

*/

type ModuleArgs struct {
	Role       string
	Operation  string
	Detach     bool
	Docker_url string
	Join_url   []string
	Use_tls    string
	Tls_path   string
}

func connectEngine(args *ModuleArgs) *client.Client {
	var c *http.Client
	var response ansible.Response

	securityOptions := tlsconfig.Options{
		CAFile:             filepath.Join(args.Tls_path, "ca.pem"),
		CertFile:           filepath.Join(args.Tls_path, "cert.pem"),
		KeyFile:            filepath.Join(args.Tls_path, "key.pem"),
		InsecureSkipVerify: true,
	}

	tlsc, err := tlsconfig.Client(securityOptions)
	if err != nil {
		response.Msg = "TLS configuration error: " + args.Tls_path
		ansible.FailJson(response)
	}

	c = &http.Client{
		Transport: &http.Transport{
			TLSClientConfig: tlsc,
		},
	}

	defaultHeaders := map[string]string{"User-Agent": "engine-api-cli-1.0"}
	// v1.24 = engine 1.12
	cli, err := client.NewClient(args.Docker_url, "v1.24", c, defaultHeaders)
	if err != nil {
		response.Msg = "Impossible to connect to Docker Engine: " + args.Docker_url
		ansible.FailJson(response)
	}

	return cli
}

func initSwarm(cli *client.Client) string {
	var response ansible.Response

	swarm, err := cli.SwarmInit(context.Background(), swarm.InitRequest{
		ListenAddr:      "0.0.0.0:2377",
		ForceNewCluster: true,
		/*
			XXX
			Spec: {
				AcceptancePolicy: []Policies{
					Policy: {
						Role:       "manager",
						Autoaccept: true,
					},
				},
			},
		*/
	})
	if err != nil {
		response.Msg = "ERROR: Swarm init: " + swarm
		ansible.FailJson(response)
	}
	return swarm
}

func joinCluster(cli *client.Client, addr []string, role string) string {
	var response ansible.Response
	var isManager bool

	if role == "master" {
		isManager = true
	} else {
		isManager = false
	}

	err := cli.SwarmJoin(context.Background(), swarm.JoinRequest{
		RemoteAddrs: addr,
		Manager:     isManager,
	})
	if err != nil {
		response.Msg = "ERROR: Swarm join: " + role
		ansible.FailJson(response)
	}

	return "ok"
}

func leaveCluster(cli *client.Client) error {
	return nil
}

func promoteNode(cli *client.Client) error {
	return nil
}

func demoteNode(cli *client.Client) error {
	return nil
}

func updateSwarm(cli *client.Client) error {
	return nil
}

func main() {
	var response ansible.Response
	var moduleArgs ModuleArgs

	text := ansible.ParseVariables(os.Args)

	if err := json.Unmarshal(text, &moduleArgs); err != nil {
		response.Msg = "Configuration file not valid JSON: " + os.Args[1]
		ansible.FailJson(response)
	}

	cli := connectEngine(&moduleArgs)

	if moduleArgs.Role == "master" {
		// Init cluster
		if moduleArgs.Operation == "init" {
			swarm := initSwarm(cli)
			response.Msg = swarm
			ansible.ExitJson(response)
		}
		// Join as a master
		if moduleArgs.Operation == "join" {
			swarm := joinCluster(cli, moduleArgs.Join_url, "master")
			response.Msg = swarm
			ansible.ExitJson(response)
		}
	} else if moduleArgs.Role == "slave" {
		// Join as a slave
		if moduleArgs.Operation == "join" {
			swarm := joinCluster(cli, moduleArgs.Join_url, "node")
			response.Msg = swarm
			ansible.ExitJson(response)
		}

	}
}
<|endoftext|>


<commit_before>package main

import (
	"go/ast"
	"go/parser"
	"unicode"
	"unicode/utf8"
)

type cursor_context struct {
	decl    *decl
	partial string
}

type bytes_iterator struct {
	data   []byte
	cursor int
}

// return the character under the cursor
func (this *bytes_iterator) char() byte {
	return this.data[this.cursor]
}

// return the rune under the cursor
func (this *bytes_iterator) rune() rune {
	r, _ := utf8.DecodeRune(this.data[this.cursor:])
	return r
}

// move cursor backwards to the next valid utf8 rune start, or 0
func (this *bytes_iterator) move_backwards() bool {
	for this.cursor != 0 {
		this.cursor--
		if utf8.RuneStart(this.char()) {
			return true
		}
	}
	return false
}

// move cursor forwards to the next valid utf8 rune start
func (this *bytes_iterator) move_forwards() {
	for this.cursor < len(this.data) {
		this.cursor++
		if utf8.RuneStart(this.char()) {
			return
		}
	}
}

var g_unicode_ident_set = []*unicode.RangeTable{
	unicode.Letter,
	unicode.Digit,
	{R16: []unicode.Range16{{'_', '_', 1}}},
}

// move cursor backwards, stop at the first rune that is not from
// 'g_unicode_ident_set', or 0
func (this *bytes_iterator) skip_ident() bool {
	for this.cursor != 0 {
		r := this.rune()

		// stop if 'r' is not [a-zA-Z0-9_] (unicode correct though)
		if !unicode.IsOneOf(g_unicode_ident_set, r) {
			return true
		}
		this.move_backwards()
	}
	return true
}

func (this *bytes_iterator) skip_all_whitespace() bool {
	for this.cursor != 0 {
		r := this.rune()

		if !unicode.IsSpace(r) {
			return true
		}
		this.move_backwards()
	}
	return true
}

func (this *bytes_iterator) skip_forward_ident() {
	for this.cursor < len(this.data) {
		r := this.rune()

		// stop if 'r' is not [a-zA-Z0-9_] (unicode correct though)
		if !unicode.IsOneOf(g_unicode_ident_set, r) {
			return
		}
		this.move_forwards()
	}
}

var g_bracket_pairs = map[byte]byte{
	')': '(',
	']': '[',
}

// when the cursor is at the ')' or ']', move the cursor to an opposite bracket
// pair, this functions takes inner bracker pairs into account
func (this *bytes_iterator) skip_to_bracket_pair() bool {
	right := this.char()
	left := g_bracket_pairs[right]
	return this.skip_to_left_bracket(left, right)
}

func (this *bytes_iterator) skip_to_left_bracket(left, right byte) bool {
	balance := 1
	for balance != 0 {
		this.move_backwards()
		if this.cursor == 0 {
			return false
		}
		switch this.char() {
		case right:
			balance++
		case left:
			balance--
		}
	}
	return true
}

// Move the cursor to the open brace of the current block, taking inner blocks
// into account.
func (this *bytes_iterator) skip_to_open_brace() bool {
	return this.skip_to_left_bracket('{', '}')
}

// try_extract_struct_init_expr tries to match the current cursor position as being inside a struct
// initialization expression of the form:
// &X{
// 	Xa: 1,
// 	Xb: 2,
// }
// Note that this currently only works when:
// - the type of the struct immediately precedes the opening '{'
// - each field is declared on its own line
// Nested struct initialization expressions are handled correctly.
func (this *bytes_iterator) try_extract_struct_init_expr() []byte {
	for this.cursor != 0 {
		if !this.skip_to_open_brace() {
			return nil
		}

		if !this.move_backwards() {
			return nil
		}

		orig := this.cursor + 1
		if !this.skip_ident() {
			return nil
		}

		return this.data[this.cursor+1 : orig]
	}
	return nil
}

// starting from the end of the 'file', move backwards and return a slice of a
// valid Go expression
func (this *bytes_iterator) extract_go_expr() []byte {
	const (
		last_none = iota
		last_dot
		last_paren
		last_ident
	)
	last := last_none
	orig := this.cursor
	this.move_backwards()
loop:
	for {
		if this.cursor == 0 {
			return this.data[:orig]
		}
		r := this.rune()
		switch r {
		case '.':
			this.move_backwards()
			last = last_dot
		case ')', ']':
			if last == last_ident {
				break loop
			}
			this.skip_to_bracket_pair()
			this.move_backwards()
			last = last_paren
		default:
			if unicode.IsOneOf(g_unicode_ident_set, r) {
				this.skip_ident()
				last = last_ident
			} else {
				break loop
			}
		}
	}
	return this.data[this.cursor+1 : orig]
}

// this function is called when the cursor is at the '.' and you need to get the
// declaration before that dot
func (c *auto_complete_context) deduce_cursor_decl(iter *bytes_iterator) *decl {
	e := string(iter.extract_go_expr())
	expr, err := parser.ParseExpr(e)
	if err != nil {
		return nil
	}
	return expr_to_decl(expr, c.current.scope)
}

// deduce cursor context, it includes the declaration under the cursor and partial identifier
// (usually a part of the name of the child declaration)
func (c *auto_complete_context) deduce_cursor_context(file []byte, cursor int) (cursor_context, bool) {
	if cursor <= 0 {
		return cursor_context{nil, ""}, true
	}

	orig := cursor
	iter := bytes_iterator{file, cursor}

	// figure out what is just before the cursor
	iter.move_backwards()
	if iter.char() == '.' {
		// we're '<whatever>.'
		// figure out decl, Parital is ""
		decl := c.deduce_cursor_decl(&iter)
		return cursor_context{decl, ""}, decl != nil
	}

	r := iter.rune()
	if unicode.IsOneOf(g_unicode_ident_set, r) {
		// we're '<whatever>.<ident>'
		// parse <ident> as Partial and figure out decl
		iter.skip_ident()
		partial := string(iter.data[iter.cursor+1 : orig])
		if iter.char() == '.' {
			decl := c.deduce_cursor_decl(&iter)
			return cursor_context{decl, partial}, decl != nil
		} else {
			return cursor_context{nil, partial}, true
		}
	}

	if unicode.IsSpace(iter.rune()) {
		// Try to parse the current expression as a structure initialization.
		data := iter.try_extract_struct_init_expr()
		if data == nil {
			return cursor_context{nil, ""}, true
		}

		expr, err := parser.ParseExpr(string(data))
		if err != nil {
			return cursor_context{nil, ""}, true
		}
		decl := expr_to_decl(expr, c.current.scope)
		if decl == nil {
			return cursor_context{nil, ""}, true
		}

		switch decl.typ.(type) {
		case *ast.StructType:
			// TODO: Return partial.
			return cursor_context{struct_members_only(decl), ""}, true
		}
	}

	return cursor_context{nil, ""}, true
}

// struct_members_only returns a copy of decl with all its children of type function stripped out.
// This is used when returning matches for struct initialization expressions, for which it does not
// make sense to suggest a function name associated with the struct.
func struct_members_only(decl *decl) *decl {
	new_decl := *decl
	for k, d := range new_decl.children {
		switch d.typ.(type) {
		case *ast.FuncType:
			// Strip functions from the list.
			delete(new_decl.children, k)
		}
	}
	return &new_decl
}

// deduce the type of the expression under the cursor, a bit of copy & paste from the method
// above, returns true if deduction was successful (even if the result of it is nil)
func (c *auto_complete_context) deduce_cursor_type_pkg(file []byte, cursor int) (ast.Expr, string, bool) {
	if cursor <= 0 {
		return nil, "", true
	}

	iter := bytes_iterator{file, cursor}

	// move forward to the end of the current identifier
	// so that we can grab the whole identifier when
	// reading backwards
	iter.skip_forward_ident()

	// read backwards to extract expression
	e := string(iter.extract_go_expr())

	expr, err := parser.ParseExpr(e)
	if err != nil {
		return nil, "", false
	} else {
		t, scope, _ := infer_type(expr, c.current.scope, -1)
		return t, lookup_pkg(get_type_path(t), scope), t != nil
	}
}
<commit_msg>Convert bracket maching functions to use runes instead of bytes<commit_after>package main

import (
	"go/ast"
	"go/parser"
	"unicode"
	"unicode/utf8"
)

type cursor_context struct {
	decl    *decl
	partial string
}

type bytes_iterator struct {
	data   []byte
	cursor int
}

// return the character under the cursor
func (this *bytes_iterator) char() byte {
	return this.data[this.cursor]
}

// return the rune under the cursor
func (this *bytes_iterator) rune() rune {
	r, _ := utf8.DecodeRune(this.data[this.cursor:])
	return r
}

// move cursor backwards to the next valid utf8 rune start, or 0
func (this *bytes_iterator) move_backwards() bool {
	for this.cursor != 0 {
		this.cursor--
		if utf8.RuneStart(this.char()) {
			return true
		}
	}
	return false
}

// move cursor forwards to the next valid utf8 rune start
func (this *bytes_iterator) move_forwards() {
	for this.cursor < len(this.data) {
		this.cursor++
		if utf8.RuneStart(this.char()) {
			return
		}
	}
}

var g_unicode_ident_set = []*unicode.RangeTable{
	unicode.Letter,
	unicode.Digit,
	{R16: []unicode.Range16{{'_', '_', 1}}},
}

// move cursor backwards, stop at the first rune that is not from
// 'g_unicode_ident_set', or 0
func (this *bytes_iterator) skip_ident() bool {
	for this.cursor != 0 {
		r := this.rune()

		// stop if 'r' is not [a-zA-Z0-9_] (unicode correct though)
		if !unicode.IsOneOf(g_unicode_ident_set, r) {
			return true
		}
		this.move_backwards()
	}
	return true
}

func (this *bytes_iterator) skip_all_whitespace() bool {
	for this.cursor != 0 {
		r := this.rune()

		if !unicode.IsSpace(r) {
			return true
		}
		this.move_backwards()
	}
	return true
}

func (this *bytes_iterator) skip_forward_ident() bool {
	for this.cursor < len(this.data) {
		r := this.rune()

		// stop if 'r' is not [a-zA-Z0-9_] (unicode correct though)
		if !unicode.IsOneOf(g_unicode_ident_set, r) {
			return true
		}
		this.move_forwards()
	}
	return false
}

var g_bracket_pairs = map[rune]rune{
	')': '(',
	']': '[',
}

// when the cursor is at the ')' or ']', move the cursor to an opposite bracket
// pair, this functions takes inner bracker pairs into account
func (this *bytes_iterator) skip_to_bracket_pair() bool {
	right := this.rune()
	left := g_bracket_pairs[right]
	return this.skip_to_left_bracket(left, right)
}

func (this *bytes_iterator) skip_to_left_bracket(left, right rune) bool {
	balance := 1
	for balance != 0 {
		this.move_backwards()
		if this.cursor == 0 {
			return false
		}
		switch this.rune() {
		case right:
			balance++
		case left:
			balance--
		}
	}
	return true
}

// Move the cursor to the open brace of the current block, taking inner blocks
// into account.
func (this *bytes_iterator) skip_to_open_brace() bool {
	return this.skip_to_left_bracket('{', '}')
}

// try_extract_struct_init_expr tries to match the current cursor position as being inside a struct
// initialization expression of the form:
// &X{
// 	Xa: 1,
// 	Xb: 2,
// }
// Note that this currently only works when:
// - the type of the struct immediately precedes the opening '{'
// - each field is declared on its own line
// Nested struct initialization expressions are handled correctly.
func (this *bytes_iterator) try_extract_struct_init_expr() []byte {
	for this.cursor != 0 {
		if !this.skip_to_open_brace() {
			return nil
		}

		if !this.move_backwards() {
			return nil
		}

		orig := this.cursor + 1
		if !this.skip_ident() {
			return nil
		}

		return this.data[this.cursor+1 : orig]
	}
	return nil
}

// starting from the end of the 'file', move backwards and return a slice of a
// valid Go expression
func (this *bytes_iterator) extract_go_expr() []byte {
	const (
		last_none = iota
		last_dot
		last_paren
		last_ident
	)
	last := last_none
	orig := this.cursor
	this.move_backwards()
loop:
	for {
		if this.cursor == 0 {
			return this.data[:orig]
		}
		r := this.rune()
		switch r {
		case '.':
			this.move_backwards()
			last = last_dot
		case ')', ']':
			if last == last_ident {
				break loop
			}
			this.skip_to_bracket_pair()
			this.move_backwards()
			last = last_paren
		default:
			if unicode.IsOneOf(g_unicode_ident_set, r) {
				this.skip_ident()
				last = last_ident
			} else {
				break loop
			}
		}
	}
	return this.data[this.cursor+1 : orig]
}

// this function is called when the cursor is at the '.' and you need to get the
// declaration before that dot
func (c *auto_complete_context) deduce_cursor_decl(iter *bytes_iterator) *decl {
	e := string(iter.extract_go_expr())
	expr, err := parser.ParseExpr(e)
	if err != nil {
		return nil
	}
	return expr_to_decl(expr, c.current.scope)
}

// deduce cursor context, it includes the declaration under the cursor and partial identifier
// (usually a part of the name of the child declaration)
func (c *auto_complete_context) deduce_cursor_context(file []byte, cursor int) (cursor_context, bool) {
	if cursor <= 0 {
		return cursor_context{nil, ""}, true
	}

	orig := cursor
	iter := bytes_iterator{file, cursor}

	// figure out what is just before the cursor
	iter.move_backwards()
	if iter.char() == '.' {
		// we're '<whatever>.'
		// figure out decl, Parital is ""
		decl := c.deduce_cursor_decl(&iter)
		return cursor_context{decl, ""}, decl != nil
	}

	r := iter.rune()
	if unicode.IsOneOf(g_unicode_ident_set, r) {
		// we're '<whatever>.<ident>'
		// parse <ident> as Partial and figure out decl
		iter.skip_ident()
		partial := string(iter.data[iter.cursor+1 : orig])
		if iter.char() == '.' {
			decl := c.deduce_cursor_decl(&iter)
			return cursor_context{decl, partial}, decl != nil
		} else {
			return cursor_context{nil, partial}, true
		}
	}

	if unicode.IsSpace(iter.rune()) {
		// Try to parse the current expression as a structure initialization.
		data := iter.try_extract_struct_init_expr()
		if data == nil {
			return cursor_context{nil, ""}, true
		}

		expr, err := parser.ParseExpr(string(data))
		if err != nil {
			return cursor_context{nil, ""}, true
		}
		decl := expr_to_decl(expr, c.current.scope)
		if decl == nil {
			return cursor_context{nil, ""}, true
		}

		switch decl.typ.(type) {
		case *ast.StructType:
			// TODO: Return partial.
			return cursor_context{struct_members_only(decl), ""}, true
		}
	}

	return cursor_context{nil, ""}, true
}

// struct_members_only returns a copy of decl with all its children of type function stripped out.
// This is used when returning matches for struct initialization expressions, for which it does not
// make sense to suggest a function name associated with the struct.
func struct_members_only(decl *decl) *decl {
	new_decl := *decl
	for k, d := range new_decl.children {
		switch d.typ.(type) {
		case *ast.FuncType:
			// Strip functions from the list.
			delete(new_decl.children, k)
		}
	}
	return &new_decl
}

// deduce the type of the expression under the cursor, a bit of copy & paste from the method
// above, returns true if deduction was successful (even if the result of it is nil)
func (c *auto_complete_context) deduce_cursor_type_pkg(file []byte, cursor int) (ast.Expr, string, bool) {
	if cursor <= 0 {
		return nil, "", true
	}

	iter := bytes_iterator{file, cursor}

	// move forward to the end of the current identifier
	// so that we can grab the whole identifier when
	// reading backwards
	iter.skip_forward_ident()

	// read backwards to extract expression
	e := string(iter.extract_go_expr())

	expr, err := parser.ParseExpr(e)
	if err != nil {
		return nil, "", false
	} else {
		t, scope, _ := infer_type(expr, c.current.scope, -1)
		return t, lookup_pkg(get_type_path(t), scope), t != nil
	}
}
<|endoftext|>


<commit_before>// Package aphgrpc provides various interfaces, functions, types
// for building and working with gRPC services.
package aphgrpc

import (
	"encoding/json"
	"net/http"
	"strconv"
	"strings"

	context "golang.org/x/net/context"

	"github.com/grpc-ecosystem/grpc-gateway/runtime"
	"github.com/pkg/errors"
	spb "google.golang.org/genproto/googleapis/rpc/status"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/metadata"
	"google.golang.org/grpc/status"
)

const (
	// MetaKey is the key used for storing all metadata
	MetaKey = "error"
)

var (
	//ErrDatabaseQuery represents database query related errors
	ErrDatabaseQuery = newError("Database query error")
	//ErrDatabaseInsert represents database insert related errors
	ErrDatabaseInsert = newError("Database insert error")
	//ErrDatabaseUpdate represents database update related errors
	ErrDatabaseUpdate = newError("Database update error")
	//ErrDatabaseDelete represents database update delete errors
	ErrDatabaseDelete = newError("Database delete error")
	//ErrNotFound represents the absence of an HTTP resource
	ErrNotFound = newError("Resource not found")
	//ErrExists represents the presence of an HTTP resource
	ErrExists = newError("Resource already exists")
	//ErrJSONEncoding represents any json encoding error
	ErrJSONEncoding = newError("Json encoding error")
	//ErrStructMarshal represents any error with marshalling structure
	ErrStructMarshal = newError("Structure marshalling error")
	//ErrIncludeParam represents any error with invalid include query parameter
	ErrIncludeParam = newErrorWithParam("Invalid include query parameter", "include")
	//ErrSparseFieldSets represents any error with invalid sparse fieldsets query parameter
	ErrFields = newErrorWithParam("Invalid field query parameter", "field")
	//ErrFilterParam represents any error with invalid filter query paramter
	ErrFilterParam = newErrorWithParam("Invalid filter query parameter", "filter")
	//ErrNotAcceptable represents any error with wrong or inappropriate http Accept header
	ErrNotAcceptable = newError("Accept header is not acceptable")
	//ErrUnsupportedMedia represents any error with unsupported media type in http header
	ErrUnsupportedMedia = newError("Media type is not supported")
	//ErrRetrieveMetadata represents any error to retrieve grpc metadata from the running context
	ErrRetrieveMetadata = errors.New("unable to retrieve metadata")
	//ErrXForwardedHost represents any failure or absence of x-forwarded-host HTTP header in the grpc context
	ErrXForwardedHost = errors.New("x-forwarded-host header is absent")
)

// HTTPError is used for errors
type HTTPError struct {
	err    error
	msg    string
	status int
	Errors []Error `json:"errors,omitempty"`
}

// Error can be used for all kind of application errors
// e.g. you would use it to define form errors or any
// other semantical application problems
// for more information see http://jsonapi.org/format/#errors
type Error struct {
	ID     string       `json:"id,omitempty"`
	Links  *ErrorLinks  `json:"links,omitempty"`
	Status string       `json:"status,omitempty"`
	Code   string       `json:"code,omitempty"`
	Title  string       `json:"title,omitempty"`
	Detail string       `json:"detail,omitempty"`
	Source *ErrorSource `json:"source,omitempty"`
	Meta   interface{}  `json:"meta,omitempty"`
}

// ErrorLinks is used to provide an About URL that leads to
// further details about the particular occurrence of the problem.
//
// for more information see http://jsonapi.org/format/#error-objects
type ErrorLinks struct {
	About string `json:"about,omitempty"`
}

// ErrorSource is used to provide references to the source of an error.
//
// The Pointer is a JSON Pointer to the associated entity in the request
// document.
// The Paramter is a string indicating which query parameter caused the error.
//
// for more information see http://jsonapi.org/format/#error-objects
type ErrorSource struct {
	Pointer   string `json:"pointer,omitempty"`
	Parameter string `json:"parameter,omitempty"`
}

func newErrorWithParam(msg, param string) metadata.MD {
	return metadata.Pairs(MetaKey, msg, MetaKey, param)
}

func newError(msg string) metadata.MD {
	return metadata.Pairs(MetaKey, msg)
}

// CustomHTTPError is a custom error handler for grpc-gateway to generate
// JSONAPI formatted HTTP response.
func CustomHTTPError(ctx context.Context, _ *runtime.ServeMux, marshaler runtime.Marshaler, w http.ResponseWriter, _ *http.Request, err error) {
	md, ok := runtime.ServerMetadataFromContext(ctx)
	if !ok {
		fallbackError(w, getgRPCStatus(errors.Wrap(err, "unable to retrieve metadata")))
		return
	}
	JSONAPIError(w, md.TrailerMD, getgRPCStatus(err))
}

func getgRPCStatus(err error) *status.Status {
	s, ok := status.FromError(err)
	if !ok {
		return status.New(codes.Unknown, err.Error())
	}
	return s
}

// JSONAPIError generates JSONAPI formatted error message
func JSONAPIError(w http.ResponseWriter, md metadata.MD, s *status.Status) {
	status := runtime.HTTPStatusFromCode(s.Code())
	jsnErr := Error{
		Status: strconv.Itoa(status),
		Title:  strings.Join(md["error"], "-"),
		Detail: s.Message(),
		Meta: map[string]interface{}{
			"creator": "api error helper",
		},
	}
	w.Header().Set("Content-Type", "application/vnd.api+json")
	w.WriteHeader(status)
	encErr := json.NewEncoder(w).Encode(HTTPError{Errors: []Error{jsnErr}})
	if encErr != nil {
		http.Error(w, encErr.Error(), http.StatusInternalServerError)
	}
}

func fallbackError(w http.ResponseWriter, s *status.Status) {
	status := runtime.HTTPStatusFromCode(s.Code())
	jsnErr := Error{
		Status: strconv.Itoa(status),
		Title:  "gRPC error",
		Detail: s.Message(),
		Meta: map[string]interface{}{
			"creator": "api error helper",
		},
	}
	w.Header().Set("Content-Type", "application/vnd.api+json")
	w.WriteHeader(status)
	encErr := json.NewEncoder(w).Encode(HTTPError{Errors: []Error{jsnErr}})
	if encErr != nil {
		http.Error(w, encErr.Error(), http.StatusInternalServerError)
	}
}

func CheckNoRows(err error) bool {
	if strings.Contains(err.Error(), "no rows") {
		return true
	}
	return false
}

func HandleMessagingError(ctx context.Context, st *spb.Status) error {
	err := status.ErrorProto(st)
	grpc.SetTrailer(ctx, newError(err.Error()))
	return err
}

func HandleError(ctx context.Context, err error) error {
	if CheckNoRows(err) {
		grpc.SetTrailer(ctx, ErrNotFound)
		return status.Error(codes.NotFound, err.Error())
	}
	grpc.SetTrailer(ctx, newError(err.Error()))
	return status.Error(codes.Internal, err.Error())
}

func HandleGenericError(ctx context.Context, err error) error {
	grpc.SetTrailer(ctx, newError(err.Error()))
	return status.Error(codes.Internal, err.Error())
}

func HandleDeleteError(ctx context.Context, err error) error {
	grpc.SetTrailer(ctx, ErrDatabaseDelete)
	return status.Error(codes.Internal, err.Error())
}

func HandleGetError(ctx context.Context, err error) error {
	grpc.SetTrailer(ctx, ErrDatabaseQuery)
	return status.Error(codes.Internal, err.Error())
}

func HandleInsertError(ctx context.Context, err error) error {
	grpc.SetTrailer(ctx, ErrDatabaseInsert)
	return status.Error(codes.Internal, err.Error())
}

func HandleUpdateError(ctx context.Context, err error) error {
	grpc.SetTrailer(ctx, ErrDatabaseUpdate)
	return status.Error(codes.Internal, err.Error())
}

func HandleGetArgError(ctx context.Context, err error) error {
	grpc.SetTrailer(ctx, ErrDatabaseQuery)
	return status.Error(codes.InvalidArgument, err.Error())
}

func HandleInsertArgError(ctx context.Context, err error) error {
	grpc.SetTrailer(ctx, ErrDatabaseInsert)
	return status.Error(codes.InvalidArgument, err.Error())
}

func HandleUpdateArgError(ctx context.Context, err error) error {
	grpc.SetTrailer(ctx, ErrDatabaseUpdate)
	return status.Error(codes.InvalidArgument, err.Error())
}

func HandleNotFoundError(ctx context.Context, err error) error {
	grpc.SetTrailer(ctx, ErrNotFound)
	return status.Error(codes.NotFound, err.Error())
}

func HandleExistError(ctx context.Context, err error) error {
	grpc.SetTrailer(ctx, ErrExists)
	return status.Error(codes.AlreadyExists, err.Error())
}
<commit_msg>feat: add HandleFilterParamError for handling filter parameter errors<commit_after>// Package aphgrpc provides various interfaces, functions, types
// for building and working with gRPC services.
package aphgrpc

import (
	"encoding/json"
	"net/http"
	"strconv"
	"strings"

	context "golang.org/x/net/context"

	"github.com/grpc-ecosystem/grpc-gateway/runtime"
	"github.com/pkg/errors"
	spb "google.golang.org/genproto/googleapis/rpc/status"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/metadata"
	"google.golang.org/grpc/status"
)

const (
	// MetaKey is the key used for storing all metadata
	MetaKey = "error"
)

var (
	//ErrDatabaseQuery represents database query related errors
	ErrDatabaseQuery = newError("Database query error")
	//ErrDatabaseInsert represents database insert related errors
	ErrDatabaseInsert = newError("Database insert error")
	//ErrDatabaseUpdate represents database update related errors
	ErrDatabaseUpdate = newError("Database update error")
	//ErrDatabaseDelete represents database update delete errors
	ErrDatabaseDelete = newError("Database delete error")
	//ErrNotFound represents the absence of an HTTP resource
	ErrNotFound = newError("Resource not found")
	//ErrExists represents the presence of an HTTP resource
	ErrExists = newError("Resource already exists")
	//ErrJSONEncoding represents any json encoding error
	ErrJSONEncoding = newError("Json encoding error")
	//ErrStructMarshal represents any error with marshalling structure
	ErrStructMarshal = newError("Structure marshalling error")
	//ErrIncludeParam represents any error with invalid include query parameter
	ErrIncludeParam = newErrorWithParam("Invalid include query parameter", "include")
	//ErrSparseFieldSets represents any error with invalid sparse fieldsets query parameter
	ErrFields = newErrorWithParam("Invalid field query parameter", "field")
	//ErrFilterParam represents any error with invalid filter query paramter
	ErrFilterParam = newErrorWithParam("Invalid filter query parameter", "filter")
	//ErrNotAcceptable represents any error with wrong or inappropriate http Accept header
	ErrNotAcceptable = newError("Accept header is not acceptable")
	//ErrUnsupportedMedia represents any error with unsupported media type in http header
	ErrUnsupportedMedia = newError("Media type is not supported")
	//ErrRetrieveMetadata represents any error to retrieve grpc metadata from the running context
	ErrRetrieveMetadata = errors.New("unable to retrieve metadata")
	//ErrXForwardedHost represents any failure or absence of x-forwarded-host HTTP header in the grpc context
	ErrXForwardedHost = errors.New("x-forwarded-host header is absent")
)

// HTTPError is used for errors
type HTTPError struct {
	err    error
	msg    string
	status int
	Errors []Error `json:"errors,omitempty"`
}

// Error can be used for all kind of application errors
// e.g. you would use it to define form errors or any
// other semantical application problems
// for more information see http://jsonapi.org/format/#errors
type Error struct {
	ID     string       `json:"id,omitempty"`
	Links  *ErrorLinks  `json:"links,omitempty"`
	Status string       `json:"status,omitempty"`
	Code   string       `json:"code,omitempty"`
	Title  string       `json:"title,omitempty"`
	Detail string       `json:"detail,omitempty"`
	Source *ErrorSource `json:"source,omitempty"`
	Meta   interface{}  `json:"meta,omitempty"`
}

// ErrorLinks is used to provide an About URL that leads to
// further details about the particular occurrence of the problem.
//
// for more information see http://jsonapi.org/format/#error-objects
type ErrorLinks struct {
	About string `json:"about,omitempty"`
}

// ErrorSource is used to provide references to the source of an error.
//
// The Pointer is a JSON Pointer to the associated entity in the request
// document.
// The Paramter is a string indicating which query parameter caused the error.
//
// for more information see http://jsonapi.org/format/#error-objects
type ErrorSource struct {
	Pointer   string `json:"pointer,omitempty"`
	Parameter string `json:"parameter,omitempty"`
}

func newErrorWithParam(msg, param string) metadata.MD {
	return metadata.Pairs(MetaKey, msg, MetaKey, param)
}

func newError(msg string) metadata.MD {
	return metadata.Pairs(MetaKey, msg)
}

// CustomHTTPError is a custom error handler for grpc-gateway to generate
// JSONAPI formatted HTTP response.
func CustomHTTPError(ctx context.Context, _ *runtime.ServeMux, marshaler runtime.Marshaler, w http.ResponseWriter, _ *http.Request, err error) {
	md, ok := runtime.ServerMetadataFromContext(ctx)
	if !ok {
		fallbackError(w, getgRPCStatus(errors.Wrap(err, "unable to retrieve metadata")))
		return
	}
	JSONAPIError(w, md.TrailerMD, getgRPCStatus(err))
}

func getgRPCStatus(err error) *status.Status {
	s, ok := status.FromError(err)
	if !ok {
		return status.New(codes.Unknown, err.Error())
	}
	return s
}

// JSONAPIError generates JSONAPI formatted error message
func JSONAPIError(w http.ResponseWriter, md metadata.MD, s *status.Status) {
	status := runtime.HTTPStatusFromCode(s.Code())
	jsnErr := Error{
		Status: strconv.Itoa(status),
		Title:  strings.Join(md["error"], "-"),
		Detail: s.Message(),
		Meta: map[string]interface{}{
			"creator": "api error helper",
		},
	}
	w.Header().Set("Content-Type", "application/vnd.api+json")
	w.WriteHeader(status)
	encErr := json.NewEncoder(w).Encode(HTTPError{Errors: []Error{jsnErr}})
	if encErr != nil {
		http.Error(w, encErr.Error(), http.StatusInternalServerError)
	}
}

func fallbackError(w http.ResponseWriter, s *status.Status) {
	status := runtime.HTTPStatusFromCode(s.Code())
	jsnErr := Error{
		Status: strconv.Itoa(status),
		Title:  "gRPC error",
		Detail: s.Message(),
		Meta: map[string]interface{}{
			"creator": "api error helper",
		},
	}
	w.Header().Set("Content-Type", "application/vnd.api+json")
	w.WriteHeader(status)
	encErr := json.NewEncoder(w).Encode(HTTPError{Errors: []Error{jsnErr}})
	if encErr != nil {
		http.Error(w, encErr.Error(), http.StatusInternalServerError)
	}
}

func CheckNoRows(err error) bool {
	if strings.Contains(err.Error(), "no rows") {
		return true
	}
	return false
}

func HandleMessagingError(ctx context.Context, st *spb.Status) error {
	err := status.ErrorProto(st)
	grpc.SetTrailer(ctx, newError(err.Error()))
	return err
}

func HandleError(ctx context.Context, err error) error {
	if CheckNoRows(err) {
		grpc.SetTrailer(ctx, ErrNotFound)
		return status.Error(codes.NotFound, err.Error())
	}
	grpc.SetTrailer(ctx, newError(err.Error()))
	return status.Error(codes.Internal, err.Error())
}

func HandleGenericError(ctx context.Context, err error) error {
	grpc.SetTrailer(ctx, newError(err.Error()))
	return status.Error(codes.Internal, err.Error())
}

func HandleDeleteError(ctx context.Context, err error) error {
	grpc.SetTrailer(ctx, ErrDatabaseDelete)
	return status.Error(codes.Internal, err.Error())
}

func HandleGetError(ctx context.Context, err error) error {
	grpc.SetTrailer(ctx, ErrDatabaseQuery)
	return status.Error(codes.Internal, err.Error())
}

func HandleInsertError(ctx context.Context, err error) error {
	grpc.SetTrailer(ctx, ErrDatabaseInsert)
	return status.Error(codes.Internal, err.Error())
}

func HandleUpdateError(ctx context.Context, err error) error {
	grpc.SetTrailer(ctx, ErrDatabaseUpdate)
	return status.Error(codes.Internal, err.Error())
}

func HandleGetArgError(ctx context.Context, err error) error {
	grpc.SetTrailer(ctx, ErrDatabaseQuery)
	return status.Error(codes.InvalidArgument, err.Error())
}

func HandleInsertArgError(ctx context.Context, err error) error {
	grpc.SetTrailer(ctx, ErrDatabaseInsert)
	return status.Error(codes.InvalidArgument, err.Error())
}

func HandleUpdateArgError(ctx context.Context, err error) error {
	grpc.SetTrailer(ctx, ErrDatabaseUpdate)
	return status.Error(codes.InvalidArgument, err.Error())
}

func HandleNotFoundError(ctx context.Context, err error) error {
	grpc.SetTrailer(ctx, ErrNotFound)
	return status.Error(codes.NotFound, err.Error())
}

func HandleExistError(ctx context.Context, err error) error {
	grpc.SetTrailer(ctx, ErrExists)
	return status.Error(codes.AlreadyExists, err.Error())
}

func HandleFilterParamError(ctx context.Context, err error) error {
	grpc.SetTrailer(ctx, ErrFilterParam)
	return status.Error(codes.InvalidArgument, err.Error())
}
<|endoftext|>


<commit_before>package repository

import (
	"io"

	"github.com/restic/restic/crypto"
)

// decryptReadCloser couples an underlying reader with a DecryptReader and
// implements io.ReadCloser. On Close(), both readers are closed.
type decryptReadCloser struct {
	r  io.ReadCloser
	dr io.ReadCloser
}

func newDecryptReadCloser(key *crypto.Key, rd io.ReadCloser) (io.ReadCloser, error) {
	dr, err := crypto.DecryptFrom(key, rd)
	if err != nil {
		return nil, err
	}

	return &decryptReadCloser{r: rd, dr: dr}, nil
}

func (dr *decryptReadCloser) Read(buf []byte) (int, error) {
	return dr.dr.Read(buf)
}

func (dr *decryptReadCloser) Close() error {
	err := dr.dr.Close()
	if err != nil {
		return err
	}

	return dr.r.Close()
}
<commit_msg>repository: remove decryptReadCloser<commit_after><|endoftext|>


<commit_before>// xgettext-soy is a tool to extract messages from Soy templates in the PO
// (gettext) file format.
package main

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

	"github.com/robfig/gettext/po"
	"github.com/robfig/soy/ast"
	"github.com/robfig/soy/parse"
	"github.com/robfig/soy/parsepasses"
	"github.com/robfig/soy/soymsg/pomsg"
	"github.com/robfig/soy/template"
)

func usage() {
	fmt.Fprintln(os.Stderr, `xgettext-soy is a tool to extract messages from Soy templates.

Usage:

	./xgettext-soy [INPUTPATH]...

INPUTPATH elements may be files or directories. Input directories will be
recursively searched for *.soy files.

The resulting POT (PO template) file is written to STDOUT`)
}

var registry = template.Registry{}

func main() {
	if len(os.Args) < 2 || strings.HasSuffix(os.Args[1], "help") {
		usage()
		os.Exit(1)
	}

	// Add all the sources to the registry.
	for _, src := range os.Args[1:] {
		err := filepath.Walk(src, walkSource)
		if err != nil {
			exit(err)
		}
	}
	parsepasses.ProcessMessages(registry)

	var e = extractor{&po.File{}}
	for _, t := range registry.Templates {
		e.extract(t.Node)
	}
	e.file.WriteTo(os.Stdout)
}

func walkSource(path string, info os.FileInfo, err error) error {
	if err != nil {
		return err
	}
	if !strings.HasSuffix(path, ".soy") {
		return nil
	}

	content, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}

	tree, err := parse.SoyFile(path, string(content))
	if err != nil {
		return err
	}
	if err = registry.Add(tree); err != nil {
		return err
	}
	return nil
}

type extractor struct {
	file *po.File
}

func (e extractor) extract(node ast.Node) {
	switch node := node.(type) {
	case *ast.MsgNode:
		if err := pomsg.Validate(node); err != nil {
			exit(err)
		}
		var pluralVar = ""
		if plural, ok := node.Body.Children()[0].(*ast.MsgPluralNode); ok {
			pluralVar = " var=" + plural.VarName
		}
		e.file.Messages = append(e.file.Messages, po.Message{
			Comment: po.Comment{
				ExtractedComments: []string{node.Desc},
				References:        []string{fmt.Sprintf("id=%d%v", node.ID, pluralVar)},
			},
			Ctxt:     node.Meaning,
			Id:       pomsg.Msgid(node),
			IdPlural: pomsg.MsgidPlural(node),
		})
	default:
		if parent, ok := node.(ast.ParentNode); ok {
			for _, child := range parent.Children() {
				e.extract(child)
			}
		}
	}
}

func exit(err error) {
	fmt.Fprintln(os.Stderr, err)
	os.Exit(1)
}
<commit_msg>fix go vet warning: Fprintln -> Fprint<commit_after>// xgettext-soy is a tool to extract messages from Soy templates in the PO
// (gettext) file format.
package main

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

	"github.com/robfig/gettext/po"
	"github.com/robfig/soy/ast"
	"github.com/robfig/soy/parse"
	"github.com/robfig/soy/parsepasses"
	"github.com/robfig/soy/soymsg/pomsg"
	"github.com/robfig/soy/template"
)

func usage() {
	fmt.Fprint(os.Stderr, `xgettext-soy is a tool to extract messages from Soy templates.

Usage:

	./xgettext-soy [INPUTPATH]...

INPUTPATH elements may be files or directories. Input directories will be
recursively searched for *.soy files.

The resulting POT (PO template) file is written to STDOUT`)
}

var registry = template.Registry{}

func main() {
	if len(os.Args) < 2 || strings.HasSuffix(os.Args[1], "help") {
		usage()
		os.Exit(1)
	}

	// Add all the sources to the registry.
	for _, src := range os.Args[1:] {
		err := filepath.Walk(src, walkSource)
		if err != nil {
			exit(err)
		}
	}
	parsepasses.ProcessMessages(registry)

	var e = extractor{&po.File{}}
	for _, t := range registry.Templates {
		e.extract(t.Node)
	}
	e.file.WriteTo(os.Stdout)
}

func walkSource(path string, info os.FileInfo, err error) error {
	if err != nil {
		return err
	}
	if !strings.HasSuffix(path, ".soy") {
		return nil
	}

	content, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}

	tree, err := parse.SoyFile(path, string(content))
	if err != nil {
		return err
	}
	if err = registry.Add(tree); err != nil {
		return err
	}
	return nil
}

type extractor struct {
	file *po.File
}

func (e extractor) extract(node ast.Node) {
	switch node := node.(type) {
	case *ast.MsgNode:
		if err := pomsg.Validate(node); err != nil {
			exit(err)
		}
		var pluralVar = ""
		if plural, ok := node.Body.Children()[0].(*ast.MsgPluralNode); ok {
			pluralVar = " var=" + plural.VarName
		}
		e.file.Messages = append(e.file.Messages, po.Message{
			Comment: po.Comment{
				ExtractedComments: []string{node.Desc},
				References:        []string{fmt.Sprintf("id=%d%v", node.ID, pluralVar)},
			},
			Ctxt:     node.Meaning,
			Id:       pomsg.Msgid(node),
			IdPlural: pomsg.MsgidPlural(node),
		})
	default:
		if parent, ok := node.(ast.ParentNode); ok {
			for _, child := range parent.Children() {
				e.extract(child)
			}
		}
	}
}

func exit(err error) {
	fmt.Fprintln(os.Stderr, err)
	os.Exit(1)
}
<|endoftext|>


<commit_before>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package v1

import (
	"github.com/loadimpact/k6/core"
	"gopkg.in/guregu/null.v3"
)

type Status struct {
	Paused null.Bool `json:"paused" yaml:"paused"`
	VUs    null.Int  `json:"vus" yaml:"vus"`
	VUsMax null.Int  `json:"vus-max" yaml:"vus-max"`

	// Readonly.
	Running bool `json:"running" yaml:"running"`
	Tainted bool `json:"tainted" yaml:"tainted"`
}

func NewStatus(engine *core.Engine) Status {
	executionState := engine.ExecutionScheduler.GetState()
	return Status{
		Running: executionState.HasStarted() && !executionState.HasEnded(),
		Paused:  null.BoolFrom(executionState.IsPaused()),
		VUs:     null.IntFrom(executionState.GetCurrentlyActiveVUsCount()),
		VUsMax:  null.IntFrom(executionState.GetInitializedVUsCount()),
		Tainted: engine.IsTainted(),
	}
}

func (s Status) GetName() string {
	return "status"
}

func (s Status) GetID() string {
	return "default"
}

func (s Status) SetID(id string) error {
	return nil
}
<commit_msg>Expose the execution status via the REST API<commit_after>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package v1

import (
	"github.com/loadimpact/k6/core"
	"github.com/loadimpact/k6/lib"
	"gopkg.in/guregu/null.v3"
)

type Status struct {
	Status lib.ExecutionStatus `json:"status" yaml:"status"`

	Paused  null.Bool `json:"paused" yaml:"paused"`
	VUs     null.Int  `json:"vus" yaml:"vus"`
	VUsMax  null.Int  `json:"vus-max" yaml:"vus-max"`
	Running bool      `json:"running" yaml:"running"`
	Tainted bool      `json:"tainted" yaml:"tainted"`
}

func NewStatus(engine *core.Engine) Status {
	executionState := engine.ExecutionScheduler.GetState()
	return Status{
		Status:  executionState.GetCurrentExecutionStatus(),
		Running: executionState.HasStarted() && !executionState.HasEnded(),
		Paused:  null.BoolFrom(executionState.IsPaused()),
		VUs:     null.IntFrom(executionState.GetCurrentlyActiveVUsCount()),
		VUsMax:  null.IntFrom(executionState.GetInitializedVUsCount()),
		Tainted: engine.IsTainted(),
	}
}

func (s Status) GetName() string {
	return "status"
}

func (s Status) GetID() string {
	return "default"
}

func (s Status) SetID(id string) error {
	return nil
}
<|endoftext|>