<commit_before>package swag

import (
	"fmt"
	"regexp"
	"strconv"
	"strings"

	"github.com/go-openapi/jsonreference"
	"github.com/go-openapi/spec"
)

// Operation describes a single API operation on a path.
//
//  For more information: https://github.com/swaggo/swag#api-operation
type Operation struct {
	HttpMethod string
	Path       string
	spec.Operation

	parser *Parser // TODO: we don't need it
}

// NewOperation creates a new Operation with default properties.
// map[int]Response
func NewOperation() *Operation {
	return &Operation{
		HttpMethod: "get",
		Operation: spec.Operation{
			OperationProps: spec.OperationProps{},
		},
	}
}

// ParseComment parses comment for gived comment string and returns error if error occurs.
func (operation *Operation) ParseComment(comment string) error {
	commentLine := strings.TrimSpace(strings.TrimLeft(comment, "//"))
	if len(commentLine) == 0 {
		return nil
	}

	attribute := strings.Fields(commentLine)[0]
	switch strings.ToLower(attribute) {
	case "@description":
		operation.Description = strings.TrimSpace(commentLine[len(attribute):])
	case "@summary":
		operation.Summary = strings.TrimSpace(commentLine[len(attribute):])
	case "@id":
		operation.ID = strings.TrimSpace(commentLine[len(attribute):])
	case "@accept":
		if err := operation.ParseAcceptComment(strings.TrimSpace(commentLine[len(attribute):])); err != nil {
			return err
		}
	case "@produce":
		if err := operation.ParseProduceComment(strings.TrimSpace(commentLine[len(attribute):])); err != nil {
			return err
		}
	case "@param":
		if err := operation.ParseParamComment(strings.TrimSpace(commentLine[len(attribute):])); err != nil {
			return err
		}
	case "@success", "@failure":
		if err := operation.ParseResponseComment(strings.TrimSpace(commentLine[len(attribute):])); err != nil {

			if errWhenEmpty := operation.ParseEmptyResponseComment(strings.TrimSpace(commentLine[len(attribute):])); errWhenEmpty != nil {
				var errs []string
				errs = append(errs, err.Error())
				errs = append(errs, errWhenEmpty.Error())

				return fmt.Errorf(strings.Join(errs, "\n"))

			}
		}

	case "@router":
		if err := operation.ParseRouterComment(strings.TrimSpace(commentLine[len(attribute):])); err != nil {
			return err
		}
	}

	return nil
}

// Parse params return []string of param properties
// @Param	queryText		form	      string	  true		        "The email for login"
// 			[param name]    [paramType] [data type]  [is mandatory?]   [Comment]
// @Param   some_id     path    int     true        "Some ID"
func (operation *Operation) ParseParamComment(commentLine string) error {
	paramString := commentLine

	re := regexp.MustCompile(`([-\w]+)[\s]+([\w]+)[\s]+([\S.]+)[\s]+([\w]+)[\s]+"([^"]+)"`)

	if matches := re.FindStringSubmatch(paramString); len(matches) != 6 {
		return fmt.Errorf("Can not parse param comment \"%s\", skipped.", paramString)
	} else {
		name := matches[1]
		paramType := matches[2]

		schemaType := matches[3]

		requiredText := strings.ToLower(matches[4])
		required := (requiredText == "true" || requiredText == "required")
		description := matches[5]

		var param spec.Parameter

		//five possible parameter types.
		switch paramType {
		case "query", "path":
			param = createParameter(paramType, description, name, schemaType, required)
		case "body":
			param = createParameter(paramType, description, name, "object", required) // TODO: if Parameter types can be objects, but also primitives and arrays

			// TODO: this snippets have to extract out
			refSplit := strings.Split(schemaType, ".")
			if len(refSplit) == 2 {
				//TODO:---------- extract out
				pkgName := refSplit[0]
				typeName := refSplit[1]
				if typeSpec, ok := operation.parser.TypeDefinitions[pkgName][typeName]; ok {
					operation.parser.registerTypes[schemaType] = typeSpec
				} else {
					return fmt.Errorf("Can not find ref type:\"%s\".", schemaType)
				}
				//TODO:----------
				param.Schema.Ref = spec.Ref{
					Ref: jsonreference.MustCreateRef("#/definitions/" + schemaType),
				}
			}

			//case "Header": // TODO: support Header and Form
			//	panic("not supported Header paramType yet.")
			//case "Form":
			//	panic("not supported Form paramType yet.")
		}

		operation.Operation.Parameters = append(operation.Operation.Parameters, param)
	}

	return nil
}
func (operation *Operation) ParseAcceptComment(commentLine string) error {
	accepts := strings.Split(commentLine, ",")
	for _, a := range accepts {
		switch a {
		case "json", "application/json":
			operation.Consumes = append(operation.Consumes, "application/json")
		case "xml", "text/xml":
			operation.Consumes = append(operation.Consumes, "text/xml")
		case "plain", "text/plain":
			operation.Consumes = append(operation.Consumes, "text/plain")
		case "html", "text/html":
			operation.Consumes = append(operation.Consumes, "text/html")
		case "mpfd", "multipart/form-data":
			operation.Consumes = append(operation.Consumes, "multipart/form-data")
		default:
			return fmt.Errorf("%v accept type can't accepted.", a)
		}
	}
	return nil
}

func (operation *Operation) ParseProduceComment(commentLine string) error {
	produces := strings.Split(commentLine, ",")
	for _, a := range produces {
		switch a {
		case "json", "application/json":
			operation.Produces = append(operation.Produces, "application/json")
		case "xml", "text/xml":
			operation.Produces = append(operation.Produces, "text/xml")
		case "plain", "text/plain":
			operation.Produces = append(operation.Produces, "text/plain")
		case "html", "text/html":
			operation.Produces = append(operation.Produces, "text/html")
		case "mpfd", "multipart/form-data":
			operation.Produces = append(operation.Produces, "multipart/form-data")
		default:
			return fmt.Errorf("%v produce type can't accepted.", a)
		}
	}
	return nil
}

func (operation *Operation) ParseRouterComment(commentLine string) error {
	re := regexp.MustCompile(`([\w\.\/\-{}]+)[^\[]+\[([^\]]+)`)
	var matches []string

	if matches = re.FindStringSubmatch(commentLine); len(matches) != 3 {
		return fmt.Errorf("Can not parse router comment \"%s\", skipped.", commentLine)
	}
	path := matches[1]
	httpMethod := matches[2]

	operation.Path = path
	operation.HttpMethod = strings.ToUpper(httpMethod)

	return nil
}

func (operation *Operation) ParseResponseComment(commentLine string) error {
	re := regexp.MustCompile(`([\d]+)[\s]+([\w\{\}]+)[\s]+([\w\-\.\/]+)[^"]*(.*)?`)
	var matches []string

	if matches = re.FindStringSubmatch(commentLine); len(matches) != 5 {
		return fmt.Errorf("Can not parse response comment \"%s\".", commentLine)
	}

	response := spec.Response{}

	code, _ := strconv.Atoi(matches[1])

	response.Description = strings.Trim(matches[4], "\"")

	schemaType := strings.Trim(matches[2], "{}")
	refType := matches[3]

	if operation.parser != nil { // checking refType has existing in 'TypeDefinitions'
		refSplit := strings.Split(refType, ".")
		if len(refSplit) == 2 {
			pkgName := refSplit[0]
			typeName := refSplit[1]
			if typeSpec, ok := operation.parser.TypeDefinitions[pkgName][typeName]; ok {
				operation.parser.registerTypes[refType] = typeSpec
			} else {
				return fmt.Errorf("Can not find ref type:\"%s\".", refType)
			}

		}
	}

	// so we have to know all type in app
	//TODO: we might omitted schema.type if schemaType equals 'object'
	response.Schema = &spec.Schema{SchemaProps: spec.SchemaProps{Type: []string{schemaType}}}

	if schemaType == "object" {
		response.Schema.Ref = spec.Ref{
			Ref: jsonreference.MustCreateRef("#/definitions/" + refType),
		}
	}

	if schemaType == "array" {
		response.Schema.Items = &spec.SchemaOrArray{
			Schema: &spec.Schema{
				SchemaProps: spec.SchemaProps{
					Ref: spec.Ref{Ref: jsonreference.MustCreateRef("#/definitions/" + refType)},
				},
			},
		}

	}

	if operation.Responses == nil {
		operation.Responses = &spec.Responses{
			ResponsesProps: spec.ResponsesProps{
				StatusCodeResponses: make(map[int]spec.Response),
			},
		}
	}

	operation.Responses.StatusCodeResponses[code] = response

	return nil
}

func (operation *Operation) ParseEmptyResponseComment(commentLine string) error {
	re := regexp.MustCompile(`([\d]+)[\s]+"(.*)"`)
	var matches []string

	if matches = re.FindStringSubmatch(commentLine); len(matches) != 3 {
		return fmt.Errorf("can not parse empty response comment \"%s\"", commentLine)
	}

	response := spec.Response{}

	code, _ := strconv.Atoi(matches[1])

	response.Description = strings.Trim(matches[2], "")

	if operation.Responses == nil {
		operation.Responses = &spec.Responses{
			ResponsesProps: spec.ResponsesProps{
				StatusCodeResponses: make(map[int]spec.Response),
			},
		}
	}

	operation.Responses.StatusCodeResponses[code] = response

	return nil
}

// createParamter returns swagger spec.Parameter for gived  paramType, description, paramName, schemaType, required
func createParameter(paramType, description, paramName, schemaType string, required bool) spec.Parameter {
	// //five possible parameter types. 	query, path, body, header, form
	paramProps := spec.ParamProps{
		Name:        paramName,
		Description: description,
		Required:    required,
		In:          paramType,
	}
	if paramType == "body" {
		paramProps.Schema = &spec.Schema{
			SchemaProps: spec.SchemaProps{
				Type: []string{schemaType},
			},
		}
		parameter := spec.Parameter{
			ParamProps: paramProps,
		}

		return parameter
	} else {
		parameter := spec.Parameter{
			ParamProps: paramProps,
			SimpleSchema: spec.SimpleSchema{
				Type: schemaType,
			},
		}
		return parameter

	}
}
<commit_msg>enable  multipart/form-data  and can upload files (#20)<commit_after>package swag

import (
	"fmt"
	"regexp"
	"strconv"
	"strings"

	"github.com/go-openapi/jsonreference"
	"github.com/go-openapi/spec"
)

// Operation describes a single API operation on a path.
//
//  For more information: https://github.com/swaggo/swag#api-operation
type Operation struct {
	HttpMethod string
	Path       string
	spec.Operation

	parser *Parser // TODO: we don't need it
}

// NewOperation creates a new Operation with default properties.
// map[int]Response
func NewOperation() *Operation {
	return &Operation{
		HttpMethod: "get",
		Operation: spec.Operation{
			OperationProps: spec.OperationProps{},
		},
	}
}

// ParseComment parses comment for gived comment string and returns error if error occurs.
func (operation *Operation) ParseComment(comment string) error {
	commentLine := strings.TrimSpace(strings.TrimLeft(comment, "//"))
	if len(commentLine) == 0 {
		return nil
	}

	attribute := strings.Fields(commentLine)[0]
	switch strings.ToLower(attribute) {
	case "@description":
		operation.Description = strings.TrimSpace(commentLine[len(attribute):])
	case "@summary":
		operation.Summary = strings.TrimSpace(commentLine[len(attribute):])
	case "@id":
		operation.ID = strings.TrimSpace(commentLine[len(attribute):])
	case "@accept":
		if err := operation.ParseAcceptComment(strings.TrimSpace(commentLine[len(attribute):])); err != nil {
			return err
		}
	case "@produce":
		if err := operation.ParseProduceComment(strings.TrimSpace(commentLine[len(attribute):])); err != nil {
			return err
		}
	case "@param":
		if err := operation.ParseParamComment(strings.TrimSpace(commentLine[len(attribute):])); err != nil {
			return err
		}
	case "@success", "@failure":
		if err := operation.ParseResponseComment(strings.TrimSpace(commentLine[len(attribute):])); err != nil {

			if errWhenEmpty := operation.ParseEmptyResponseComment(strings.TrimSpace(commentLine[len(attribute):])); errWhenEmpty != nil {
				var errs []string
				errs = append(errs, err.Error())
				errs = append(errs, errWhenEmpty.Error())

				return fmt.Errorf(strings.Join(errs, "\n"))

			}
		}

	case "@router":
		if err := operation.ParseRouterComment(strings.TrimSpace(commentLine[len(attribute):])); err != nil {
			return err
		}
	}

	return nil
}

// Parse params return []string of param properties
// @Param	queryText		form	      string	  true		        "The email for login"
// 			[param name]    [paramType] [data type]  [is mandatory?]   [Comment]
// @Param   some_id     path    int     true        "Some ID"
func (operation *Operation) ParseParamComment(commentLine string) error {
	paramString := commentLine

	re := regexp.MustCompile(`([-\w]+)[\s]+([\w]+)[\s]+([\S.]+)[\s]+([\w]+)[\s]+"([^"]+)"`)

	if matches := re.FindStringSubmatch(paramString); len(matches) != 6 {
		return fmt.Errorf("Can not parse param comment \"%s\", skipped.", paramString)
	} else {
		name := matches[1]
		paramType := matches[2]

		schemaType := matches[3]

		requiredText := strings.ToLower(matches[4])
		required := (requiredText == "true" || requiredText == "required")
		description := matches[5]

		var param spec.Parameter

		//five possible parameter types.
		switch paramType {
		case "query", "path":
			param = createParameter(paramType, description, name, schemaType, required)
		case "body":
			param = createParameter(paramType, description, name, "object", required) // TODO: if Parameter types can be objects, but also primitives and arrays

			// TODO: this snippets have to extract out
			refSplit := strings.Split(schemaType, ".")
			if len(refSplit) == 2 {
				//TODO:---------- extract out
				pkgName := refSplit[0]
				typeName := refSplit[1]
				if typeSpec, ok := operation.parser.TypeDefinitions[pkgName][typeName]; ok {
					operation.parser.registerTypes[schemaType] = typeSpec
				} else {
					return fmt.Errorf("Can not find ref type:\"%s\".", schemaType)
				}
				//TODO:----------
				param.Schema.Ref = spec.Ref{
					Ref: jsonreference.MustCreateRef("#/definitions/" + schemaType),
				}
			}

			//case "Header": // TODO: support Header and Form
			//	panic("not supported Header paramType yet.")
			//case "Form":
			//	panic("not supported Form paramType yet.")
			// enable multipart/form-data upload file
		case "formData" :
		        param = createParameter(paramType, description, name, "file", required)
		}
		operation.Operation.Parameters = append(operation.Operation.Parameters, param)
	}

	return nil
}
func (operation *Operation) ParseAcceptComment(commentLine string) error {
	accepts := strings.Split(commentLine, ",")
	for _, a := range accepts {
		switch a {
		case "json", "application/json":
			operation.Consumes = append(operation.Consumes, "application/json")
		case "xml", "text/xml":
			operation.Consumes = append(operation.Consumes, "text/xml")
		case "plain", "text/plain":
			operation.Consumes = append(operation.Consumes, "text/plain")
		case "html", "text/html":
			operation.Consumes = append(operation.Consumes, "text/html")
		case "mpfd", "multipart/form-data":
			operation.Consumes = append(operation.Consumes, "multipart/form-data")
		default:
			return fmt.Errorf("%v accept type can't accepted.", a)
		}
	}
	return nil
}

func (operation *Operation) ParseProduceComment(commentLine string) error {
	produces := strings.Split(commentLine, ",")
	for _, a := range produces {
		switch a {
		case "json", "application/json":
			operation.Produces = append(operation.Produces, "application/json")
		case "xml", "text/xml":
			operation.Produces = append(operation.Produces, "text/xml")
		case "plain", "text/plain":
			operation.Produces = append(operation.Produces, "text/plain")
		case "html", "text/html":
			operation.Produces = append(operation.Produces, "text/html")
		case "mpfd", "multipart/form-data":
			operation.Produces = append(operation.Produces, "multipart/form-data")
		default:
			return fmt.Errorf("%v produce type can't accepted.", a)
		}
	}
	return nil
}

func (operation *Operation) ParseRouterComment(commentLine string) error {
	re := regexp.MustCompile(`([\w\.\/\-{}]+)[^\[]+\[([^\]]+)`)
	var matches []string

	if matches = re.FindStringSubmatch(commentLine); len(matches) != 3 {
		return fmt.Errorf("Can not parse router comment \"%s\", skipped.", commentLine)
	}
	path := matches[1]
	httpMethod := matches[2]

	operation.Path = path
	operation.HttpMethod = strings.ToUpper(httpMethod)

	return nil
}

func (operation *Operation) ParseResponseComment(commentLine string) error {
	re := regexp.MustCompile(`([\d]+)[\s]+([\w\{\}]+)[\s]+([\w\-\.\/]+)[^"]*(.*)?`)
	var matches []string

	if matches = re.FindStringSubmatch(commentLine); len(matches) != 5 {
		return fmt.Errorf("Can not parse response comment \"%s\".", commentLine)
	}

	response := spec.Response{}

	code, _ := strconv.Atoi(matches[1])

	response.Description = strings.Trim(matches[4], "\"")

	schemaType := strings.Trim(matches[2], "{}")
	refType := matches[3]

	if operation.parser != nil { // checking refType has existing in 'TypeDefinitions'
		refSplit := strings.Split(refType, ".")
		if len(refSplit) == 2 {
			pkgName := refSplit[0]
			typeName := refSplit[1]
			if typeSpec, ok := operation.parser.TypeDefinitions[pkgName][typeName]; ok {
				operation.parser.registerTypes[refType] = typeSpec
			} else {
				return fmt.Errorf("Can not find ref type:\"%s\".", refType)
			}

		}
	}

	// so we have to know all type in app
	//TODO: we might omitted schema.type if schemaType equals 'object'
	response.Schema = &spec.Schema{SchemaProps: spec.SchemaProps{Type: []string{schemaType}}}

	if schemaType == "object" {
		response.Schema.Ref = spec.Ref{
			Ref: jsonreference.MustCreateRef("#/definitions/" + refType),
		}
	}

	if schemaType == "array" {
		response.Schema.Items = &spec.SchemaOrArray{
			Schema: &spec.Schema{
				SchemaProps: spec.SchemaProps{
					Ref: spec.Ref{Ref: jsonreference.MustCreateRef("#/definitions/" + refType)},
				},
			},
		}

	}

	if operation.Responses == nil {
		operation.Responses = &spec.Responses{
			ResponsesProps: spec.ResponsesProps{
				StatusCodeResponses: make(map[int]spec.Response),
			},
		}
	}

	operation.Responses.StatusCodeResponses[code] = response

	return nil
}

func (operation *Operation) ParseEmptyResponseComment(commentLine string) error {
	re := regexp.MustCompile(`([\d]+)[\s]+"(.*)"`)
	var matches []string

	if matches = re.FindStringSubmatch(commentLine); len(matches) != 3 {
		return fmt.Errorf("can not parse empty response comment \"%s\"", commentLine)
	}

	response := spec.Response{}

	code, _ := strconv.Atoi(matches[1])

	response.Description = strings.Trim(matches[2], "")

	if operation.Responses == nil {
		operation.Responses = &spec.Responses{
			ResponsesProps: spec.ResponsesProps{
				StatusCodeResponses: make(map[int]spec.Response),
			},
		}
	}

	operation.Responses.StatusCodeResponses[code] = response

	return nil
}

// createParamter returns swagger spec.Parameter for gived  paramType, description, paramName, schemaType, required
func createParameter(paramType, description, paramName, schemaType string, required bool) spec.Parameter {
	// //five possible parameter types. 	query, path, body, header, form
	paramProps := spec.ParamProps{
		Name:        paramName,
		Description: description,
		Required:    required,
		In:          paramType,
	}
	if paramType == "body" {
		paramProps.Schema = &spec.Schema{
			SchemaProps: spec.SchemaProps{
				Type: []string{schemaType},
			},
		}
		parameter := spec.Parameter{
			ParamProps: paramProps,
		}

		return parameter
	} else {
		parameter := spec.Parameter{
			ParamProps: paramProps,
			SimpleSchema: spec.SimpleSchema{
				Type: schemaType,
			},
		}
		return parameter

	}
}
<|endoftext|>


<commit_before>package main

import (
	"./types"
	"fmt"
	"github.com/jessevdk/go-flags"
	"go/ast"
	"go/build"
	"go/format"
	"go/parser"
	"go/token"
	"os"
	"path"
)

func getSourceDir(args []string) string {
	if len(args) > 1 {
		fmt.Fprintf(os.Stderr, "Please provide only a single directory to parse\n")
		os.Exit(1)
	}

	if len(args) == 0 {
		dirname, err := os.Getwd()

		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to obtain current working directory\n")
			os.Exit(1)
		}

		return dirname
	}

	return args[0]
}

func main() {
	var opts struct {
		Output  string `short:"o" long:"output" description:"Output directory (required)" required:"true"`
		Verbose bool   `short:"v" long:"verbose" description:"Enable verbose mode"`
	}

	fp := flags.NewParser(&opts, flags.Default)
	fp.Usage = "--output OUTPUT_DIR [OPTIONS] SOURCE_DIR"

	args, err := fp.Parse()

	if err != nil {
		os.Exit(1)
	}

	if err := os.MkdirAll(opts.Output, 0766); err != nil {
		fmt.Fprintf(os.Stderr, "Failed to create output directory: %s\n", err)
		os.Exit(1)
	}

	dirname := getSourceDir(args)

	p, err := build.ImportDir(dirname, 0)

	if err != nil {
		panic(err)
	}

	fs := token.NewFileSet()
	afs := make([]*ast.File, 0, len(p.GoFiles))

	for _, f := range p.GoFiles {
		af, err := parser.ParseFile(fs, path.Join(dirname, f), nil, 0)

		if err != nil {
			panic(err)
		}

		afs = append(afs, af)
	}

	pp, err := types.Check(dirname, fs, afs)

	if err != nil {
		fmt.Fprintf(os.Stderr, "Error while parsing: %s\n", err)
		os.Exit(1)
	}

	overloads := pp.Overloads()

	for i, f := range afs {
		f = replace(func(node ast.Node) ast.Node {
			expr, ok := node.(ast.Expr)

			if !ok {
				return node
			}

			info, ok := overloads[expr]

			if !ok {
				return node
			}

			sel := &ast.SelectorExpr{
				X:   info.Recv,
				Sel: ast.NewIdent(info.Func.Name()),
			}

			args := []ast.Expr{}

			if info.Oper != nil {
				args = append(args, info.Oper)
			}

			// Create function call expression
			call := &ast.CallExpr{
				Fun:  sel,
				Args: args,
			}

			return call
		}, f).(*ast.File)

		fn := path.Join(opts.Output, p.GoFiles[i])

		of, err := os.Create(fn)

		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to create output file: %s\n", err)
			os.Exit(1)
		}

		defer of.Close()

		if opts.Verbose {
			fmt.Println(fn)
		}

		format.Node(of, fs, f)
	}
}
<commit_msg>Allow parsing of single files<commit_after>package main

import (
	"./types"
	"fmt"
	"github.com/jessevdk/go-flags"
	"go/ast"
	"go/build"
	"go/format"
	"go/parser"
	"go/token"
	"os"
	"path"
)

func getSources(args []string) (dirname string, files []string) {
	if len(args) == 0 {
		dirname, err := os.Getwd()

		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to obtain current working directory\n")
			os.Exit(1)
		}

		return dirname, nil
	}

	if len(args) == 1 {
		info, err := os.Stat(args[0])

		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to check file `%s': %s\n", args[0], err)
			os.Exit(1)
		}

		if info.IsDir() {
			return args[0], nil
		}
	}

	return "", args
}

func main() {
	var opts struct {
		Output  string `short:"o" long:"output" description:"Output directory (required)" required:"true"`
		Verbose bool   `short:"v" long:"verbose" description:"Enable verbose mode"`
		Package string `short:"p" long:"package" description:"Package name" default:"main"`
	}

	fp := flags.NewParser(&opts, flags.Default)
	fp.Usage = "--output OUTPUT_DIR [OPTIONS] SOURCE_DIR"

	args, err := fp.Parse()

	if err != nil {
		os.Exit(1)
	}

	if err := os.MkdirAll(opts.Output, 0766); err != nil {
		fmt.Fprintf(os.Stderr, "Failed to create output directory: %s\n", err)
		os.Exit(1)
	}

	dirname, files := getSources(args)

	if len(dirname) != 0 {
		p, err := build.ImportDir(dirname, 0)

		if err != nil {
			panic(err)
		}

		for _, f := range p.GoFiles {
			files = append(files, path.Join(dirname, f))
		}
	}

	fs := token.NewFileSet()
	afs := make([]*ast.File, 0, len(files))

	for _, f := range files {
		af, err := parser.ParseFile(fs, f, nil, 0)

		if err != nil {
			panic(err)
		}

		afs = append(afs, af)
	}

	pkgname := path.Base(dirname)

	if len(pkgname) == 0 {
		pkgname = opts.Package
	}

	pp, err := types.Check(pkgname, fs, afs)

	if err != nil {
		fmt.Fprintf(os.Stderr, "Error while parsing: %s\n", err)
		os.Exit(1)
	}

	overloads := pp.Overloads()

	for i, f := range afs {
		f = replace(func(node ast.Node) ast.Node {
			expr, ok := node.(ast.Expr)

			if !ok {
				return node
			}

			info, ok := overloads[expr]

			if !ok {
				return node
			}

			sel := &ast.SelectorExpr{
				X:   info.Recv,
				Sel: ast.NewIdent(info.Func.Name()),
			}

			args := []ast.Expr{}

			if info.Oper != nil {
				args = append(args, info.Oper)
			}

			// Create function call expression
			call := &ast.CallExpr{
				Fun:  sel,
				Args: args,
			}

			return call
		}, f).(*ast.File)

		fn := path.Join(opts.Output, files[i])
		err := os.MkdirAll(path.Join(opts.Output, path.Dir(files[i])), 0766)

		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to create output directory: %s\n", err)
			os.Exit(1)
		}

		of, err := os.Create(fn)

		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to create output file: %s\n", err)
			os.Exit(1)
		}

		defer of.Close()

		if opts.Verbose {
			fmt.Println(fn)
		}

		format.Node(of, fs, f)
	}
}
<|endoftext|>


<commit_before>// gorewind is an event store server written in Python that talks ZeroMQ.
// Copyright (C) 2013  Jens Rantil
//
// 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/>.

// Deals with persisting events to disk and querying them. No network is
// involved in any of the code in this package.
package server

import (
	"bytes"
	"sync"
	"math/big"
	"strconv"
	//"code.google.com/p/leveldb-go/leveldb"
	"github.com/syndtr/goleveldb/leveldb"
	"github.com/syndtr/goleveldb/leveldb/descriptor"
	"github.com/syndtr/goleveldb/leveldb/comparer"
	"github.com/syndtr/goleveldb/leveldb/opt"
)

const (
	EVENT_ID_CHAN_SIZE = 100
)

// Instance of an event store. All of its functions are threadsafe.
type EventStore struct {
	eventPublishersLock sync.RWMutex
	// Using a map to avoid registering a channel multiple times
	eventPublishers map[chan StoredEvent]chan StoredEvent

	// A channel where we can make read event ID:s in a lock-free
	// way.
	eventIdChan chan string

	// Write something to this channel to quit the generator
	eventIdChanGeneratorShutdown chan bool

	db *leveldb.DB
}

// An event that has not yet been persisted to disk.
type UnstoredEvent struct {
	Stream []byte
	Data []byte
}

// An event that has previously been persisted to disk.
type StoredEvent struct {
	Stream []byte
	Id []byte
	Data []byte
}

// Register a channel where are published events will be pushed to.
// Multiple channels can be registered.
func (v *EventStore) RegisterPublishedEventsChannel(publisher chan StoredEvent) {
	// TODO: Implement an UnregisterPublishedEventsChannel.
	v.eventPublishersLock.Lock()
	defer v.eventPublishersLock.Unlock()
	v.eventPublishers[publisher] = publisher
}

var streamPrefix []byte = []byte("stream")
var eventPrefix []byte = []byte("event")

// Store an event to the event store. Returns the unique event id that
// the event was stored under. As long as no error occurred, of course.
func (v *EventStore) Add(event UnstoredEvent) (string, error) {
	newId := <-v.eventIdChan

	batch := new(leveldb.Batch)

	// TODO: Benchmark how much impact this write has. We could also
	// check if it exists and not write it in that case, which is
	// probably faster. Especially if we are using bloom filter.
	// TODO: Rewrite to use eventStoreKey
	streamKeyParts := [][]byte{streamPrefix, event.Stream}
	streamKey := bytes.Join(streamKeyParts, []byte(""))
	batch.Put(streamKey, []byte(""))

	evKeyParts := [][]byte{
		eventPrefix,
		event.Stream,
		[]byte(":"),
		[]byte(newId),
	}
	evKey := bytes.Join(evKeyParts, []byte(""))
	batch.Put(evKey, event.Data)

	wo := &opt.WriteOptions{}
	err := v.db.Write(batch, wo)
	if err != nil {
		return "", err
	}

	storedEvent := StoredEvent{
		Stream: event.Stream,
		Id: []byte(newId),
		Data: event.Data,
	}
	for pubchan := range v.eventPublishers {
		pubchan <- storedEvent
	}
	return newId, nil
}

// Close an open event store. A previously closed event store must never
// be used further.
func (v* EventStore) Close() error {
	v.eventIdChanGeneratorShutdown <- true
	return nil
}

// A query request.
type QueryRequest struct {
	Stream []byte
	FromId []byte
	ToId []byte
}

// Query events from an event store. If the request is malformed in any
// way, an error is returned. Otherwise, the query result is streamed
// through the res channel in chronological order.
func (v* EventStore) Query(req QueryRequest, res chan StoredEvent) error {
	// TODO: Implement
	close(res)
	return nil
}

func startEventIdGenerator() (chan string, chan bool) {
	// TODO: Allow nextId to be set explicitly based on what's
	// previously been stored in the event store.
	nextId := big.NewInt(0)
	stopChan := make(chan bool)
	idChan := make(chan string, EVENT_ID_CHAN_SIZE)
	go func() {
		for {
			select {
			case idChan <- nextId.String():
				nextId.Add(nextId, big.NewInt(1))
			case <-stopChan:
				return
			}
		}
	}()
	return idChan, stopChan
}

// Create a new event store instance.
func NewEventStore(desc descriptor.Desc) (*EventStore, error) {
	estore := new(EventStore)
	estore.eventIdChan, estore.eventIdChanGeneratorShutdown = startEventIdGenerator()

	options := &opt.Options{
		Flag: opt.OFCreateIfMissing,
		Comparer: &EventStreamComparer{},
	}
	db, err := leveldb.Open(desc, options)
	if err != nil {
		return nil, err
	}
	estore.db = db

	return estore, nil
}

// The separator used for separating into the different eventStoreKey
// fields.
var groupSep []byte = []byte(":")

// Represents a leveldb key.
type eventStoreKey struct {
	groupKey []byte
	key []byte
	keyId *big.Int
}

// Convert a eventStoreKey to bytes. The returned byte slice is either
// "groupKey:key:keyId" if keyId is non-nil, or "groupKey:key"
// otherwise.
func (v *eventStoreKey) toBytes() []byte {
	var pieces [][]byte
	if v.keyId != nil {
		pieces = make([][]byte, 3)
		pieces[0] = v.groupKey
		pieces[1] = v.key
		pieces[2] = []byte(v.keyId.String())
	} else {
		pieces = make([][]byte, 2)
		pieces[0] = v.groupKey
		pieces[1] = v.key
	}
	return bytes.Join(pieces, groupSep)

}

// Convert a byte slice to a parsed eventStoreKey.
func neweventStoreKey(data []byte) (*eventStoreKey) {
	res := new(eventStoreKey)
	pieces := bytes.Split(data, groupSep)
	if len(pieces) > 2 {
		possibleId := big.NewInt(0)
		_, success := possibleId.SetString(string(pieces[len(pieces)-1]), 10)
		if success {
			res.keyId = possibleId
		}
	}
	if len(pieces) > 0 {
		res.groupKey = pieces[0]
	}
	if len(pieces) > 1 {
		var upperIndex int
		if res.keyId != nil {
			upperIndex = len(pieces) - 1
		} else {
			upperIndex = len(pieces)
		}
		keyPieces := pieces[1:upperIndex]
		res.key = bytes.Join(pieces, groupSep)
	}
	return res
}

// Compare to another eventStoreKey. Returns -1 if this one is smaller
// than o2, 0 same, or 1 is this one is bigger than the previous one.
func (o1 *eventStoreKey) compare(o2 *eventStoreKey) int {
	if diff := bytes.Compare(o1.groupKey, o2.groupKey); diff != 0 {
		return diff
	}
	if diff := bytes.Compare(o1.key, o2.key); diff != 0 {
		return diff
	}
	switch {
	case o1.keyId != nil && o2.keyId != nil:
		return o1.keyId.Cmp(o2.keyId)
	case o1.keyId != nil:
		return 1
	case o2.keyId != nil:
		return -1
	default:
		return 0
	}
}

// Helper functions for comparer

func getGroup(key []byte) []byte {
	return bytes.SplitN(key, groupSep, 1)[0]
}

func getRealKey(key []byte) []byte {
	pieces := bytes.Split(key, groupSep)
	if _, err := getIntegerPart(key); err != nil {
		return bytes.Join(pieces[1:len(pieces)], groupSep)
	}
	return bytes.Join(pieces[1:len(pieces) - 1], groupSep)
}

func getIntegerPart(key []byte) (int, error) {
	pieces := bytes.Split(key, groupSep)
	lastpiece := pieces[len(pieces) - 1]
	i, err := strconv.Atoi(string(lastpiece))
	if err != nil {
		return 0, err
	}
	return i, nil
}

// Comparer

type EventStreamComparer struct {
}

func (v* EventStreamComparer) Name() string {
	return "rewindd.eventStreamComparer"
}

// If 'a' < 'b', changes 'a' to a short string in [a,b).
//
// Used to minimize the size of index blocks and other data structures.
func (v* EventStreamComparer) Separator(a, b []byte) []byte {
	groupA := getGroup(a)
	groupB := getGroup(b)
	if c := bytes.Compare(groupA, groupB); c != 0 {
		bcomp := comparer.BytesComparer{}
		return bytes.Join([][]byte{
			bcomp.Separator(groupA, groupB),
			[]byte{},
		}, groupSep)
	}
	// Here we know that groupA==groupB

	realKeyA := getRealKey(a)
	realKeyB := getRealKey(b)
	if c := bytes.Compare(realKeyA, realKeyB); c != 0 {
		bcomp := comparer.BytesComparer{}
		return bytes.Join([][]byte{
			groupA,
			bcomp.Separator(realKeyA, realKeyA),
		}, groupSep)
	}
	// Here we know that realKeyA==realKeyB

	// TODO: Handle this
	intPartA, errA := getIntegerPart(a)
	intPartB, errB := getIntegerPart(b)
	switch {
	case errA == nil && errB == nil:
		// [Group, key, intA] </>/= [Group, key, intB]
		switch {
		case intPartA < intPartB:
			return bytes.Join([][]byte{
				groupA,
				realKeyA,
				[]byte(strconv.Itoa(intPartB - 1)),
			}, groupSep)
		/*case intPartA > intPartB:
			return a*/
		default:
			return a
		}
	case errA != nil && errB != nil:
		// [Group, key] == [Group, key]
		return a
	case errA != nil:
		// [Group, key, int] > [Group, key]
		return a
	}
	//default: -- must be put outside of switch to avoid compiler
	//error.
	// [Group, key] < [Group, key, int]
	return bytes.Join([][]byte{
		groupA,
		realKeyA,
		[]byte("1"),
	}, groupSep)

	// Unoptimized result that always works.
	return a
}

// Changes 'b' to a short string >= 'b'
//
// Used to minimize the size of index blocks and other data structures.
func (v* EventStreamComparer) Successor(b []byte) []byte {
	groupB := getGroup(b)
	bcomp := comparer.BytesComparer{}
	return bytes.Join([][]byte{
		bcomp.Successor(groupB),
		[]byte{},
	}, groupSep)
}

func (v* EventStreamComparer) Compare(a, b []byte) int {
	groupA := getGroup(a)
	groupB := getGroup(b)
	if c := bytes.Compare(groupA, groupB); c != 0 {
		return c
	}

	realKeyA := getRealKey(a)
	realKeyB := getRealKey(b)
	if c := bytes.Compare(realKeyA, realKeyB); c != 0 {
		return c
	}

	intPartA, errA := getIntegerPart(a)
	intPartB, errB := getIntegerPart(b)
	switch {
	case errA == nil && errB == nil:
		// [Group, key, intA] </>/= [Group, key, intB]
		switch {
		case intPartA < intPartB:
			return -1
		case intPartA > intPartB:
			return 1
		default:
			return 0
		}
	case errA != nil && errB != nil:
		// [Group, key] == [Group, key]
		return 0
	case errA != nil:
		// [Group, key, int] > [Group, key]
		return 1
	}
	//default: -- must be put outside of switch to avoid compiler
	//error.
	// [Group, key] < [Group, key, int]
	return -1
}
<commit_msg>`EventIdGenerator` now supports an init value<commit_after>// gorewind is an event store server written in Python that talks ZeroMQ.
// Copyright (C) 2013  Jens Rantil
//
// 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/>.

// Deals with persisting events to disk and querying them. No network is
// involved in any of the code in this package.
package server

import (
	"bytes"
	"sync"
	"math/big"
	"strconv"
	//"code.google.com/p/leveldb-go/leveldb"
	"github.com/syndtr/goleveldb/leveldb"
	"github.com/syndtr/goleveldb/leveldb/descriptor"
	"github.com/syndtr/goleveldb/leveldb/comparer"
	"github.com/syndtr/goleveldb/leveldb/opt"
)

const (
	EVENT_ID_CHAN_SIZE = 100
)

// Instance of an event store. All of its functions are threadsafe.
type EventStore struct {
	eventPublishersLock sync.RWMutex
	// Using a map to avoid registering a channel multiple times
	eventPublishers map[chan StoredEvent]chan StoredEvent

	// A channel where we can make read event ID:s in a lock-free
	// way.
	eventIdChan chan string

	// Write something to this channel to quit the generator
	eventIdChanGeneratorShutdown chan bool

	db *leveldb.DB
}

// An event that has not yet been persisted to disk.
type UnstoredEvent struct {
	Stream []byte
	Data []byte
}

// An event that has previously been persisted to disk.
type StoredEvent struct {
	Stream []byte
	Id []byte
	Data []byte
}

// Register a channel where are published events will be pushed to.
// Multiple channels can be registered.
func (v *EventStore) RegisterPublishedEventsChannel(publisher chan StoredEvent) {
	// TODO: Implement an UnregisterPublishedEventsChannel.
	v.eventPublishersLock.Lock()
	defer v.eventPublishersLock.Unlock()
	v.eventPublishers[publisher] = publisher
}

var streamPrefix []byte = []byte("stream")
var eventPrefix []byte = []byte("event")

// Store an event to the event store. Returns the unique event id that
// the event was stored under. As long as no error occurred, of course.
func (v *EventStore) Add(event UnstoredEvent) (string, error) {
	newId := <-v.eventIdChan

	batch := new(leveldb.Batch)

	// TODO: Benchmark how much impact this write has. We could also
	// check if it exists and not write it in that case, which is
	// probably faster. Especially if we are using bloom filter.
	// TODO: Rewrite to use eventStoreKey
	streamKeyParts := [][]byte{streamPrefix, event.Stream}
	streamKey := bytes.Join(streamKeyParts, []byte(""))
	batch.Put(streamKey, []byte(""))

	evKeyParts := [][]byte{
		eventPrefix,
		event.Stream,
		[]byte(":"),
		[]byte(newId),
	}
	evKey := bytes.Join(evKeyParts, []byte(""))
	batch.Put(evKey, event.Data)

	wo := &opt.WriteOptions{}
	err := v.db.Write(batch, wo)
	if err != nil {
		return "", err
	}

	storedEvent := StoredEvent{
		Stream: event.Stream,
		Id: []byte(newId),
		Data: event.Data,
	}
	for pubchan := range v.eventPublishers {
		pubchan <- storedEvent
	}
	return newId, nil
}

// Close an open event store. A previously closed event store must never
// be used further.
func (v* EventStore) Close() error {
	v.eventIdChanGeneratorShutdown <- true
	return nil
}

// A query request.
type QueryRequest struct {
	Stream []byte
	FromId []byte
	ToId []byte
}

// Query events from an event store. If the request is malformed in any
// way, an error is returned. Otherwise, the query result is streamed
// through the res channel in chronological order.
func (v* EventStore) Query(req QueryRequest, res chan StoredEvent) error {
	// TODO: Implement
	close(res)
	return nil
}

func startEventIdGenerator(initId *string) (chan string, chan bool) {
	// TODO: Allow nextId to be set explicitly based on what's
	// previously been stored in the event store.
	nextId := big.NewInt(0)
	if initId != nil {
		nextId.SetString(*initId, 10)
		// We do not care if this succeeded. Instead, we simply
		// initialize with zero (0).
	}
	stopChan := make(chan bool)
	idChan := make(chan string, EVENT_ID_CHAN_SIZE)
	go func() {
		for {
			select {
			case idChan <- nextId.String():
				nextId.Add(nextId, big.NewInt(1))
			case <-stopChan:
				return
			}
		}
	}()
	return idChan, stopChan
}

// Create a new event store instance.
func NewEventStore(desc descriptor.Desc) (*EventStore, error) {
	estore := new(EventStore)

	// TODO: Initialize the eventid generator with maxId+1
	initId := "0"
	idChan, idChanShutdown := startEventIdGenerator(&initId)
	estore.eventIdChan = idChan
	estore.eventIdChanGeneratorShutdown = idChanShutdown

	options := &opt.Options{
		Flag: opt.OFCreateIfMissing,
		Comparer: &EventStreamComparer{},
	}
	db, err := leveldb.Open(desc, options)
	if err != nil {
		return nil, err
	}
	estore.db = db

	return estore, nil
}

// The separator used for separating into the different eventStoreKey
// fields.
var groupSep []byte = []byte(":")

// Represents a leveldb key.
type eventStoreKey struct {
	groupKey []byte
	key []byte
	keyId *big.Int
}

// Convert a eventStoreKey to bytes. The returned byte slice is either
// "groupKey:key:keyId" if keyId is non-nil, or "groupKey:key"
// otherwise.
func (v *eventStoreKey) toBytes() []byte {
	var pieces [][]byte
	if v.keyId != nil {
		pieces = make([][]byte, 3)
		pieces[0] = v.groupKey
		pieces[1] = v.key
		pieces[2] = []byte(v.keyId.String())
	} else {
		pieces = make([][]byte, 2)
		pieces[0] = v.groupKey
		pieces[1] = v.key
	}
	return bytes.Join(pieces, groupSep)

}

// Convert a byte slice to a parsed eventStoreKey.
func neweventStoreKey(data []byte) (*eventStoreKey) {
	res := new(eventStoreKey)
	pieces := bytes.Split(data, groupSep)
	if len(pieces) > 2 {
		possibleId := big.NewInt(0)
		_, success := possibleId.SetString(string(pieces[len(pieces)-1]), 10)
		if success {
			res.keyId = possibleId
		}
	}
	if len(pieces) > 0 {
		res.groupKey = pieces[0]
	}
	if len(pieces) > 1 {
		var upperIndex int
		if res.keyId != nil {
			upperIndex = len(pieces) - 1
		} else {
			upperIndex = len(pieces)
		}
		keyPieces := pieces[1:upperIndex]
		res.key = bytes.Join(pieces, groupSep)
	}
	return res
}

// Compare to another eventStoreKey. Returns -1 if this one is smaller
// than o2, 0 same, or 1 is this one is bigger than the previous one.
func (o1 *eventStoreKey) compare(o2 *eventStoreKey) int {
	if diff := bytes.Compare(o1.groupKey, o2.groupKey); diff != 0 {
		return diff
	}
	if diff := bytes.Compare(o1.key, o2.key); diff != 0 {
		return diff
	}
	switch {
	case o1.keyId != nil && o2.keyId != nil:
		return o1.keyId.Cmp(o2.keyId)
	case o1.keyId != nil:
		return 1
	case o2.keyId != nil:
		return -1
	default:
		return 0
	}
}

// Helper functions for comparer

func getGroup(key []byte) []byte {
	return bytes.SplitN(key, groupSep, 1)[0]
}

func getRealKey(key []byte) []byte {
	pieces := bytes.Split(key, groupSep)
	if _, err := getIntegerPart(key); err != nil {
		return bytes.Join(pieces[1:len(pieces)], groupSep)
	}
	return bytes.Join(pieces[1:len(pieces) - 1], groupSep)
}

func getIntegerPart(key []byte) (int, error) {
	pieces := bytes.Split(key, groupSep)
	lastpiece := pieces[len(pieces) - 1]
	i, err := strconv.Atoi(string(lastpiece))
	if err != nil {
		return 0, err
	}
	return i, nil
}

// Comparer

type EventStreamComparer struct {
}

func (v* EventStreamComparer) Name() string {
	return "rewindd.eventStreamComparer"
}

// If 'a' < 'b', changes 'a' to a short string in [a,b).
//
// Used to minimize the size of index blocks and other data structures.
func (v* EventStreamComparer) Separator(a, b []byte) []byte {
	groupA := getGroup(a)
	groupB := getGroup(b)
	if c := bytes.Compare(groupA, groupB); c != 0 {
		bcomp := comparer.BytesComparer{}
		return bytes.Join([][]byte{
			bcomp.Separator(groupA, groupB),
			[]byte{},
		}, groupSep)
	}
	// Here we know that groupA==groupB

	realKeyA := getRealKey(a)
	realKeyB := getRealKey(b)
	if c := bytes.Compare(realKeyA, realKeyB); c != 0 {
		bcomp := comparer.BytesComparer{}
		return bytes.Join([][]byte{
			groupA,
			bcomp.Separator(realKeyA, realKeyA),
		}, groupSep)
	}
	// Here we know that realKeyA==realKeyB

	// TODO: Handle this
	intPartA, errA := getIntegerPart(a)
	intPartB, errB := getIntegerPart(b)
	switch {
	case errA == nil && errB == nil:
		// [Group, key, intA] </>/= [Group, key, intB]
		switch {
		case intPartA < intPartB:
			return bytes.Join([][]byte{
				groupA,
				realKeyA,
				[]byte(strconv.Itoa(intPartB - 1)),
			}, groupSep)
		/*case intPartA > intPartB:
			return a*/
		default:
			return a
		}
	case errA != nil && errB != nil:
		// [Group, key] == [Group, key]
		return a
	case errA != nil:
		// [Group, key, int] > [Group, key]
		return a
	}
	//default: -- must be put outside of switch to avoid compiler
	//error.
	// [Group, key] < [Group, key, int]
	return bytes.Join([][]byte{
		groupA,
		realKeyA,
		[]byte("1"),
	}, groupSep)

	// Unoptimized result that always works.
	return a
}

// Changes 'b' to a short string >= 'b'
//
// Used to minimize the size of index blocks and other data structures.
func (v* EventStreamComparer) Successor(b []byte) []byte {
	groupB := getGroup(b)
	bcomp := comparer.BytesComparer{}
	return bytes.Join([][]byte{
		bcomp.Successor(groupB),
		[]byte{},
	}, groupSep)
}

func (v* EventStreamComparer) Compare(a, b []byte) int {
	groupA := getGroup(a)
	groupB := getGroup(b)
	if c := bytes.Compare(groupA, groupB); c != 0 {
		return c
	}

	realKeyA := getRealKey(a)
	realKeyB := getRealKey(b)
	if c := bytes.Compare(realKeyA, realKeyB); c != 0 {
		return c
	}

	intPartA, errA := getIntegerPart(a)
	intPartB, errB := getIntegerPart(b)
	switch {
	case errA == nil && errB == nil:
		// [Group, key, intA] </>/= [Group, key, intB]
		switch {
		case intPartA < intPartB:
			return -1
		case intPartA > intPartB:
			return 1
		default:
			return 0
		}
	case errA != nil && errB != nil:
		// [Group, key] == [Group, key]
		return 0
	case errA != nil:
		// [Group, key, int] > [Group, key]
		return 1
	}
	//default: -- must be put outside of switch to avoid compiler
	//error.
	// [Group, key] < [Group, key, int]
	return -1
}
<|endoftext|>


<commit_before>package base

import (
	"errors"
	"fmt"
	"log"
	"os"

	"github.com/fatih/color"
)

var logBuffer chan string

func init() {
	logBuffer = make(chan string, 100000)

	go logger()
}

func Log(format string, values ...interface{}) {

	logBuffer <- fmt.Sprintf(format, values...)
}

func logger() {

	if len(os.Getenv("DEBUG_LOGS")) == 0 {
		f, err := os.OpenFile("/log.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
		if err != nil {
			msg := fmt.Sprintf("Couldn't open log file: %s", err)
			log.Printf(color.HiRedString(msg))
			panic(errors.New(msg))
		}
		defer f.Close()
		log.SetOutput(f)
	}

	for {
		log.Printf(<-logBuffer)
	}
}
<commit_msg>write to file<commit_after>package base

import (
	"errors"
	"fmt"
	"log"
	"os"

	"github.com/fatih/color"
)

var logBuffer chan string

func init() {
	logBuffer = make(chan string, 100000)

	go logger()
}

func Log(format string, values ...interface{}) {

	logBuffer <- fmt.Sprintf(format, values...)
}

func logger() {

	if len(os.Getenv("DEBUG_LOGS")) == 0 {

		f, err := os.OpenFile("/log.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
		if err != nil {
			msg := fmt.Sprintf("Couldn't open log file: %s", err)
			log.Printf(color.HiRedString(msg))
			panic(errors.New(msg))
		}
		defer f.Close()

		log.SetOutput(f)
	}

	for {
		log.Printf(<-logBuffer)
	}
}
<|endoftext|>


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

package ipoam

import (
	"fmt"
	"net"
	"time"

	"golang.org/x/net/icmp"
	"golang.org/x/net/ipv4"
	"golang.org/x/net/ipv6"
)

// A Report represents a test report for IP-layer OAM.
type Report struct {
	Error error         // on-link operation error
	Time  time.Time     // time packet received
	Src   net.IP        // source address on received packet
	ICMP  *icmp.Message // received ICMP message

	// Original datagram fields when ICMP is an error message.
	OrigHeader  interface{} // IP header, either ipv4.Header or ipv6.Header
	OrigPayload []byte      // IP payload

	// These fields may not be set when the tester is configured
	// to use non-privileged datagram-oriented ICMP endpoint.
	TC        int            // IPv4 TOS or IPv6 traffic-class on received packet
	Hops      int            // IPv4 TTL or IPv6 hop-limit on receievd packet
	Dst       net.IP         // destinaion address on received packet
	Interface *net.Interface // inbound interface on received packet
}

func parseICMPError(m *icmp.Message) (interface{}, []byte, error) {
	var b []byte
	switch body := m.Body.(type) {
	case *icmp.DstUnreach:
		b = body.Data
	case *icmp.PacketTooBig:
		b = body.Data
	case *icmp.TimeExceeded:
		b = body.Data
	case *icmp.ParamProb:
		b = body.Data
	}

	var iph interface{}
	switch m.Type.Protocol() {
	case ianaProtocolICMP:
		h, err := icmp.ParseIPv4Header(b) // cannot use ipv4.ParseHeader for this purpose
		if err != nil {
			return nil, nil, err
		}
		if len(b) < ipv4.HeaderLen+len(h.Options)+8 {
			return nil, nil, fmt.Errorf("ICMP error message too short: %v, %d", m.Type, m.Code)
		}
		b = b[ipv4.HeaderLen+len(h.Options):]
		iph = h
	case ianaProtocolIPv6ICMP:
		h, err := ipv6.ParseHeader(b)
		if err != nil {
			return nil, nil, err
		}
		if len(b) < ipv6.HeaderLen+8 {
			return nil, nil, fmt.Errorf("ICMP error message too short: %v, %d", m.Type, m.Code)
		}
		b = b[ipv6.HeaderLen:]
		iph = h
	}
	return iph, b, nil
}

func parseOrigIP(iph interface{}) int {
	switch h := iph.(type) {
	case *ipv4.Header:
		return h.Protocol
	case *ipv6.Header:
		return h.NextHeader
	}
	return -1
}

func parseOrigUDP(b []byte) (sport, dport int) {
	if len(b) < 8 {
		return -1, -1
	}
	return int(b[0])<<8 | int(b[1]), int(b[2])<<8 | int(b[3])
}
<commit_msg>ipoam: use of encoding/binary package<commit_after>// Copyright 2015 Mikio Hara. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ipoam

import (
	"encoding/binary"
	"fmt"
	"net"
	"time"

	"golang.org/x/net/icmp"
	"golang.org/x/net/ipv4"
	"golang.org/x/net/ipv6"
)

// A Report represents a test report for IP-layer OAM.
type Report struct {
	Error error         // on-link operation error
	Time  time.Time     // time packet received
	Src   net.IP        // source address on received packet
	ICMP  *icmp.Message // received ICMP message

	// Original datagram fields when ICMP is an error message.
	OrigHeader  interface{} // IP header, either ipv4.Header or ipv6.Header
	OrigPayload []byte      // IP payload

	// These fields may not be set when the tester is configured
	// to use non-privileged datagram-oriented ICMP endpoint.
	TC        int            // IPv4 TOS or IPv6 traffic-class on received packet
	Hops      int            // IPv4 TTL or IPv6 hop-limit on receievd packet
	Dst       net.IP         // destinaion address on received packet
	Interface *net.Interface // inbound interface on received packet
}

func parseICMPError(m *icmp.Message) (interface{}, []byte, error) {
	var b []byte
	switch body := m.Body.(type) {
	case *icmp.DstUnreach:
		b = body.Data
	case *icmp.PacketTooBig:
		b = body.Data
	case *icmp.TimeExceeded:
		b = body.Data
	case *icmp.ParamProb:
		b = body.Data
	}

	var iph interface{}
	switch m.Type.Protocol() {
	case ianaProtocolICMP:
		h, err := icmp.ParseIPv4Header(b) // cannot use ipv4.ParseHeader for this purpose
		if err != nil {
			return nil, nil, err
		}
		if len(b) < ipv4.HeaderLen+len(h.Options)+8 {
			return nil, nil, fmt.Errorf("ICMP error message too short: %v, %d", m.Type, m.Code)
		}
		b = b[ipv4.HeaderLen+len(h.Options):]
		iph = h
	case ianaProtocolIPv6ICMP:
		h, err := ipv6.ParseHeader(b)
		if err != nil {
			return nil, nil, err
		}
		if len(b) < ipv6.HeaderLen+8 {
			return nil, nil, fmt.Errorf("ICMP error message too short: %v, %d", m.Type, m.Code)
		}
		b = b[ipv6.HeaderLen:]
		iph = h
	}
	return iph, b, nil
}

func parseOrigIP(iph interface{}) int {
	switch h := iph.(type) {
	case *ipv4.Header:
		return h.Protocol
	case *ipv6.Header:
		return h.NextHeader
	}
	return -1
}

func parseOrigUDP(b []byte) (sport, dport int) {
	if len(b) < 8 {
		return -1, -1
	}
	return int(binary.BigEndian.Uint16(b[:2])), int(binary.BigEndian.Uint16(b[2:4]))
}
<|endoftext|>


<commit_before>// Copyright 2018 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Gauge 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 General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package lang

import (
	"context"
	"encoding/json"
	"fmt"

	gm "github.com/getgauge/gauge/gauge_messages"
	"github.com/getgauge/gauge/util"
	"github.com/sourcegraph/go-langserver/pkg/lsp"
	"github.com/sourcegraph/jsonrpc2"
)

func documentOpened(req *jsonrpc2.Request, ctx context.Context, conn jsonrpc2.JSONRPC2) error {
	var params lsp.DidOpenTextDocumentParams
	var err error
	if err = json.Unmarshal(*req.Params, &params); err != nil {
		return fmt.Errorf("failed to parse request %s", err.Error())
	}
	if util.IsGaugeFile(string(params.TextDocument.URI)) {
		openFile(params)
	} else if lRunner.runner != nil {
		err = cacheFileOnRunner(params.TextDocument.URI, params.TextDocument.Text, false, gm.CacheFileRequest_OPENED)
	}
	go publishDiagnostics(ctx, conn)
	return err
}

func documentChange(req *jsonrpc2.Request, ctx context.Context, conn jsonrpc2.JSONRPC2) error {
	var params lsp.DidChangeTextDocumentParams
	var err error
	if err = json.Unmarshal(*req.Params, &params); err != nil {
		return fmt.Errorf("failed to parse request %s", err.Error())
	}
	file := params.TextDocument.URI
	if util.IsGaugeFile(string(file)) {
		changeFile(params)
	} else if lRunner.runner != nil {
		err = cacheFileOnRunner(params.TextDocument.URI, params.ContentChanges[0].Text, false, gm.CacheFileRequest_CHANGED)
	}
	go publishDiagnostics(ctx, conn)
	return err
}

func documentClosed(req *jsonrpc2.Request, ctx context.Context, conn jsonrpc2.JSONRPC2) error {
	var params lsp.DidCloseTextDocumentParams
	var err error
	if err := json.Unmarshal(*req.Params, &params); err != nil {
		return fmt.Errorf("failed to parse request. %s", err.Error())
	}
	if util.IsGaugeFile(string(params.TextDocument.URI)) {
		closeFile(params)
	} else if lRunner.runner != nil {
		err = cacheFileOnRunner(params.TextDocument.URI, "", true, gm.CacheFileRequest_CLOSED)
	}
	go publishDiagnostics(ctx, conn)
	return err
}

func documentChangeWatchedFiles(req *jsonrpc2.Request, ctx context.Context, conn jsonrpc2.JSONRPC2) error {
	var params lsp.DidChangeWatchedFilesParams
	if err := json.Unmarshal(*req.Params, &params); err != nil {
		return fmt.Errorf("failed to parse request. %s", err.Error())
	}
	for _, fileEvent := range params.Changes {
		if fileEvent.Type == int(lsp.Created) {
			if err := documentCreate(fileEvent.URI, ctx, conn); err != nil {
				return err
			}
		} else {
			if err := documentCreate(fileEvent.URI, ctx, conn); err != nil {
				return err
			}
		}
	}
	go publishDiagnostics(ctx, conn)
	return nil
}

func documentCreate(uri lsp.DocumentURI, ctx context.Context, conn jsonrpc2.JSONRPC2) error {
	var err error
	if !util.IsGaugeFile(string(uri)) {
		if lRunner.runner != nil {
			err = cacheFileOnRunner(uri, "", false, gm.CacheFileRequest_CREATED)
		}
	}
	return err
}

func documentDelete(uri lsp.DocumentURI, ctx context.Context, conn jsonrpc2.JSONRPC2) error {
	var err error
	if !util.IsGaugeFile(string(uri)) {
		if lRunner.runner != nil {
			err = cacheFileOnRunner(uri, "", false, gm.CacheFileRequest_DELETED)
		}
	} else {
		publishDiagnostic(uri, []lsp.Diagnostic{}, conn, ctx)
	}
	return err
}
<commit_msg>Sending cache file request for delete event. getgauge/gauge-js#141<commit_after>// Copyright 2018 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Gauge 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 General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package lang

import (
	"context"
	"encoding/json"
	"fmt"

	gm "github.com/getgauge/gauge/gauge_messages"
	"github.com/getgauge/gauge/util"
	"github.com/sourcegraph/go-langserver/pkg/lsp"
	"github.com/sourcegraph/jsonrpc2"
)

func documentOpened(req *jsonrpc2.Request, ctx context.Context, conn jsonrpc2.JSONRPC2) error {
	var params lsp.DidOpenTextDocumentParams
	var err error
	if err = json.Unmarshal(*req.Params, &params); err != nil {
		return fmt.Errorf("failed to parse request %s", err.Error())
	}
	if util.IsGaugeFile(string(params.TextDocument.URI)) {
		openFile(params)
	} else if lRunner.runner != nil {
		err = cacheFileOnRunner(params.TextDocument.URI, params.TextDocument.Text, false, gm.CacheFileRequest_OPENED)
	}
	go publishDiagnostics(ctx, conn)
	return err
}

func documentChange(req *jsonrpc2.Request, ctx context.Context, conn jsonrpc2.JSONRPC2) error {
	var params lsp.DidChangeTextDocumentParams
	var err error
	if err = json.Unmarshal(*req.Params, &params); err != nil {
		return fmt.Errorf("failed to parse request %s", err.Error())
	}
	file := params.TextDocument.URI
	if util.IsGaugeFile(string(file)) {
		changeFile(params)
	} else if lRunner.runner != nil {
		err = cacheFileOnRunner(params.TextDocument.URI, params.ContentChanges[0].Text, false, gm.CacheFileRequest_CHANGED)
	}
	go publishDiagnostics(ctx, conn)
	return err
}

func documentClosed(req *jsonrpc2.Request, ctx context.Context, conn jsonrpc2.JSONRPC2) error {
	var params lsp.DidCloseTextDocumentParams
	var err error
	if err := json.Unmarshal(*req.Params, &params); err != nil {
		return fmt.Errorf("failed to parse request. %s", err.Error())
	}
	if util.IsGaugeFile(string(params.TextDocument.URI)) {
		closeFile(params)
	} else if lRunner.runner != nil {
		err = cacheFileOnRunner(params.TextDocument.URI, "", true, gm.CacheFileRequest_CLOSED)
	}
	go publishDiagnostics(ctx, conn)
	return err
}

func documentChangeWatchedFiles(req *jsonrpc2.Request, ctx context.Context, conn jsonrpc2.JSONRPC2) error {
	var params lsp.DidChangeWatchedFilesParams
	if err := json.Unmarshal(*req.Params, &params); err != nil {
		return fmt.Errorf("failed to parse request. %s", err.Error())
	}
	for _, fileEvent := range params.Changes {
		if fileEvent.Type == int(lsp.Created) {
			if err := documentCreate(fileEvent.URI, ctx, conn); err != nil {
				return err
			}
		} else if fileEvent.Type == int(lsp.Deleted) {
			if err := documentDelete(fileEvent.URI, ctx, conn); err != nil {
				return err
			}
		} else {
			if err := documentCreate(fileEvent.URI, ctx, conn); err != nil {
				return err
			}
		}
	}
	go publishDiagnostics(ctx, conn)
	return nil
}

func documentCreate(uri lsp.DocumentURI, ctx context.Context, conn jsonrpc2.JSONRPC2) error {
	var err error
	if !util.IsGaugeFile(string(uri)) {
		if lRunner.runner != nil {
			err = cacheFileOnRunner(uri, "", false, gm.CacheFileRequest_CREATED)
		}
	}
	return err
}

func documentDelete(uri lsp.DocumentURI, ctx context.Context, conn jsonrpc2.JSONRPC2) error {
	var err error
	if !util.IsGaugeFile(string(uri)) {
		if lRunner.runner != nil {
			err = cacheFileOnRunner(uri, "", false, gm.CacheFileRequest_DELETED)
		}
	} else {
		publishDiagnostic(uri, []lsp.Diagnostic{}, conn, ctx)
	}
	return err
}
<|endoftext|>


<commit_before>// Copyright 2016 The Linux Foundation
//
// 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 image

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/pkg/errors"
)

// ValidateLayout walks through the given file tree and validates the manifest
// pointed to by the given refs or returns an error if the validation failed.
func ValidateLayout(src string, refs []string, out *log.Logger) error {
	return validate(newPathWalker(src), refs, out)
}

// ValidateFile opens the tar file given by the filename, then calls ValidateReader
func ValidateFile(tarFile string, refs []string, out *log.Logger) error {
	f, err := os.Open(tarFile)
	if err != nil {
		return errors.Wrap(err, "unable to open file")
	}
	defer f.Close()

	return Validate(f, refs, out)
}

// Validate walks through a tar stream and validates the manifest.
// * Check that all refs point to extant blobs
// * Checks that all referred blobs are valid
// * Checks that mime-types are correct
// returns error on validation failure
func Validate(r io.ReadSeeker, refs []string, out *log.Logger) error {
	return validate(newTarWalker(r), refs, out)
}

var validRefMediaTypes = []string{
	v1.MediaTypeImageManifest,
	v1.MediaTypeImageIndex,
}

func validate(w walker, refs []string, out *log.Logger) error {
	if err := layoutValidate(w); err != nil {
		return err
	}

	ds, err := listReferences(w)
	if err != nil {
		return err
	}
	if len(refs) == 0 && len(ds) == 0 {
		// TODO(runcom): ugly, we'll need a better way and library
		// to express log levels.
		// see https://github.com/opencontainers/image-spec/issues/288
		out.Print("WARNING: no descriptors found")
	}

	if len(refs) == 0 {
		for ref := range ds {
			refs = append(refs, ref)
		}
	}

	for _, ref := range refs {
		d, ok := ds[ref]
		if !ok {
			// TODO(runcom):
			// soften this error to a warning if the user didn't ask for any specific reference
			// with --ref but she's just validating the whole image.
			return fmt.Errorf("reference %s not found", ref)
		}

		if err = validateDescriptor(d, w, validRefMediaTypes); err != nil {
			return err
		}

		if d.MediaType == validRefMediaTypes[0] {
			m, err := findManifest(w, d)
			if err != nil {
				return err
			}

			if err := m.validate(w); err != nil {
				return err
			}
		}

		if d.MediaType == validRefMediaTypes[1] {
			index, err := findIndex(w, d)
			if err != nil {
				return err
			}

			if err := validateIndex(index, w); err != nil {
				return err
			}

			if len(index.Manifests) == 0 {
				fmt.Println("warning: no manifests found")
				return nil
			}

			for _, manifest := range index.Manifests {
				m, err := findManifest(w, &manifest)
				if err != nil {
					return err
				}

				if err := m.validate(w); err != nil {
					return err
				}
			}
		}

		if out != nil {
			out.Printf("reference %q: OK", ref)
		}
	}
	return nil
}

// UnpackLayout walks through the file tree given by src and, using the layers
// specified in the manifest pointed to by the given ref, unpacks all layers in
// the given destination directory or returns an error if the unpacking failed.
func UnpackLayout(src, dest, ref, platform string) error {
	return unpack(newPathWalker(src), dest, ref, platform)
}

// UnpackFile opens the file pointed by tarFileName and calls Unpack on it.
func UnpackFile(tarFileName, dest, ref, platform string) error {
	f, err := os.Open(tarFileName)
	if err != nil {
		return errors.Wrap(err, "unable to open file")
	}
	defer f.Close()

	return Unpack(f, dest, ref, platform)
}

// Unpack walks through the tar stream and, using the layers specified in
// the manifest pointed to by the given ref, unpacks all layers in the given
// destination directory or returns an error if the unpacking failed.
// The destination will be created if it does not exist.
func Unpack(r io.ReadSeeker, dest, refName, platform string) error {
	return unpack(newTarWalker(r), dest, refName, platform)
}

func unpack(w walker, dest, refName, platform string) error {
	if err := layoutValidate(w); err != nil {
		return err
	}

	ref, err := findDescriptor(w, refName)
	if err != nil {
		return err
	}

	if err = validateDescriptor(ref, w, validRefMediaTypes); err != nil {
		return err
	}

	if ref.MediaType == validRefMediaTypes[0] {
		m, err := findManifest(w, ref)
		if err != nil {
			return err
		}

		if err := m.validate(w); err != nil {
			return err
		}

		return m.unpack(w, dest)
	}

	if ref.MediaType == validRefMediaTypes[1] {
		index, err := findIndex(w, ref)
		if err != nil {
			return err
		}

		if err = validateIndex(index, w); err != nil {
			return err
		}

		manifests, err := filterManifest(w, index.Manifests, platform)
		if err != nil {
			return err
		}

		for _, m := range manifests {
			return m.unpack(w, dest)
		}
	}

	return nil
}

// CreateRuntimeBundleLayout walks through the file tree given by src and
// creates an OCI runtime bundle in the given destination dest
// or returns an error if the unpacking failed.
func CreateRuntimeBundleLayout(src, dest, ref, root, platform string) error {
	return createRuntimeBundle(newPathWalker(src), dest, ref, root, platform)
}

// CreateRuntimeBundleFile opens the file pointed by tarFile and calls
// CreateRuntimeBundle.
func CreateRuntimeBundleFile(tarFile, dest, ref, root, platform string) error {
	f, err := os.Open(tarFile)
	if err != nil {
		return errors.Wrap(err, "unable to open file")
	}
	defer f.Close()

	return createRuntimeBundle(newTarWalker(f), dest, ref, root, platform)
}

// CreateRuntimeBundle walks through the given tar stream and
// creates an OCI runtime bundle in the given destination dest
// or returns an error if the unpacking failed.
func CreateRuntimeBundle(r io.ReadSeeker, dest, ref, root, platform string) error {
	return createRuntimeBundle(newTarWalker(r), dest, ref, root, platform)
}

func createRuntimeBundle(w walker, dest, refName, rootfs, platform string) error {
	if err := layoutValidate(w); err != nil {
		return err
	}

	ref, err := findDescriptor(w, refName)
	if err != nil {
		return err
	}

	if err = validateDescriptor(ref, w, validRefMediaTypes); err != nil {
		return err
	}

	if ref.MediaType == validRefMediaTypes[0] {
		m, err := findManifest(w, ref)
		if err != nil {
			return err
		}

		if err := m.validate(w); err != nil {
			return err
		}

		return createBundle(w, m, dest, rootfs)
	}

	if ref.MediaType == validRefMediaTypes[1] {
		index, err := findIndex(w, ref)
		if err != nil {
			return err
		}

		if err = validateIndex(index, w); err != nil {
			return err
		}

		manifests, err := filterManifest(w, index.Manifests, platform)
		if err != nil {
			return err
		}

		for _, m := range manifests {
			return createBundle(w, m, dest, rootfs)
		}
	}

	return nil
}

func createBundle(w walker, m *manifest, dest, rootfs string) error {
	c, err := findConfig(w, &m.Config)
	if err != nil {
		return err
	}

	if _, err = os.Stat(dest); err != nil {
		if os.IsNotExist(err) {
			if err2 := os.MkdirAll(dest, 0755); err2 != nil {
				return err2
			}
		} else {
			return err
		}
	}

	if err = m.unpack(w, filepath.Join(dest, rootfs)); err != nil {
		return err
	}

	spec, err := c.runtimeSpec(rootfs)
	if err != nil {
		return err
	}

	f, err := os.Create(filepath.Join(dest, "config.json"))
	if err != nil {
		return err
	}
	defer f.Close()

	return json.NewEncoder(f).Encode(spec)
}

// filertManifest returns a filtered list of manifests
func filterManifest(w walker, Manifests []v1.Descriptor, platform string) ([]*manifest, error) {
	var manifests []*manifest

	argsParts := strings.Split(platform, ":")
	if len(argsParts) != 2 {
		return manifests, fmt.Errorf("platform must have os and arch when reftype is index")
	}

	if len(Manifests) == 0 {
		fmt.Println("warning: no manifests found")
		return manifests, nil
	}

	for _, manifest := range Manifests {
		m, err := findManifest(w, &manifest)
		if err != nil {
			return manifests, err
		}

		if err := m.validate(w); err != nil {
			return manifests, err
		}
		if strings.EqualFold(manifest.Platform.OS, argsParts[0]) && strings.EqualFold(manifest.Platform.Architecture, argsParts[1]) {
			manifests = append(manifests, m)
		}
	}

	if len(manifests) == 0 {
		return manifests, fmt.Errorf("There is no matching manifest")
	}

	return manifests, nil
}
<commit_msg>cleanup created bundle when creating failed<commit_after>// Copyright 2016 The Linux Foundation
//
// 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 image

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/pkg/errors"
)

// ValidateLayout walks through the given file tree and validates the manifest
// pointed to by the given refs or returns an error if the validation failed.
func ValidateLayout(src string, refs []string, out *log.Logger) error {
	return validate(newPathWalker(src), refs, out)
}

// ValidateFile opens the tar file given by the filename, then calls ValidateReader
func ValidateFile(tarFile string, refs []string, out *log.Logger) error {
	f, err := os.Open(tarFile)
	if err != nil {
		return errors.Wrap(err, "unable to open file")
	}
	defer f.Close()

	return Validate(f, refs, out)
}

// Validate walks through a tar stream and validates the manifest.
// * Check that all refs point to extant blobs
// * Checks that all referred blobs are valid
// * Checks that mime-types are correct
// returns error on validation failure
func Validate(r io.ReadSeeker, refs []string, out *log.Logger) error {
	return validate(newTarWalker(r), refs, out)
}

var validRefMediaTypes = []string{
	v1.MediaTypeImageManifest,
	v1.MediaTypeImageIndex,
}

func validate(w walker, refs []string, out *log.Logger) error {
	if err := layoutValidate(w); err != nil {
		return err
	}

	ds, err := listReferences(w)
	if err != nil {
		return err
	}
	if len(refs) == 0 && len(ds) == 0 {
		// TODO(runcom): ugly, we'll need a better way and library
		// to express log levels.
		// see https://github.com/opencontainers/image-spec/issues/288
		out.Print("WARNING: no descriptors found")
	}

	if len(refs) == 0 {
		for ref := range ds {
			refs = append(refs, ref)
		}
	}

	for _, ref := range refs {
		d, ok := ds[ref]
		if !ok {
			// TODO(runcom):
			// soften this error to a warning if the user didn't ask for any specific reference
			// with --ref but she's just validating the whole image.
			return fmt.Errorf("reference %s not found", ref)
		}

		if err = validateDescriptor(d, w, validRefMediaTypes); err != nil {
			return err
		}

		if d.MediaType == validRefMediaTypes[0] {
			m, err := findManifest(w, d)
			if err != nil {
				return err
			}

			if err := m.validate(w); err != nil {
				return err
			}
		}

		if d.MediaType == validRefMediaTypes[1] {
			index, err := findIndex(w, d)
			if err != nil {
				return err
			}

			if err := validateIndex(index, w); err != nil {
				return err
			}

			if len(index.Manifests) == 0 {
				fmt.Println("warning: no manifests found")
				return nil
			}

			for _, manifest := range index.Manifests {
				m, err := findManifest(w, &manifest)
				if err != nil {
					return err
				}

				if err := m.validate(w); err != nil {
					return err
				}
			}
		}

		if out != nil {
			out.Printf("reference %q: OK", ref)
		}
	}
	return nil
}

// UnpackLayout walks through the file tree given by src and, using the layers
// specified in the manifest pointed to by the given ref, unpacks all layers in
// the given destination directory or returns an error if the unpacking failed.
func UnpackLayout(src, dest, ref, platform string) error {
	return unpack(newPathWalker(src), dest, ref, platform)
}

// UnpackFile opens the file pointed by tarFileName and calls Unpack on it.
func UnpackFile(tarFileName, dest, ref, platform string) error {
	f, err := os.Open(tarFileName)
	if err != nil {
		return errors.Wrap(err, "unable to open file")
	}
	defer f.Close()

	return Unpack(f, dest, ref, platform)
}

// Unpack walks through the tar stream and, using the layers specified in
// the manifest pointed to by the given ref, unpacks all layers in the given
// destination directory or returns an error if the unpacking failed.
// The destination will be created if it does not exist.
func Unpack(r io.ReadSeeker, dest, refName, platform string) error {
	return unpack(newTarWalker(r), dest, refName, platform)
}

func unpack(w walker, dest, refName, platform string) error {
	if err := layoutValidate(w); err != nil {
		return err
	}

	ref, err := findDescriptor(w, refName)
	if err != nil {
		return err
	}

	if err = validateDescriptor(ref, w, validRefMediaTypes); err != nil {
		return err
	}

	if ref.MediaType == validRefMediaTypes[0] {
		m, err := findManifest(w, ref)
		if err != nil {
			return err
		}

		if err := m.validate(w); err != nil {
			return err
		}

		return m.unpack(w, dest)
	}

	if ref.MediaType == validRefMediaTypes[1] {
		index, err := findIndex(w, ref)
		if err != nil {
			return err
		}

		if err = validateIndex(index, w); err != nil {
			return err
		}

		manifests, err := filterManifest(w, index.Manifests, platform)
		if err != nil {
			return err
		}

		for _, m := range manifests {
			return m.unpack(w, dest)
		}
	}

	return nil
}

// CreateRuntimeBundleLayout walks through the file tree given by src and
// creates an OCI runtime bundle in the given destination dest
// or returns an error if the unpacking failed.
func CreateRuntimeBundleLayout(src, dest, ref, root, platform string) error {
	return createRuntimeBundle(newPathWalker(src), dest, ref, root, platform)
}

// CreateRuntimeBundleFile opens the file pointed by tarFile and calls
// CreateRuntimeBundle.
func CreateRuntimeBundleFile(tarFile, dest, ref, root, platform string) error {
	f, err := os.Open(tarFile)
	if err != nil {
		return errors.Wrap(err, "unable to open file")
	}
	defer f.Close()

	return createRuntimeBundle(newTarWalker(f), dest, ref, root, platform)
}

// CreateRuntimeBundle walks through the given tar stream and
// creates an OCI runtime bundle in the given destination dest
// or returns an error if the unpacking failed.
func CreateRuntimeBundle(r io.ReadSeeker, dest, ref, root, platform string) error {
	return createRuntimeBundle(newTarWalker(r), dest, ref, root, platform)
}

func createRuntimeBundle(w walker, dest, refName, rootfs, platform string) error {
	if err := layoutValidate(w); err != nil {
		return err
	}

	ref, err := findDescriptor(w, refName)
	if err != nil {
		return err
	}

	if err = validateDescriptor(ref, w, validRefMediaTypes); err != nil {
		return err
	}

	if ref.MediaType == validRefMediaTypes[0] {
		m, err := findManifest(w, ref)
		if err != nil {
			return err
		}

		if err := m.validate(w); err != nil {
			return err
		}

		return createBundle(w, m, dest, rootfs)
	}

	if ref.MediaType == validRefMediaTypes[1] {
		index, err := findIndex(w, ref)
		if err != nil {
			return err
		}

		if err = validateIndex(index, w); err != nil {
			return err
		}

		manifests, err := filterManifest(w, index.Manifests, platform)
		if err != nil {
			return err
		}

		for _, m := range manifests {
			return createBundle(w, m, dest, rootfs)
		}
	}

	return nil
}

func createBundle(w walker, m *manifest, dest, rootfs string) (retErr error) {
	c, err := findConfig(w, &m.Config)
	if err != nil {
		return err
	}

	if _, err = os.Stat(dest); err != nil {
		if os.IsNotExist(err) {
			if err2 := os.MkdirAll(dest, 0755); err2 != nil {
				return err2
			}
			defer func() {
				if retErr != nil {
					if err3 := os.RemoveAll(dest); err3 != nil {
						fmt.Printf("Failed to clean up %q: %s\n", dest, err3.Error())
					}
				}
			}()
		} else {
			return err
		}
	}

	if err = m.unpack(w, filepath.Join(dest, rootfs)); err != nil {
		return err
	}

	spec, err := c.runtimeSpec(rootfs)
	if err != nil {
		return err
	}

	f, err := os.Create(filepath.Join(dest, "config.json"))
	if err != nil {
		return err
	}
	defer f.Close()

	return json.NewEncoder(f).Encode(spec)
}

// filertManifest returns a filtered list of manifests
func filterManifest(w walker, Manifests []v1.Descriptor, platform string) ([]*manifest, error) {
	var manifests []*manifest

	argsParts := strings.Split(platform, ":")
	if len(argsParts) != 2 {
		return manifests, fmt.Errorf("platform must have os and arch when reftype is index")
	}

	if len(Manifests) == 0 {
		fmt.Println("warning: no manifests found")
		return manifests, nil
	}

	for _, manifest := range Manifests {
		m, err := findManifest(w, &manifest)
		if err != nil {
			return manifests, err
		}

		if err := m.validate(w); err != nil {
			return manifests, err
		}
		if strings.EqualFold(manifest.Platform.OS, argsParts[0]) && strings.EqualFold(manifest.Platform.Architecture, argsParts[1]) {
			manifests = append(manifests, m)
		}
	}

	if len(manifests) == 0 {
		return manifests, fmt.Errorf("There is no matching manifest")
	}

	return manifests, nil
}
<|endoftext|>


<commit_before>package functional

import (
	"strings"
	"testing"

	"github.com/coreos/fleet/functional/platform"
)

// TestUnitRunnable is the simplest test possible, deplying a single-node
// cluster and ensuring a unit can enter an 'active' state
func TestUnitRunnable(t *testing.T) {
	cluster, err := platform.NewNspawnCluster("smoke")
	if err != nil {
		t.Fatal(err)
	}
	defer cluster.Destroy()

	if err := platform.CreateNClusterMembers(cluster, 1, platform.MachineConfig{}); err != nil {
		t.Fatal(err)
	}
	_, err = cluster.WaitForNMachines(1)
	if err != nil {
		t.Fatal(err)
	}

	if stdout, stderr, err := cluster.Fleetctl("start", "fixtures/units/hello.service"); err != nil {
		t.Fatalf("Unable to start fleet unit: \nstdout: %s\nstderr: %s\nerr: %v", stdout, stderr, err)
	}

	units, err := cluster.WaitForNActiveUnits(1)
	if err != nil {
		t.Fatal(err)
	}
	_, found := units["hello.service"]
	if len(units) != 1 || !found {
		t.Fatalf("Expected hello.service to be sole active unit, got %v", units)
	}
}

func TestUnitSubmit(t *testing.T) {
	cluster, err := platform.NewNspawnCluster("smoke")
	if err != nil {
		t.Fatal(err)
	}
	defer cluster.Destroy()

	if err := platform.CreateNClusterMembers(cluster, 1, platform.MachineConfig{}); err != nil {
		t.Fatal(err)
	}
	_, err = cluster.WaitForNMachines(1)
	if err != nil {
		t.Fatal(err)
	}

	// submit a unit and assert it shows up
	if _, _, err := cluster.Fleetctl("submit", "fixtures/units/hello.service"); err != nil {
		t.Fatalf("Unable to submit fleet unit: %v", err)
	}
	stdout, _, err := cluster.Fleetctl("list-units", "--no-legend")
	if err != nil {
		t.Fatalf("Failed to run list-units: %v", err)
	}
	units := strings.Split(strings.TrimSpace(stdout), "\n")
	if len(units) != 1 {
		t.Fatalf("Did not find 1 unit in cluster: \n%s", stdout)
	}

	// submitting the same unit should fail
	if _, _, err = cluster.Fleetctl("submit", "fixtures/units/hello.service"); err == nil {
		t.Fatalf("Expected failure when double-submitting unit, got success.")
	}

	// destroy the unit and ensure it disappears from the unit list
	if _, _, err := cluster.Fleetctl("destroy", "fixtures/units/hello.service"); err != nil {
		t.Fatalf("Failed to destroy unit: %v", err)
	}
	stdout, _, err = cluster.Fleetctl("list-units", "--no-legend")
	if err != nil {
		t.Fatalf("Failed to run list-units: %v", err)
	}
	if strings.TrimSpace(stdout) != "" {
		t.Fatalf("Did not find 0 units in cluster: \n%s", stdout)
	}

	// submitting the unit after destruction should succeed
	if _, _, err := cluster.Fleetctl("submit", "fixtures/units/hello.service"); err != nil {
		t.Fatalf("Unable to submit fleet unit: %v", err)
	}
	stdout, _, err = cluster.Fleetctl("list-units", "--no-legend")
	if err != nil {
		t.Fatalf("Failed to run list-units: %v", err)
	}
	units = strings.Split(strings.TrimSpace(stdout), "\n")
	if len(units) != 1 {
		t.Fatalf("Did not find 1 unit in cluster: \n%s", stdout)
	}
}

func TestUnitRestart(t *testing.T) {
	cluster, err := platform.NewNspawnCluster("smoke")
	if err != nil {
		t.Fatal(err)
	}
	defer cluster.Destroy()

	if err := platform.CreateNClusterMembers(cluster, 1, platform.MachineConfig{}); err != nil {
		t.Fatal(err)
	}
	_, err = cluster.WaitForNMachines(1)
	if err != nil {
		t.Fatal(err)
	}

	if stdout, stderr, err := cluster.Fleetctl("start", "fixtures/units/hello.service"); err != nil {
		t.Fatalf("Unable to start fleet unit: \nstdout: %s\nstderr: %s\nerr: %v", stdout, stderr, err)
	}

	units, err := cluster.WaitForNActiveUnits(1)
	if err != nil {
		t.Fatal(err)
	}
	_, found := units["hello.service"]
	if len(units) != 1 || !found {
		t.Fatalf("Expected hello.service to be sole active unit, got %v", units)
	}

	if _, _, err := cluster.Fleetctl("stop", "hello.service"); err != nil {
		t.Fatal(err)
	}
	units, err = cluster.WaitForNActiveUnits(0)
	if err != nil {
		t.Fatal(err)
	}
	if len(units) != 0 {
		t.Fatalf("Zero units should be running, found %v", units)
	}

	if stdout, stderr, err := cluster.Fleetctl("start", "hello.service"); err != nil {
		t.Fatalf("Unable to start fleet unit: \nstdout: %s\nstderr: %s\nerr: %v", stdout, stderr, err)
	}
	units, err = cluster.WaitForNActiveUnits(1)
	if err != nil {
		t.Fatal(err)
	}
	_, found = units["hello.service"]
	if len(units) != 1 || !found {
		t.Fatalf("Expected hello.service to be sole active unit, got %v", units)
	}

}

func TestUnitSSHActions(t *testing.T) {
	cluster, err := platform.NewNspawnCluster("smoke")
	if err != nil {
		t.Fatal(err)
	}
	defer cluster.Destroy()

	if err := platform.CreateNClusterMembers(cluster, 1, platform.MachineConfig{}); err != nil {
		t.Fatal(err)
	}
	_, err = cluster.WaitForNMachines(1)
	if err != nil {
		t.Fatal(err)
	}

	if _, _, err := cluster.Fleetctl("start", "--no-block", "fixtures/units/hello.service"); err != nil {
		t.Fatalf("Unable to start fleet unit: %v", err)
	}

	units, err := cluster.WaitForNActiveUnits(1)
	if err != nil {
		t.Fatal(err)
	}

	_, found := units["hello.service"]
	if len(units) != 1 || !found {
		t.Fatalf("Expected hello.service to be sole active unit, got %v", units)
	}

	stdout, _, err := cluster.Fleetctl("--strict-host-key-checking=false", "ssh", "hello.service", "echo", "foo")
	if err != nil {
		t.Errorf("Failure occurred while calling fleetctl ssh: %v", err)
	}

	if !strings.Contains(stdout, "foo") {
		t.Errorf("Could not find expected string in command output:\n%s", stdout)
	}

	stdout, _, err = cluster.Fleetctl("--strict-host-key-checking=false", "status", "hello.service")
	if err != nil {
		t.Errorf("Failure occurred while calling fleetctl status: %v", err)
	}

	if !strings.Contains(stdout, "Active: active") {
		t.Errorf("Could not find expected string in status output:\n%s", stdout)
	}

	stdout, _, err = cluster.Fleetctl("--strict-host-key-checking=false", "journal", "hello.service")
	if err != nil {
		t.Errorf("Failure occurred while calling fleetctl journal: %v", err)
	}

	if !strings.Contains(stdout, "Hello, World!") {
		t.Errorf("Could not find expected string in journal output:\n%s", stdout)
	}
}
<commit_msg>fix(functional): double-submit units should not fail<commit_after>package functional

import (
	"strings"
	"testing"

	"github.com/coreos/fleet/functional/platform"
)

// TestUnitRunnable is the simplest test possible, deplying a single-node
// cluster and ensuring a unit can enter an 'active' state
func TestUnitRunnable(t *testing.T) {
	cluster, err := platform.NewNspawnCluster("smoke")
	if err != nil {
		t.Fatal(err)
	}
	defer cluster.Destroy()

	if err := platform.CreateNClusterMembers(cluster, 1, platform.MachineConfig{}); err != nil {
		t.Fatal(err)
	}
	_, err = cluster.WaitForNMachines(1)
	if err != nil {
		t.Fatal(err)
	}

	if stdout, stderr, err := cluster.Fleetctl("start", "fixtures/units/hello.service"); err != nil {
		t.Fatalf("Unable to start fleet unit: \nstdout: %s\nstderr: %s\nerr: %v", stdout, stderr, err)
	}

	units, err := cluster.WaitForNActiveUnits(1)
	if err != nil {
		t.Fatal(err)
	}
	_, found := units["hello.service"]
	if len(units) != 1 || !found {
		t.Fatalf("Expected hello.service to be sole active unit, got %v", units)
	}
}

func TestUnitSubmit(t *testing.T) {
	cluster, err := platform.NewNspawnCluster("smoke")
	if err != nil {
		t.Fatal(err)
	}
	defer cluster.Destroy()

	if err := platform.CreateNClusterMembers(cluster, 1, platform.MachineConfig{}); err != nil {
		t.Fatal(err)
	}
	_, err = cluster.WaitForNMachines(1)
	if err != nil {
		t.Fatal(err)
	}

	// submit a unit and assert it shows up
	if _, _, err := cluster.Fleetctl("submit", "fixtures/units/hello.service"); err != nil {
		t.Fatalf("Unable to submit fleet unit: %v", err)
	}
	stdout, _, err := cluster.Fleetctl("list-units", "--no-legend")
	if err != nil {
		t.Fatalf("Failed to run list-units: %v", err)
	}
	units := strings.Split(strings.TrimSpace(stdout), "\n")
	if len(units) != 1 {
		t.Fatalf("Did not find 1 unit in cluster: \n%s", stdout)
	}

	// submitting the same unit should not fail
	if _, _, err = cluster.Fleetctl("submit", "fixtures/units/hello.service"); err != nil {
		t.Fatalf("Expected no failure when double-submitting unit, got this: %v", err)
	}

	// destroy the unit and ensure it disappears from the unit list
	if _, _, err := cluster.Fleetctl("destroy", "fixtures/units/hello.service"); err != nil {
		t.Fatalf("Failed to destroy unit: %v", err)
	}
	stdout, _, err = cluster.Fleetctl("list-units", "--no-legend")
	if err != nil {
		t.Fatalf("Failed to run list-units: %v", err)
	}
	if strings.TrimSpace(stdout) != "" {
		t.Fatalf("Did not find 0 units in cluster: \n%s", stdout)
	}

	// submitting the unit after destruction should succeed
	if _, _, err := cluster.Fleetctl("submit", "fixtures/units/hello.service"); err != nil {
		t.Fatalf("Unable to submit fleet unit: %v", err)
	}
	stdout, _, err = cluster.Fleetctl("list-units", "--no-legend")
	if err != nil {
		t.Fatalf("Failed to run list-units: %v", err)
	}
	units = strings.Split(strings.TrimSpace(stdout), "\n")
	if len(units) != 1 {
		t.Fatalf("Did not find 1 unit in cluster: \n%s", stdout)
	}
}

func TestUnitRestart(t *testing.T) {
	cluster, err := platform.NewNspawnCluster("smoke")
	if err != nil {
		t.Fatal(err)
	}
	defer cluster.Destroy()

	if err := platform.CreateNClusterMembers(cluster, 1, platform.MachineConfig{}); err != nil {
		t.Fatal(err)
	}
	_, err = cluster.WaitForNMachines(1)
	if err != nil {
		t.Fatal(err)
	}

	if stdout, stderr, err := cluster.Fleetctl("start", "fixtures/units/hello.service"); err != nil {
		t.Fatalf("Unable to start fleet unit: \nstdout: %s\nstderr: %s\nerr: %v", stdout, stderr, err)
	}

	units, err := cluster.WaitForNActiveUnits(1)
	if err != nil {
		t.Fatal(err)
	}
	_, found := units["hello.service"]
	if len(units) != 1 || !found {
		t.Fatalf("Expected hello.service to be sole active unit, got %v", units)
	}

	if _, _, err := cluster.Fleetctl("stop", "hello.service"); err != nil {
		t.Fatal(err)
	}
	units, err = cluster.WaitForNActiveUnits(0)
	if err != nil {
		t.Fatal(err)
	}
	if len(units) != 0 {
		t.Fatalf("Zero units should be running, found %v", units)
	}

	if stdout, stderr, err := cluster.Fleetctl("start", "hello.service"); err != nil {
		t.Fatalf("Unable to start fleet unit: \nstdout: %s\nstderr: %s\nerr: %v", stdout, stderr, err)
	}
	units, err = cluster.WaitForNActiveUnits(1)
	if err != nil {
		t.Fatal(err)
	}
	_, found = units["hello.service"]
	if len(units) != 1 || !found {
		t.Fatalf("Expected hello.service to be sole active unit, got %v", units)
	}

}

func TestUnitSSHActions(t *testing.T) {
	cluster, err := platform.NewNspawnCluster("smoke")
	if err != nil {
		t.Fatal(err)
	}
	defer cluster.Destroy()

	if err := platform.CreateNClusterMembers(cluster, 1, platform.MachineConfig{}); err != nil {
		t.Fatal(err)
	}
	_, err = cluster.WaitForNMachines(1)
	if err != nil {
		t.Fatal(err)
	}

	if _, _, err := cluster.Fleetctl("start", "--no-block", "fixtures/units/hello.service"); err != nil {
		t.Fatalf("Unable to start fleet unit: %v", err)
	}

	units, err := cluster.WaitForNActiveUnits(1)
	if err != nil {
		t.Fatal(err)
	}

	_, found := units["hello.service"]
	if len(units) != 1 || !found {
		t.Fatalf("Expected hello.service to be sole active unit, got %v", units)
	}

	stdout, _, err := cluster.Fleetctl("--strict-host-key-checking=false", "ssh", "hello.service", "echo", "foo")
	if err != nil {
		t.Errorf("Failure occurred while calling fleetctl ssh: %v", err)
	}

	if !strings.Contains(stdout, "foo") {
		t.Errorf("Could not find expected string in command output:\n%s", stdout)
	}

	stdout, _, err = cluster.Fleetctl("--strict-host-key-checking=false", "status", "hello.service")
	if err != nil {
		t.Errorf("Failure occurred while calling fleetctl status: %v", err)
	}

	if !strings.Contains(stdout, "Active: active") {
		t.Errorf("Could not find expected string in status output:\n%s", stdout)
	}

	stdout, _, err = cluster.Fleetctl("--strict-host-key-checking=false", "journal", "hello.service")
	if err != nil {
		t.Errorf("Failure occurred while calling fleetctl journal: %v", err)
	}

	if !strings.Contains(stdout, "Hello, World!") {
		t.Errorf("Could not find expected string in journal output:\n%s", stdout)
	}
}
<|endoftext|>