<commit_before>// Copyright (c) 2019 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package http

import (
	"context"
	"net"
	"net/http"
	"strings"
	"time"

	"github.com/opentracing/opentracing-go"
	"go.uber.org/yarpc/api/transport"
	"go.uber.org/yarpc/internal/introspection"
	intnet "go.uber.org/yarpc/internal/net"
	"go.uber.org/yarpc/pkg/lifecycle"
	"go.uber.org/yarpc/yarpcerrors"
	"go.uber.org/zap"
)

const defaultShutdownTimeout = 5 * time.Second

// InboundOption customizes the behavior of an HTTP Inbound constructed with
// NewInbound.
type InboundOption func(*Inbound)

func (InboundOption) httpOption() {}

// Mux specifies that the HTTP server should make the YARPC endpoint available
// under the given pattern on the given ServeMux. By default, the YARPC
// service is made available on all paths of the HTTP server. By specifying a
// ServeMux, users can narrow the endpoints under which the YARPC service is
// available and offer their own non-YARPC endpoints.
func Mux(pattern string, mux *http.ServeMux) InboundOption {
	return func(i *Inbound) {
		i.mux = mux
		i.muxPattern = pattern
	}
}

// Interceptor specifies a function which can wrap the YARPC handler. If
// provided, this function will be called with an http.Handler which will
// route requests through YARPC. The http.Handler returned by this function
// may delegate requests to the provided YARPC handler to route them through
// YARPC.
func Interceptor(interceptor func(yarpcHandler http.Handler) http.Handler) InboundOption {
	return func(i *Inbound) {
		i.interceptor = interceptor
	}
}

// GrabHeaders specifies additional headers that are not prefixed with
// ApplicationHeaderPrefix that should be propagated to the caller.
//
// All headers given must begin with x- or X- or the Inbound that the
// returned option is passed to will return an error when Start is called.
//
// Headers specified with GrabHeaders are case-insensitive.
// https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
func GrabHeaders(headers ...string) InboundOption {
	return func(i *Inbound) {
		for _, header := range headers {
			i.grabHeaders[strings.ToLower(header)] = struct{}{}
		}
	}
}

// ShutdownTimeout specifies the maximum duration the inbound should wait for
// closing idle connections, and pending calls to complete.
//
// Set to 0 to wait for a complete drain.
//
// Defaults to 5 seconds.
func ShutdownTimeout(timeout time.Duration) InboundOption {
	return func(i *Inbound) {
		i.shutdownTimeout = timeout
	}
}

// NewInbound builds a new HTTP inbound that listens on the given address and
// sharing this transport.
func (t *Transport) NewInbound(addr string, opts ...InboundOption) *Inbound {
	i := &Inbound{
		once:              lifecycle.NewOnce(),
		addr:              addr,
		shutdownTimeout:   defaultShutdownTimeout,
		tracer:            t.tracer,
		logger:            t.logger,
		transport:         t,
		grabHeaders:       make(map[string]struct{}),
		bothResponseError: true,
	}
	for _, opt := range opts {
		opt(i)
	}
	return i
}

// Inbound receives YARPC requests using an HTTP server. It may be constructed
// using the NewInbound method on the Transport.
type Inbound struct {
	addr            string
	mux             *http.ServeMux
	muxPattern      string
	server          *intnet.HTTPServer
	shutdownTimeout time.Duration
	router          transport.Router
	tracer          opentracing.Tracer
	logger          *zap.Logger
	transport       *Transport
	grabHeaders     map[string]struct{}
	interceptor     func(http.Handler) http.Handler

	once *lifecycle.Once

	// should only be false in testing
	bothResponseError bool
}

// Tracer configures a tracer on this inbound.
func (i *Inbound) Tracer(tracer opentracing.Tracer) *Inbound {
	i.tracer = tracer
	return i
}

// SetRouter configures a router to handle incoming requests.
// This satisfies the transport.Inbound interface, and would be called
// by a dispatcher when it starts.
func (i *Inbound) SetRouter(router transport.Router) {
	i.router = router
}

// Transports returns the inbound's HTTP transport.
func (i *Inbound) Transports() []transport.Transport {
	return []transport.Transport{i.transport}
}

// Start starts the inbound with a given service detail, opening a listening
// socket.
func (i *Inbound) Start() error {
	return i.once.Start(i.start)
}

func (i *Inbound) start() error {
	if i.router == nil {
		return yarpcerrors.Newf(yarpcerrors.CodeInternal, "no router configured for transport inbound")
	}
	for header := range i.grabHeaders {
		if !strings.HasPrefix(header, "x-") {
			return yarpcerrors.Newf(yarpcerrors.CodeInvalidArgument, "header %s does not begin with 'x-'", header)
		}
	}

	var httpHandler http.Handler = handler{
		router:            i.router,
		tracer:            i.tracer,
		grabHeaders:       i.grabHeaders,
		bothResponseError: i.bothResponseError,
		logger:            i.logger,
	}
	if i.interceptor != nil {
		httpHandler = i.interceptor(httpHandler)
	}
	if i.mux != nil {
		i.mux.Handle(i.muxPattern, httpHandler)
		httpHandler = i.mux
	}

	i.server = intnet.NewHTTPServer(&http.Server{
		Addr:    i.addr,
		Handler: httpHandler,
	})
	if err := i.server.ListenAndServe(); err != nil {
		return err
	}

	i.addr = i.server.Listener().Addr().String() // in case it changed
	i.logger.Info("started HTTP inbound", zap.String("address", i.addr))
	if len(i.router.Procedures()) == 0 {
		i.logger.Warn("no procedures specified for HTTP inbound")
	}
	return nil
}

// Stop the inbound using Shutdown.
func (i *Inbound) Stop() error {
	ctx, cancel := context.WithTimeout(context.Background(), i.shutdownTimeout)
	defer cancel()

	return i.shutdown(ctx)
}

// shutdown the inbound, closing the listening socket, closing idle
// connections, and waiting for all pending calls to complete.
func (i *Inbound) shutdown(ctx context.Context) error {
	return i.once.Stop(func() error {
		if i.server == nil {
			return nil
		}

		return i.server.Shutdown(ctx)
	})
}

// IsRunning returns whether the inbound is currently running
func (i *Inbound) IsRunning() bool {
	return i.once.IsRunning()
}

// Addr returns the address on which the server is listening. Returns nil if
// Start has not been called yet.
func (i *Inbound) Addr() net.Addr {
	if i.server == nil {
		return nil
	}

	listener := i.server.Listener()
	if listener == nil {
		return nil
	}

	return listener.Addr()
}

// Introspect returns the state of the inbound for introspection purposes.
func (i *Inbound) Introspect() introspection.InboundStatus {
	state := "Stopped"
	if i.IsRunning() {
		state = "Started"
	}
	var addrString string
	if addr := i.Addr(); addr != nil {
		addrString = addr.String()
	}
	return introspection.InboundStatus{
		Transport: "http",
		Endpoint:  addrString,
		State:     state,
	}
}
<commit_msg>Increase HTTP default timeout to > 5 seconds (#1850)<commit_after>// Copyright (c) 2019 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package http

import (
	"context"
	"net"
	"net/http"
	"strings"
	"time"

	"github.com/opentracing/opentracing-go"
	"go.uber.org/yarpc/api/transport"
	"go.uber.org/yarpc/internal/introspection"
	intnet "go.uber.org/yarpc/internal/net"
	"go.uber.org/yarpc/pkg/lifecycle"
	"go.uber.org/yarpc/yarpcerrors"
	"go.uber.org/zap"
)

// We want a value that's around 5 seconds, but slightly higher than how
// long a successful HTTP shutdown can take.
// There's a specific path in the HTTP shutdown path that can take 5 seconds:
// https://golang.org/src/net/http/server.go?s=83923:83977#L2710
// This avoids timeouts in shutdown caused by new idle connections, without
// making the timeout too large.
const defaultShutdownTimeout = 6 * time.Second

// InboundOption customizes the behavior of an HTTP Inbound constructed with
// NewInbound.
type InboundOption func(*Inbound)

func (InboundOption) httpOption() {}

// Mux specifies that the HTTP server should make the YARPC endpoint available
// under the given pattern on the given ServeMux. By default, the YARPC
// service is made available on all paths of the HTTP server. By specifying a
// ServeMux, users can narrow the endpoints under which the YARPC service is
// available and offer their own non-YARPC endpoints.
func Mux(pattern string, mux *http.ServeMux) InboundOption {
	return func(i *Inbound) {
		i.mux = mux
		i.muxPattern = pattern
	}
}

// Interceptor specifies a function which can wrap the YARPC handler. If
// provided, this function will be called with an http.Handler which will
// route requests through YARPC. The http.Handler returned by this function
// may delegate requests to the provided YARPC handler to route them through
// YARPC.
func Interceptor(interceptor func(yarpcHandler http.Handler) http.Handler) InboundOption {
	return func(i *Inbound) {
		i.interceptor = interceptor
	}
}

// GrabHeaders specifies additional headers that are not prefixed with
// ApplicationHeaderPrefix that should be propagated to the caller.
//
// All headers given must begin with x- or X- or the Inbound that the
// returned option is passed to will return an error when Start is called.
//
// Headers specified with GrabHeaders are case-insensitive.
// https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
func GrabHeaders(headers ...string) InboundOption {
	return func(i *Inbound) {
		for _, header := range headers {
			i.grabHeaders[strings.ToLower(header)] = struct{}{}
		}
	}
}

// ShutdownTimeout specifies the maximum duration the inbound should wait for
// closing idle connections, and pending calls to complete.
//
// Set to 0 to wait for a complete drain.
//
// Defaults to 5 seconds.
func ShutdownTimeout(timeout time.Duration) InboundOption {
	return func(i *Inbound) {
		i.shutdownTimeout = timeout
	}
}

// NewInbound builds a new HTTP inbound that listens on the given address and
// sharing this transport.
func (t *Transport) NewInbound(addr string, opts ...InboundOption) *Inbound {
	i := &Inbound{
		once:              lifecycle.NewOnce(),
		addr:              addr,
		shutdownTimeout:   defaultShutdownTimeout,
		tracer:            t.tracer,
		logger:            t.logger,
		transport:         t,
		grabHeaders:       make(map[string]struct{}),
		bothResponseError: true,
	}
	for _, opt := range opts {
		opt(i)
	}
	return i
}

// Inbound receives YARPC requests using an HTTP server. It may be constructed
// using the NewInbound method on the Transport.
type Inbound struct {
	addr            string
	mux             *http.ServeMux
	muxPattern      string
	server          *intnet.HTTPServer
	shutdownTimeout time.Duration
	router          transport.Router
	tracer          opentracing.Tracer
	logger          *zap.Logger
	transport       *Transport
	grabHeaders     map[string]struct{}
	interceptor     func(http.Handler) http.Handler

	once *lifecycle.Once

	// should only be false in testing
	bothResponseError bool
}

// Tracer configures a tracer on this inbound.
func (i *Inbound) Tracer(tracer opentracing.Tracer) *Inbound {
	i.tracer = tracer
	return i
}

// SetRouter configures a router to handle incoming requests.
// This satisfies the transport.Inbound interface, and would be called
// by a dispatcher when it starts.
func (i *Inbound) SetRouter(router transport.Router) {
	i.router = router
}

// Transports returns the inbound's HTTP transport.
func (i *Inbound) Transports() []transport.Transport {
	return []transport.Transport{i.transport}
}

// Start starts the inbound with a given service detail, opening a listening
// socket.
func (i *Inbound) Start() error {
	return i.once.Start(i.start)
}

func (i *Inbound) start() error {
	if i.router == nil {
		return yarpcerrors.Newf(yarpcerrors.CodeInternal, "no router configured for transport inbound")
	}
	for header := range i.grabHeaders {
		if !strings.HasPrefix(header, "x-") {
			return yarpcerrors.Newf(yarpcerrors.CodeInvalidArgument, "header %s does not begin with 'x-'", header)
		}
	}

	var httpHandler http.Handler = handler{
		router:            i.router,
		tracer:            i.tracer,
		grabHeaders:       i.grabHeaders,
		bothResponseError: i.bothResponseError,
		logger:            i.logger,
	}
	if i.interceptor != nil {
		httpHandler = i.interceptor(httpHandler)
	}
	if i.mux != nil {
		i.mux.Handle(i.muxPattern, httpHandler)
		httpHandler = i.mux
	}

	i.server = intnet.NewHTTPServer(&http.Server{
		Addr:    i.addr,
		Handler: httpHandler,
	})
	if err := i.server.ListenAndServe(); err != nil {
		return err
	}

	i.addr = i.server.Listener().Addr().String() // in case it changed
	i.logger.Info("started HTTP inbound", zap.String("address", i.addr))
	if len(i.router.Procedures()) == 0 {
		i.logger.Warn("no procedures specified for HTTP inbound")
	}
	return nil
}

// Stop the inbound using Shutdown.
func (i *Inbound) Stop() error {
	ctx, cancel := context.WithTimeout(context.Background(), i.shutdownTimeout)
	defer cancel()

	return i.shutdown(ctx)
}

// shutdown the inbound, closing the listening socket, closing idle
// connections, and waiting for all pending calls to complete.
func (i *Inbound) shutdown(ctx context.Context) error {
	return i.once.Stop(func() error {
		if i.server == nil {
			return nil
		}

		return i.server.Shutdown(ctx)
	})
}

// IsRunning returns whether the inbound is currently running
func (i *Inbound) IsRunning() bool {
	return i.once.IsRunning()
}

// Addr returns the address on which the server is listening. Returns nil if
// Start has not been called yet.
func (i *Inbound) Addr() net.Addr {
	if i.server == nil {
		return nil
	}

	listener := i.server.Listener()
	if listener == nil {
		return nil
	}

	return listener.Addr()
}

// Introspect returns the state of the inbound for introspection purposes.
func (i *Inbound) Introspect() introspection.InboundStatus {
	state := "Stopped"
	if i.IsRunning() {
		state = "Started"
	}
	var addrString string
	if addr := i.Addr(); addr != nil {
		addrString = addr.String()
	}
	return introspection.InboundStatus{
		Transport: "http",
		Endpoint:  addrString,
		State:     state,
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The Kubernetes 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.
*/

/*
Contains functions that manage the reading and writing of files related to package summarize.
This includes reading and interpreting JSON files as actionable data, memoizing function
results to JSON, and outputting results once the summarization process is complete.
*/

package summarize

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"sort"
	"strconv"
	"strings"
)

// loadFailures loads a builds file and one or more test failure files. It maps build paths to builds
// and groups test failures by test name.
func loadFailures(buildsFilepath string, testsFilepaths []string) (map[string]build, map[string][]failure, error) {
	const memoMessage string = "loading failed tests"

	builds := make(map[string]build)
	tests := make(map[string][]failure)

	// Try to retrieve memoized results first to avoid another computation
	if getMemoizedResults("memo_load_failures-builds.json", "", &builds) &&
		getMemoizedResults("memo_load_failures-tests.json", "", &tests) {
		logInfo("Done (cached) " + memoMessage)
		return builds, tests, nil
	}

	builds, err := loadBuilds(buildsFilepath)
	if err != nil {
		return nil, nil, fmt.Errorf("Could not retrieve builds: %s", err)
	}

	tests, err = loadTests(testsFilepaths)
	if err != nil {
		return nil, nil, fmt.Errorf("Could not retrieve tests: %s", err)
	}

	memoizeResults("memo_load_failures-builds.json", "", builds)
	memoizeResults("memo_load_failures-tests.json", "", tests)
	logInfo("Done " + memoMessage)
	return builds, tests, nil
}

// loadPrevious loads a previous output and returns the 'clustered' field.
func loadPrevious(filepath string) ([]jsonCluster, error) {
	var previous jsonOutput

	err := getJSON(filepath, &previous)
	if err != nil {
		return nil, fmt.Errorf("Could not get previous results JSON: %s", err)
	}

	return previous.Clustered, nil
}

// loadOwners loads an owners JSON file and returns it.
func loadOwners(filepath string) (map[string][]string, error) {
	var owners map[string][]string

	err := getJSON(filepath, &owners)
	if err != nil {
		return nil, fmt.Errorf("Could not get owners JSON: %s", err)
	}

	return owners, nil
}

// writeResults outputs the results of clustering to a file.
func writeResults(filepath string, data jsonOutput) error {
	err := writeJSON(filepath, data)
	if err != nil {
		return fmt.Errorf("Could not write results to disk: %s", err)
	}
	return nil
}

type renderedSliceOutput struct {
	Clustered []jsonCluster `json:"clustered"`
	Builds    columns       `json:"builds"`
}

// writeRenderedSlice outputs the results of a call to renderSlice() to a file.
func writeRenderedSlice(filepath string, clustered []jsonCluster, builds columns) error {
	output := renderedSliceOutput{
		clustered,
		builds,
	}

	err := writeJSON(filepath, output)
	if err != nil {
		return fmt.Errorf("Could not write subset to disk: %s", err)
	}
	return nil
}

/*
getMemoizedResults attempts to retrieve memoized function results from the given filepath. If it
succeeds, it places the results into v and returns true. Otherwise, it returns false. Internally,
it calls encoding/json's Unmarshal using v as the second argument. Therefore, v mut be a non-nil
pointer.

message is a message that gets printed on success, appended to "Done (cached) ". If it is the empty
string, no message is printed.
*/
func getMemoizedResults(filepath string, message string, v interface{}) (ok bool) {
	err := getJSON(filepath, v)
	if err == nil {
		if message != "" {
			logInfo("Done (cached) " + message)
		}
		return true
	}
	return false
}

/*
memoizeResults saves the results stored in v to a JSON file. v should be a value, not a pointer. It
prints a warning if the results could not be memoized.

message is a message that gets printed on success, appended to "Done ". If it is the empty
string, no message is printed.
*/
func memoizeResults(filepath string, message string, v interface{}) {
	err := writeJSON(filepath, v)
	if err == nil && message != "" {
		logInfo("Done " + message)
		return
	}

	logWarning("Could not memoize results to '%s': %s", filepath, err)
}

/* Functions below this comment are only used within this file as of this commit. */

// jsonBuild represents a build as reported by the JSON. All values are strings.
// This should not be instantiated directly, but rather via the encoding/json package's
// Unmarshal method. This is an intermediary state for the data until it can be put into
// a build object.
type jsonBuild struct {
	Path        string `json:"path"`
	Started     string `json:"started"`
	Elapsed     string `json:"elapsed"`
	TestsRun    string `json:"tests_run"`
	TestsFailed string `json:"tests_failed"`
	Result      string `json:"result"`
	Executor    string `json:"executor"`
	Job         string `json:"job"`
	Number      string `json:"number"`
	PR          string `json:"pr"`
	Key         string `json:"key"` // Often nonexistent
}

// asBuild is a factory function that creates a build object from a jsonBuild object, appropriately
// handling all type conversions.
func (jb *jsonBuild) asBuild() (build, error) {
	// The build object that will be returned, initialized with the values that
	// don't need conversion.
	b := build{
		Path:     jb.Path,
		Result:   jb.Result,
		Executor: jb.Executor,
		Job:      jb.Job,
		PR:       jb.PR,
		Key:      jb.Key,
	}

	// To avoid assignment issues
	var err error

	// started
	if jb.Started != "" {
		b.Started, err = strconv.Atoi(jb.Started)
		if err != nil {
			return build{}, fmt.Errorf("Error converting JSON string '%s' to int for build field 'started': %s", jb.Started, err)
		}
	}

	// elapsed
	if jb.Elapsed != "" {
		tempElapsed, err := strconv.ParseFloat(jb.Elapsed, 32)
		if err != nil {
			return build{}, fmt.Errorf("Error converting JSON string '%s' to float32 for build field 'elapsed': %s", jb.Elapsed, err)
		}
		b.Elapsed = int(tempElapsed)
	}

	// testsRun
	if jb.TestsRun != "" {
		b.TestsRun, err = strconv.Atoi(jb.TestsRun)
		if err != nil {
			return build{}, fmt.Errorf("Error converting JSON string '%s' to int for build field 'testsRun': %s", jb.TestsRun, err)
		}
	}

	// testsFailed
	if jb.TestsFailed != "" {
		b.TestsFailed, err = strconv.Atoi(jb.TestsFailed)
		if err != nil {
			return build{}, fmt.Errorf("Error converting JSON string '%s' to int for build field 'testsFailed': %s", jb.TestsFailed, err)
		}
	}

	// number
	if jb.Number != "" {
		b.Number, err = strconv.Atoi(jb.Number)
		if err != nil {
			return build{}, fmt.Errorf("Error converting JSON string '%s' to int for build field 'number': %s", jb.Number, err)
		}
	}

	return b, nil
}

// loadBuilds parses a JSON file containing build information and returns a map from build paths
// to build objects.
func loadBuilds(filepath string) (map[string]build, error) {
	// The map
	builds := make(map[string]build)

	// jsonBuilds temporarily stores the builds as they are retrieved from the JSON file
	// until they can be converted to build objects
	jsonBuilds := make([]jsonBuild, 0)

	err := getJSON(filepath, &jsonBuilds)
	if err != nil {
		return nil, fmt.Errorf("Could not get builds JSON: %s", err)
	}

	// Convert the build information to internal build objects and store them in the builds map
	for _, jBuild := range jsonBuilds {
		// Skip builds without a start time or build number
		if jBuild.Started == "" || jBuild.Number == "" {
			continue
		}

		bld, err := jBuild.asBuild()
		if err != nil {
			return nil, fmt.Errorf("Could not create build object from jsonBuild object: %s", err)
		}

		if strings.Contains(bld.Path, "pr-logs") {
			parts := strings.Split(bld.Path, "/")
			bld.PR = parts[len(parts)-3]
		}

		builds[bld.Path] = bld
	}

	return builds, nil
}

// jsonFailure represents a test failure as reported by the JSON. All values are strings.
// This should not be instantiated directly, but rather via the encoding/json package's
// Unmarshal method. This is an intermediary state for the data until it can be put into
// a failure object.
type jsonFailure struct {
	Started     string `json:"started"`
	Build       string `json:"build"`
	Name        string `json:"name"`
	FailureText string `json:"failure_text"`
}

// asFailure is a factory function that creates a failure object from the jsonFailure object,
// appropriately handling all type conversions.
func (jf *jsonFailure) asFailure() (failure, error) {
	// The failure object that will be returned, initialized with the values that
	// don't need conversion.
	f := failure{
		Build:       jf.Build,
		Name:        jf.Name,
		FailureText: jf.FailureText,
	}

	// To avoid assignment issues
	var err error

	// started
	if jf.Started != "" {
		f.Started, err = strconv.Atoi(jf.Started)
		if err != nil {
			return failure{}, fmt.Errorf("Error converting JSON string '%s' to int for failure field 'started': %s", jf.Started, err)
		}
	}

	return f, nil
}

// loadTests parses multiple JSON files containing test information for failed tests. It returns a
// map from test names to failure objects.
func loadTests(testsFilepaths []string) (map[string][]failure, error) {
	// The map
	tests := make(map[string][]failure)

	// jsonTests temporarily stores the tests as they are retrieved from the JSON file
	// until they can be converted to failure objects
	jsonFailures := make([]jsonFailure, 0)
	for _, filepath := range testsFilepaths {
		file, err := os.Open(filepath)
		if err != nil {
			return nil, fmt.Errorf("Could not open tests file '%s': %s", filepath, err)
		}
		defer file.Close()

		// Read each line in the file as its own JSON object
		scanner := bufio.NewScanner(file)
		for scanner.Scan() {
			var jf jsonFailure
			err = json.Unmarshal(scanner.Bytes(), &jf)
			if err != nil {
				return nil, fmt.Errorf("Could not unmarshal JSON for text '%s': %s", scanner.Text(), err)
			}
			jsonFailures = append(jsonFailures, jf)
		}
		if err := scanner.Err(); err != nil {
			return nil, fmt.Errorf("Could not read file line by line: %s", err)
		}

		// Convert the failure information to internal failure objects and store them in tests
		for _, jf := range jsonFailures {
			// Check if tests of this type are already in the map
			if _, ok := tests[jf.Name]; !ok {
				tests[jf.Name] = make([]failure, 0)
			}

			test, err := jf.asFailure()
			if err != nil {
				return nil, fmt.Errorf("Could not create failure object from jsonFailure object: %s", err)
			}

			tests[jf.Name] = append(tests[jf.Name], test)
		}
	}

	// Sort the failures within each test by build
	for _, testSlice := range tests {
		sort.Slice(testSlice, func(i, j int) bool { return testSlice[i].Build < testSlice[j].Build })
	}

	return tests, nil
}

// getJSON opens a JSON file, parses it according to the schema provided by v, and places the results
// into v. Internally, it calls encoding/json's Unmarshal using v as the second argument. Therefore,
// v mut be a non-nil pointer.
func getJSON(filepath string, v interface{}) error {
	contents, err := ioutil.ReadFile(filepath)
	if err != nil {
		return fmt.Errorf("Could not open file '%s': %s", filepath, err)
	}

	// Decode the JSON into the provided interface
	err = json.Unmarshal(contents, v)
	if err != nil {
		return fmt.Errorf("Could not unmarshal JSON: %s", err)
	}

	return nil
}

// writeJSON generates JSON according to v and writes the results to filepath.
func writeJSON(filepath string, v interface{}) error {
	output, err := json.Marshal(v)
	if err != nil {
		return fmt.Errorf("Could not encode JSON: %s", err)
	}

	err = ioutil.WriteFile(filepath, output, 0644)
	if err != nil {
		return fmt.Errorf("Could not write JSON to file: %s", err)
	}

	return nil
}
<commit_msg>bufio => streaming decoder<commit_after>/*
Copyright 2020 The Kubernetes 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.
*/

/*
Contains functions that manage the reading and writing of files related to package summarize.
This includes reading and interpreting JSON files as actionable data, memoizing function
results to JSON, and outputting results once the summarization process is complete.
*/

package summarize

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"sort"
	"strconv"
	"strings"
)

// loadFailures loads a builds file and one or more test failure files. It maps build paths to builds
// and groups test failures by test name.
func loadFailures(buildsFilepath string, testsFilepaths []string) (map[string]build, map[string][]failure, error) {
	const memoMessage string = "loading failed tests"

	builds := make(map[string]build)
	tests := make(map[string][]failure)

	// Try to retrieve memoized results first to avoid another computation
	if getMemoizedResults("memo_load_failures-builds.json", "", &builds) &&
		getMemoizedResults("memo_load_failures-tests.json", "", &tests) {
		logInfo("Done (cached) " + memoMessage)
		return builds, tests, nil
	}

	builds, err := loadBuilds(buildsFilepath)
	if err != nil {
		return nil, nil, fmt.Errorf("Could not retrieve builds: %s", err)
	}

	tests, err = loadTests(testsFilepaths)
	if err != nil {
		return nil, nil, fmt.Errorf("Could not retrieve tests: %s", err)
	}

	memoizeResults("memo_load_failures-builds.json", "", builds)
	memoizeResults("memo_load_failures-tests.json", "", tests)
	logInfo("Done " + memoMessage)
	return builds, tests, nil
}

// loadPrevious loads a previous output and returns the 'clustered' field.
func loadPrevious(filepath string) ([]jsonCluster, error) {
	var previous jsonOutput

	err := getJSON(filepath, &previous)
	if err != nil {
		return nil, fmt.Errorf("Could not get previous results JSON: %s", err)
	}

	return previous.Clustered, nil
}

// loadOwners loads an owners JSON file and returns it.
func loadOwners(filepath string) (map[string][]string, error) {
	var owners map[string][]string

	err := getJSON(filepath, &owners)
	if err != nil {
		return nil, fmt.Errorf("Could not get owners JSON: %s", err)
	}

	return owners, nil
}

// writeResults outputs the results of clustering to a file.
func writeResults(filepath string, data jsonOutput) error {
	err := writeJSON(filepath, data)
	if err != nil {
		return fmt.Errorf("Could not write results to disk: %s", err)
	}
	return nil
}

type renderedSliceOutput struct {
	Clustered []jsonCluster `json:"clustered"`
	Builds    columns       `json:"builds"`
}

// writeRenderedSlice outputs the results of a call to renderSlice() to a file.
func writeRenderedSlice(filepath string, clustered []jsonCluster, builds columns) error {
	output := renderedSliceOutput{
		clustered,
		builds,
	}

	err := writeJSON(filepath, output)
	if err != nil {
		return fmt.Errorf("Could not write subset to disk: %s", err)
	}
	return nil
}

/*
getMemoizedResults attempts to retrieve memoized function results from the given filepath. If it
succeeds, it places the results into v and returns true. Otherwise, it returns false. Internally,
it calls encoding/json's Unmarshal using v as the second argument. Therefore, v mut be a non-nil
pointer.

message is a message that gets printed on success, appended to "Done (cached) ". If it is the empty
string, no message is printed.
*/
func getMemoizedResults(filepath string, message string, v interface{}) (ok bool) {
	err := getJSON(filepath, v)
	if err == nil {
		if message != "" {
			logInfo("Done (cached) " + message)
		}
		return true
	}
	return false
}

/*
memoizeResults saves the results stored in v to a JSON file. v should be a value, not a pointer. It
prints a warning if the results could not be memoized.

message is a message that gets printed on success, appended to "Done ". If it is the empty
string, no message is printed.
*/
func memoizeResults(filepath string, message string, v interface{}) {
	err := writeJSON(filepath, v)
	if err == nil && message != "" {
		logInfo("Done " + message)
		return
	}

	logWarning("Could not memoize results to '%s': %s", filepath, err)
}

/* Functions below this comment are only used within this file as of this commit. */

// jsonBuild represents a build as reported by the JSON. All values are strings.
// This should not be instantiated directly, but rather via the encoding/json package's
// Unmarshal method. This is an intermediary state for the data until it can be put into
// a build object.
type jsonBuild struct {
	Path        string `json:"path"`
	Started     string `json:"started"`
	Elapsed     string `json:"elapsed"`
	TestsRun    string `json:"tests_run"`
	TestsFailed string `json:"tests_failed"`
	Result      string `json:"result"`
	Executor    string `json:"executor"`
	Job         string `json:"job"`
	Number      string `json:"number"`
	PR          string `json:"pr"`
	Key         string `json:"key"` // Often nonexistent
}

// asBuild is a factory function that creates a build object from a jsonBuild object, appropriately
// handling all type conversions.
func (jb *jsonBuild) asBuild() (build, error) {
	// The build object that will be returned, initialized with the values that
	// don't need conversion.
	b := build{
		Path:     jb.Path,
		Result:   jb.Result,
		Executor: jb.Executor,
		Job:      jb.Job,
		PR:       jb.PR,
		Key:      jb.Key,
	}

	// To avoid assignment issues
	var err error

	// started
	if jb.Started != "" {
		b.Started, err = strconv.Atoi(jb.Started)
		if err != nil {
			return build{}, fmt.Errorf("Error converting JSON string '%s' to int for build field 'started': %s", jb.Started, err)
		}
	}

	// elapsed
	if jb.Elapsed != "" {
		tempElapsed, err := strconv.ParseFloat(jb.Elapsed, 32)
		if err != nil {
			return build{}, fmt.Errorf("Error converting JSON string '%s' to float32 for build field 'elapsed': %s", jb.Elapsed, err)
		}
		b.Elapsed = int(tempElapsed)
	}

	// testsRun
	if jb.TestsRun != "" {
		b.TestsRun, err = strconv.Atoi(jb.TestsRun)
		if err != nil {
			return build{}, fmt.Errorf("Error converting JSON string '%s' to int for build field 'testsRun': %s", jb.TestsRun, err)
		}
	}

	// testsFailed
	if jb.TestsFailed != "" {
		b.TestsFailed, err = strconv.Atoi(jb.TestsFailed)
		if err != nil {
			return build{}, fmt.Errorf("Error converting JSON string '%s' to int for build field 'testsFailed': %s", jb.TestsFailed, err)
		}
	}

	// number
	if jb.Number != "" {
		b.Number, err = strconv.Atoi(jb.Number)
		if err != nil {
			return build{}, fmt.Errorf("Error converting JSON string '%s' to int for build field 'number': %s", jb.Number, err)
		}
	}

	return b, nil
}

// loadBuilds parses a JSON file containing build information and returns a map from build paths
// to build objects.
func loadBuilds(filepath string) (map[string]build, error) {
	// The map
	builds := make(map[string]build)

	// jsonBuilds temporarily stores the builds as they are retrieved from the JSON file
	// until they can be converted to build objects
	jsonBuilds := make([]jsonBuild, 0)

	err := getJSON(filepath, &jsonBuilds)
	if err != nil {
		return nil, fmt.Errorf("Could not get builds JSON: %s", err)
	}

	// Convert the build information to internal build objects and store them in the builds map
	for _, jBuild := range jsonBuilds {
		// Skip builds without a start time or build number
		if jBuild.Started == "" || jBuild.Number == "" {
			continue
		}

		bld, err := jBuild.asBuild()
		if err != nil {
			return nil, fmt.Errorf("Could not create build object from jsonBuild object: %s", err)
		}

		if strings.Contains(bld.Path, "pr-logs") {
			parts := strings.Split(bld.Path, "/")
			bld.PR = parts[len(parts)-3]
		}

		builds[bld.Path] = bld
	}

	return builds, nil
}

// jsonFailure represents a test failure as reported by the JSON. All values are strings.
// This should not be instantiated directly, but rather via the encoding/json package's
// Unmarshal method. This is an intermediary state for the data until it can be put into
// a failure object.
type jsonFailure struct {
	Started     string `json:"started"`
	Build       string `json:"build"`
	Name        string `json:"name"`
	FailureText string `json:"failure_text"`
}

// asFailure is a factory function that creates a failure object from the jsonFailure object,
// appropriately handling all type conversions.
func (jf *jsonFailure) asFailure() (failure, error) {
	// The failure object that will be returned, initialized with the values that
	// don't need conversion.
	f := failure{
		Build:       jf.Build,
		Name:        jf.Name,
		FailureText: jf.FailureText,
	}

	// To avoid assignment issues
	var err error

	// started
	if jf.Started != "" {
		f.Started, err = strconv.Atoi(jf.Started)
		if err != nil {
			return failure{}, fmt.Errorf("Error converting JSON string '%s' to int for failure field 'started': %s", jf.Started, err)
		}
	}

	return f, nil
}

// loadTests parses multiple JSON files containing test information for failed tests. It returns a
// map from test names to failure objects.
func loadTests(testsFilepaths []string) (map[string][]failure, error) {
	// The map
	tests := make(map[string][]failure)

	// jsonTests temporarily stores the tests as they are retrieved from the JSON file
	// until they can be converted to failure objects
	jsonFailures := make([]jsonFailure, 0)
	for _, filepath := range testsFilepaths {
		file, err := os.Open(filepath)
		if err != nil {
			return nil, fmt.Errorf("Could not open tests file '%s': %s", filepath, err)
		}
		defer file.Close()

		// Read each line in the file as its own JSON object
		decoder := json.NewDecoder(file)
		for {
			// TODO: this probably gives fairly useless errors
			var jf jsonFailure
			if err := decoder.Decode(&jf); err == io.EOF {
				break // reached EOF
			} else if err != nil {
				return nil, err
			}
			jsonFailures = append(jsonFailures, jf)
		}

		// Convert the failure information to internal failure objects and store them in tests
		for _, jf := range jsonFailures {
			// Check if tests of this type are already in the map
			if _, ok := tests[jf.Name]; !ok {
				tests[jf.Name] = make([]failure, 0)
			}

			test, err := jf.asFailure()
			if err != nil {
				return nil, fmt.Errorf("Could not create failure object from jsonFailure object: %s", err)
			}

			tests[jf.Name] = append(tests[jf.Name], test)
		}
	}

	// Sort the failures within each test by build
	for _, testSlice := range tests {
		sort.Slice(testSlice, func(i, j int) bool { return testSlice[i].Build < testSlice[j].Build })
	}

	return tests, nil
}

// getJSON opens a JSON file, parses it according to the schema provided by v, and places the results
// into v. Internally, it calls encoding/json's Unmarshal using v as the second argument. Therefore,
// v mut be a non-nil pointer.
func getJSON(filepath string, v interface{}) error {
	contents, err := ioutil.ReadFile(filepath)
	if err != nil {
		return fmt.Errorf("Could not open file '%s': %s", filepath, err)
	}

	// Decode the JSON into the provided interface
	err = json.Unmarshal(contents, v)
	if err != nil {
		return fmt.Errorf("Could not unmarshal JSON: %s", err)
	}

	return nil
}

// writeJSON generates JSON according to v and writes the results to filepath.
func writeJSON(filepath string, v interface{}) error {
	output, err := json.Marshal(v)
	if err != nil {
		return fmt.Errorf("Could not encode JSON: %s", err)
	}

	err = ioutil.WriteFile(filepath, output, 0644)
	if err != nil {
		return fmt.Errorf("Could not write JSON to file: %s", err)
	}

	return nil
}
<|endoftext|>


<commit_before>// +build windows

/*
 * Copyright (c) 2013-2014, Jeremy Bingham (<jbingham@gmail.com>)
 *
 * 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 config

import (
	"github.com/tideland/golib/logger"
)

func setLogger(useSyslog bool) error {
	_ = useSyslog
	logger.SetLogger(logger.NewGoLogger())
	return nil
}
<commit_msg>Add a warning that syslog isn't supported under Windows and that the setting is being ignored, in case someone tries it.<commit_after>// +build windows

/*
 * Copyright (c) 2013-2014, Jeremy Bingham (<jbingham@gmail.com>)
 *
 * 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 config

import (
	"log"
	"github.com/tideland/golib/logger"
)

func setLogger(useSyslog bool) error {
	if useSyslog {
		log.Println("Syslog isn't actually supported in Windows - using regular logging.")
	}
	logger.SetLogger(logger.NewGoLogger())
	return nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2016, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package sh

// Token is the set of lexical tokens.
type Token int

// The list of all possible tokens.
const (
	ILLEGAL Token = -iota
	STOPPED
	EOF
	LIT
	COMMENT

	// POSIX Shell reserved words
	IF
	THEN
	ELIF
	ELSE
	FI
	WHILE
	FOR
	IN
	UNTIL
	DO
	DONE
	CASE
	ESAC

	NOT    // !
	LBRACE // {
	RBRACE // }

	// Bash reserved words
	FUNCTION
	DECLARE
	LOCAL
	EVAL
	LET

	// Rest of tokens
	SQUOTE // '
	DQUOTE // "
	BQUOTE // `

	AND  // &
	LAND // &&
	OR   // |
	LOR  // ||

	ASSIGN // =
	DOLLAR // $
	DOLLSQ // $'
	DOLLDQ // $"
	DOLLBR // ${
	DOLLPR // $(
	DOLLDP // $((
	LPAREN // (

	RPAREN     // )
	SEMICOLON  // ;
	DSEMICOLON // ;;
	SEMIFALL   // ;&
	DSEMIFALL  // ;;&
	COLON      // :

	LSS // <
	GTR // >
	SHL // <<
	SHR // >>

	ADD   // +
	SUB   // -
	REM   // %
	MUL   // *
	QUO   // /
	XOR   // ^
	INC   // ++
	DEC   // --
	POW   // **
	COMMA // ,
	EQL   // ==
	NEQ   // !=
	LEQ   // <=
	GEQ   // >=

	ADDASSGN // +=
	SUBASSGN // -=
	MULASSGN // *=
	QUOASSGN // /=
	REMASSGN // %=
	ANDASSGN // &=
	ORASSGN  // |=
	XORASSGN // ^=
	SHLASSGN // <<=
	SHRASSGN // >>=

	PIPEALL  // |&
	RDRINOUT // <>
	DPLIN    // <&
	DPLOUT   // >&
	DHEREDOC // <<-
	WHEREDOC // <<<
	CMDIN    // <(
	CMDOUT   // >(
	RDRALL   // &>
	APPALL   // &>>

	CADD    // :+
	CSUB    // :-
	QUEST   // ?
	CQUEST  // :?
	CASSIGN // :=
	DREM    // %%
	HASH    // #
	DHASH   // ##
	LBRACK  // [
	RBRACK  // ]
	DQUO    // //

	DLPAREN // ((
	DRPAREN // ))
)

// Pos is the internal representation of a position within a source
// file.
type Pos struct {
	Line   int // line number, starting at 1
	Column int // column number (in bytes), starting at 1
}

func posGreater(p1, p2 Pos) bool {
	if p1.Line == p2.Line {
		return p1.Column > p2.Column
	}
	return p1.Line > p2.Line
}

func posMax(p1, p2 Pos) Pos {
	if posGreater(p2, p1) {
		return p2
	}
	return p1
}

var (
	tokNames = map[Token]string{
		ILLEGAL: `ILLEGAL`,
		STOPPED: `STOPPED`,
		EOF:     `EOF`,
		LIT:     `literal`,
		COMMENT: `comment`,

		DLPAREN: "((",
		DRPAREN: "))",

		IF:    "if",
		THEN:  "then",
		ELIF:  "elif",
		ELSE:  "else",
		FI:    "fi",
		WHILE: "while",
		FOR:   "for",
		IN:    "in",
		UNTIL: "until",
		DO:    "do",
		DONE:  "done",
		CASE:  "case",
		ESAC:  "esac",

		NOT:    "!",
		LBRACE: "{",
		RBRACE: "}",

		FUNCTION: "function",
		DECLARE:  "declare",
		LOCAL:    "local",
		EVAL:     "eval",
		LET:      "let",

		SQUOTE: `'`,
		DQUOTE: `"`,
		BQUOTE: "`",

		AND:  "&",
		LAND: "&&",
		OR:   "|",
		LOR:  "||",

		DOLLAR:     "$",
		DOLLSQ:     "$'",
		DOLLDQ:     `$"`,
		DOLLBR:     `${`,
		DOLLPR:     `$(`,
		DOLLDP:     `$((`,
		LPAREN:     "(",
		RPAREN:     ")",
		SEMICOLON:  ";",
		DSEMICOLON: ";;",
		SEMIFALL:   ";&",
		DSEMIFALL:  ";;&",

		LSS:      "<",
		GTR:      ">",
		SHL:      "<<",
		SHR:      ">>",
		PIPEALL:  "|&",
		RDRINOUT: "<>",
		DPLIN:    "<&",
		DPLOUT:   ">&",
		DHEREDOC: "<<-",
		WHEREDOC: "<<<",
		CMDIN:    "<(",
		CMDOUT:   ">(",
		RDRALL:   "&>",
		APPALL:   "&>>",

		COLON:   ":",
		ADD:     "+",
		CADD:    ":+",
		SUB:     "-",
		CSUB:    ":-",
		QUEST:   "?",
		CQUEST:  ":?",
		ASSIGN:  "=",
		CASSIGN: ":=",
		REM:     "%",
		DREM:    "%%",
		HASH:    "#",
		DHASH:   "##",
		LBRACK:  "[",
		RBRACK:  "]",
		QUO:     "/",
		DQUO:    "//",

		MUL:   "*",
		XOR:   "^",
		INC:   "++",
		DEC:   "--",
		POW:   "**",
		COMMA: ",",
		EQL:   "==",
		NEQ:   "!=",
		LEQ:   "<=",
		GEQ:   ">=",

		ADDASSGN: "+=",
		SUBASSGN: "-=",
		MULASSGN: "*=",
		QUOASSGN: "/=",
		REMASSGN: "%=",
		ANDASSGN: "&=",
		ORASSGN:  "|=",
		XORASSGN: "^=",
		SHLASSGN: "<<=",
		SHRASSGN: ">>=",
	}
)

func (t Token) String() string { return tokNames[t] }

// TODO: decouple from parser. Passing readOnly as a func argument
// doesn't seem to work well as it means an extra allocation (?).
func (p *parser) doRegToken(b byte) Token {
	switch b {
	case '\'':
		return SQUOTE
	case '"':
		return DQUOTE
	case '`':
		return BQUOTE
	case '&':
		switch {
		case p.readOnly('&'):
			return LAND
		case p.readOnly('>'):
			if p.readOnly('>') {
				return APPALL
			}
			return RDRALL
		}
		return AND
	case '|':
		switch {
		case p.readOnly('|'):
			return LOR
		case p.readOnly('&'):
			return PIPEALL
		}
		return OR
	case '$':
		switch {
		case p.readOnly('\''):
			return DOLLSQ
		case p.readOnly('"'):
			return DOLLDQ
		case p.readOnly('{'):
			return DOLLBR
		case p.readOnly('('):
			if p.readOnly('(') {
				return DOLLDP
			}
			return DOLLPR
		}
		return DOLLAR
	case '(':
		return LPAREN
	case ')':
		return RPAREN
	case ';':
		if p.readOnly(';') {
			if p.readOnly('&') {
				return DSEMIFALL
			}
			return DSEMICOLON
		}
		if p.readOnly('&') {
			return SEMIFALL
		}
		return SEMICOLON
	case '<':
		switch {
		case p.readOnly('<'):
			if p.readOnly('-') {
				return DHEREDOC
			}
			if p.readOnly('<') {
				return WHEREDOC
			}
			return SHL
		case p.readOnly('>'):
			return RDRINOUT
		case p.readOnly('&'):
			return DPLIN
		case p.readOnly('('):
			return CMDIN
		}
		return LSS
	case '>':
		switch {
		case p.readOnly('>'):
			return SHR
		case p.readOnly('&'):
			return DPLOUT
		case p.readOnly('('):
			return CMDOUT
		}
		return GTR
	}
	return ILLEGAL
}

func (p *parser) doParamToken(b byte) Token {
	switch b {
	case ':':
		switch {
		case p.readOnly('+'):
			return CADD
		case p.readOnly('-'):
			return CSUB
		case p.readOnly('?'):
			return CQUEST
		case p.readOnly('='):
			return CASSIGN
		}
		return COLON
	case '+':
		return ADD
	case '-':
		return SUB
	case '?':
		return QUEST
	case '=':
		return ASSIGN
	case '%':
		if p.readOnly('%') {
			return DREM
		}
		return REM
	case '#':
		if p.readOnly('#') {
			return DHASH
		}
		return HASH
	case '[':
		return LBRACK
	case '/':
		if p.readOnly('/') {
			return DQUO
		}
		return QUO
	}
	return ILLEGAL
}

func (p *parser) doArithmToken(b byte) Token {
	switch b {
	case '!':
		if p.readOnly('=') {
			return NEQ
		}
		return NOT
	case '=':
		if p.readOnly('=') {
			return EQL
		}
		return ASSIGN
	case '(':
		return LPAREN
	case ')':
		return RPAREN
	case '&':
		if p.readOnly('&') {
			return LAND
		}
		if p.readOnly('=') {
			return ANDASSGN
		}
		return AND
	case '|':
		if p.readOnly('|') {
			return LOR
		}
		if p.readOnly('=') {
			return ORASSGN
		}
		return OR
	case '<':
		switch {
		case p.readOnly('<'):
			if p.readOnly('=') {
				return SHLASSGN
			}
			return SHL
		case p.readOnly('='):
			return LEQ
		}
		return LSS
	case '>':
		switch {
		case p.readOnly('>'):
			if p.readOnly('=') {
				return SHRASSGN
			}
			return SHR
		case p.readOnly('='):
			return GEQ
		}
		return GTR
	case '+':
		if p.readOnly('+') {
			return INC
		}
		if p.readOnly('=') {
			return ADDASSGN
		}
		return ADD
	case '-':
		if p.readOnly('-') {
			return DEC
		}
		if p.readOnly('=') {
			return SUBASSGN
		}
		return SUB
	case '%':
		if p.readOnly('=') {
			return REMASSGN
		}
		return REM
	case '*':
		if p.readOnly('*') {
			return POW
		}
		if p.readOnly('=') {
			return MULASSGN
		}
		return MUL
	case '/':
		if p.readOnly('=') {
			return QUOASSGN
		}
		return QUO
	case '^':
		if p.readOnly('=') {
			return XORASSGN
		}
		return XOR
	case ',':
		return COMMA
	case '?':
		return QUEST
	case ':':
		return COLON
	}
	return ILLEGAL
}
<commit_msg>token: make tokens be positive consts<commit_after>// Copyright (c) 2016, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package sh

// Token is the set of lexical tokens.
type Token int

// The list of all possible tokens.
const (
	ILLEGAL Token = iota
	STOPPED
	EOF
	LIT
	COMMENT

	// POSIX Shell reserved words
	IF
	THEN
	ELIF
	ELSE
	FI
	WHILE
	FOR
	IN
	UNTIL
	DO
	DONE
	CASE
	ESAC

	NOT    // !
	LBRACE // {
	RBRACE // }

	// Bash reserved words
	FUNCTION
	DECLARE
	LOCAL
	EVAL
	LET

	// Rest of tokens
	SQUOTE // '
	DQUOTE // "
	BQUOTE // `

	AND  // &
	LAND // &&
	OR   // |
	LOR  // ||

	ASSIGN // =
	DOLLAR // $
	DOLLSQ // $'
	DOLLDQ // $"
	DOLLBR // ${
	DOLLPR // $(
	DOLLDP // $((
	LPAREN // (

	RPAREN     // )
	SEMICOLON  // ;
	DSEMICOLON // ;;
	SEMIFALL   // ;&
	DSEMIFALL  // ;;&
	COLON      // :

	LSS // <
	GTR // >
	SHL // <<
	SHR // >>

	ADD   // +
	SUB   // -
	REM   // %
	MUL   // *
	QUO   // /
	XOR   // ^
	INC   // ++
	DEC   // --
	POW   // **
	COMMA // ,
	EQL   // ==
	NEQ   // !=
	LEQ   // <=
	GEQ   // >=

	ADDASSGN // +=
	SUBASSGN // -=
	MULASSGN // *=
	QUOASSGN // /=
	REMASSGN // %=
	ANDASSGN // &=
	ORASSGN  // |=
	XORASSGN // ^=
	SHLASSGN // <<=
	SHRASSGN // >>=

	PIPEALL  // |&
	RDRINOUT // <>
	DPLIN    // <&
	DPLOUT   // >&
	DHEREDOC // <<-
	WHEREDOC // <<<
	CMDIN    // <(
	CMDOUT   // >(
	RDRALL   // &>
	APPALL   // &>>

	CADD    // :+
	CSUB    // :-
	QUEST   // ?
	CQUEST  // :?
	CASSIGN // :=
	DREM    // %%
	HASH    // #
	DHASH   // ##
	LBRACK  // [
	RBRACK  // ]
	DQUO    // //

	DLPAREN // ((
	DRPAREN // ))
)

// Pos is the internal representation of a position within a source
// file.
type Pos struct {
	Line   int // line number, starting at 1
	Column int // column number (in bytes), starting at 1
}

func posGreater(p1, p2 Pos) bool {
	if p1.Line == p2.Line {
		return p1.Column > p2.Column
	}
	return p1.Line > p2.Line
}

func posMax(p1, p2 Pos) Pos {
	if posGreater(p2, p1) {
		return p2
	}
	return p1
}

var (
	tokNames = map[Token]string{
		ILLEGAL: `ILLEGAL`,
		STOPPED: `STOPPED`,
		EOF:     `EOF`,
		LIT:     `literal`,
		COMMENT: `comment`,

		DLPAREN: "((",
		DRPAREN: "))",

		IF:    "if",
		THEN:  "then",
		ELIF:  "elif",
		ELSE:  "else",
		FI:    "fi",
		WHILE: "while",
		FOR:   "for",
		IN:    "in",
		UNTIL: "until",
		DO:    "do",
		DONE:  "done",
		CASE:  "case",
		ESAC:  "esac",

		NOT:    "!",
		LBRACE: "{",
		RBRACE: "}",

		FUNCTION: "function",
		DECLARE:  "declare",
		LOCAL:    "local",
		EVAL:     "eval",
		LET:      "let",

		SQUOTE: `'`,
		DQUOTE: `"`,
		BQUOTE: "`",

		AND:  "&",
		LAND: "&&",
		OR:   "|",
		LOR:  "||",

		DOLLAR:     "$",
		DOLLSQ:     "$'",
		DOLLDQ:     `$"`,
		DOLLBR:     `${`,
		DOLLPR:     `$(`,
		DOLLDP:     `$((`,
		LPAREN:     "(",
		RPAREN:     ")",
		SEMICOLON:  ";",
		DSEMICOLON: ";;",
		SEMIFALL:   ";&",
		DSEMIFALL:  ";;&",

		LSS:      "<",
		GTR:      ">",
		SHL:      "<<",
		SHR:      ">>",
		PIPEALL:  "|&",
		RDRINOUT: "<>",
		DPLIN:    "<&",
		DPLOUT:   ">&",
		DHEREDOC: "<<-",
		WHEREDOC: "<<<",
		CMDIN:    "<(",
		CMDOUT:   ">(",
		RDRALL:   "&>",
		APPALL:   "&>>",

		COLON:   ":",
		ADD:     "+",
		CADD:    ":+",
		SUB:     "-",
		CSUB:    ":-",
		QUEST:   "?",
		CQUEST:  ":?",
		ASSIGN:  "=",
		CASSIGN: ":=",
		REM:     "%",
		DREM:    "%%",
		HASH:    "#",
		DHASH:   "##",
		LBRACK:  "[",
		RBRACK:  "]",
		QUO:     "/",
		DQUO:    "//",

		MUL:   "*",
		XOR:   "^",
		INC:   "++",
		DEC:   "--",
		POW:   "**",
		COMMA: ",",
		EQL:   "==",
		NEQ:   "!=",
		LEQ:   "<=",
		GEQ:   ">=",

		ADDASSGN: "+=",
		SUBASSGN: "-=",
		MULASSGN: "*=",
		QUOASSGN: "/=",
		REMASSGN: "%=",
		ANDASSGN: "&=",
		ORASSGN:  "|=",
		XORASSGN: "^=",
		SHLASSGN: "<<=",
		SHRASSGN: ">>=",
	}
)

func (t Token) String() string { return tokNames[t] }

// TODO: decouple from parser. Passing readOnly as a func argument
// doesn't seem to work well as it means an extra allocation (?).
func (p *parser) doRegToken(b byte) Token {
	switch b {
	case '\'':
		return SQUOTE
	case '"':
		return DQUOTE
	case '`':
		return BQUOTE
	case '&':
		switch {
		case p.readOnly('&'):
			return LAND
		case p.readOnly('>'):
			if p.readOnly('>') {
				return APPALL
			}
			return RDRALL
		}
		return AND
	case '|':
		switch {
		case p.readOnly('|'):
			return LOR
		case p.readOnly('&'):
			return PIPEALL
		}
		return OR
	case '$':
		switch {
		case p.readOnly('\''):
			return DOLLSQ
		case p.readOnly('"'):
			return DOLLDQ
		case p.readOnly('{'):
			return DOLLBR
		case p.readOnly('('):
			if p.readOnly('(') {
				return DOLLDP
			}
			return DOLLPR
		}
		return DOLLAR
	case '(':
		return LPAREN
	case ')':
		return RPAREN
	case ';':
		if p.readOnly(';') {
			if p.readOnly('&') {
				return DSEMIFALL
			}
			return DSEMICOLON
		}
		if p.readOnly('&') {
			return SEMIFALL
		}
		return SEMICOLON
	case '<':
		switch {
		case p.readOnly('<'):
			if p.readOnly('-') {
				return DHEREDOC
			}
			if p.readOnly('<') {
				return WHEREDOC
			}
			return SHL
		case p.readOnly('>'):
			return RDRINOUT
		case p.readOnly('&'):
			return DPLIN
		case p.readOnly('('):
			return CMDIN
		}
		return LSS
	case '>':
		switch {
		case p.readOnly('>'):
			return SHR
		case p.readOnly('&'):
			return DPLOUT
		case p.readOnly('('):
			return CMDOUT
		}
		return GTR
	}
	return ILLEGAL
}

func (p *parser) doParamToken(b byte) Token {
	switch b {
	case ':':
		switch {
		case p.readOnly('+'):
			return CADD
		case p.readOnly('-'):
			return CSUB
		case p.readOnly('?'):
			return CQUEST
		case p.readOnly('='):
			return CASSIGN
		}
		return COLON
	case '+':
		return ADD
	case '-':
		return SUB
	case '?':
		return QUEST
	case '=':
		return ASSIGN
	case '%':
		if p.readOnly('%') {
			return DREM
		}
		return REM
	case '#':
		if p.readOnly('#') {
			return DHASH
		}
		return HASH
	case '[':
		return LBRACK
	case '/':
		if p.readOnly('/') {
			return DQUO
		}
		return QUO
	}
	return ILLEGAL
}

func (p *parser) doArithmToken(b byte) Token {
	switch b {
	case '!':
		if p.readOnly('=') {
			return NEQ
		}
		return NOT
	case '=':
		if p.readOnly('=') {
			return EQL
		}
		return ASSIGN
	case '(':
		return LPAREN
	case ')':
		return RPAREN
	case '&':
		if p.readOnly('&') {
			return LAND
		}
		if p.readOnly('=') {
			return ANDASSGN
		}
		return AND
	case '|':
		if p.readOnly('|') {
			return LOR
		}
		if p.readOnly('=') {
			return ORASSGN
		}
		return OR
	case '<':
		switch {
		case p.readOnly('<'):
			if p.readOnly('=') {
				return SHLASSGN
			}
			return SHL
		case p.readOnly('='):
			return LEQ
		}
		return LSS
	case '>':
		switch {
		case p.readOnly('>'):
			if p.readOnly('=') {
				return SHRASSGN
			}
			return SHR
		case p.readOnly('='):
			return GEQ
		}
		return GTR
	case '+':
		if p.readOnly('+') {
			return INC
		}
		if p.readOnly('=') {
			return ADDASSGN
		}
		return ADD
	case '-':
		if p.readOnly('-') {
			return DEC
		}
		if p.readOnly('=') {
			return SUBASSGN
		}
		return SUB
	case '%':
		if p.readOnly('=') {
			return REMASSGN
		}
		return REM
	case '*':
		if p.readOnly('*') {
			return POW
		}
		if p.readOnly('=') {
			return MULASSGN
		}
		return MUL
	case '/':
		if p.readOnly('=') {
			return QUOASSGN
		}
		return QUO
	case '^':
		if p.readOnly('=') {
			return XORASSGN
		}
		return XOR
	case ',':
		return COMMA
	case '?':
		return QUEST
	case ':':
		return COLON
	}
	return ILLEGAL
}
<|endoftext|>


<commit_before>package nat

import (
	"bytes"
	"net"
	"sync"
	"time"

	"bitbucket.org/simonmenke/go-telehash/transports"
	"bitbucket.org/simonmenke/go-telehash/util/events"
	"bitbucket.org/simonmenke/go-telehash/util/nat"
)

var (
	_ transports.Transport = (*transport)(nil)
	_ transports.Config    = Config{}
)

type NATableAddr interface {
	InternalAddr() (proto string, ip net.IP, port int)
	MakeGlobal(ip net.IP, port int) transports.Addr
}

type Config struct {
	Config transports.Config
}

type transport struct {
	wg          sync.WaitGroup
	mtx         sync.Mutex
	t           transports.Transport
	mappedAddrs []transports.Addr
	nat         nat.NAT
	cEventIn    chan events.E
	cEventOut   chan<- events.E
	cTerminate  chan struct{}
	err         error
}

func (c Config) Open(e chan<- events.E) (transports.Transport, error) {
	nt := &transport{
		cEventIn:   make(chan events.E),
		cEventOut:  e,
		cTerminate: make(chan struct{}),
	}

	t, err := c.Config.Open(nt.cEventIn)
	if err != nil {
		return nil, err
	}

	nt.t = t
	nt.mappedAddrs = nt.refresh()
	nt.wg.Add(1)
	go nt.run()

	return nt, nil
}

func (t *transport) Close() error {
	detectClosed(func() { t.cTerminate <- struct{}{} })
	t.wg.Wait()
	return t.err
}

func (t *transport) close() {
	t.err = t.t.Close()
	close(t.cEventIn)
	close(t.cTerminate)
}

func (t *transport) CanHandleAddress(addr transports.Addr) bool {
	return t.t.CanHandleAddress(addr)
}

func (t *transport) LocalAddresses() []transports.Addr {
	t.mtx.Lock()
	m := t.mappedAddrs
	t.mtx.Unlock()

	return append(m, t.t.LocalAddresses()...)
}

func (t *transport) Deliver(pkt []byte, to transports.Addr) error {
	return t.t.Deliver(pkt, to)
}

func (t *transport) Receive(b []byte) (int, transports.Addr, error) {
	return t.t.Receive(b)
}

func (t *transport) run() {
	defer t.wg.Done()
	ticker := time.NewTicker(30 * time.Second)
	defer ticker.Stop()

	for {
		select {

		case <-t.cTerminate:
			t.close()
			return

		case evt := <-t.cEventIn:
			events.Emit(t.cEventOut, evt)

		case <-ticker.C:
			m := t.refresh()
			t.mtx.Lock()
			t.mappedAddrs = m
			t.mtx.Unlock()

		}
	}
}

func (t *transport) refresh() []transports.Addr {
	var (
		mappedAddrs []transports.Addr
	)

	if t.nat == nil {
		n, err := nat.Discover()
		if err != nil {
			tracef("NAT: no gateway was found. (%s)", err)
			return nil
		}
		t.nat = n
	}

	gateway_ip, err := t.nat.GetDeviceAddress()
	if err != nil {
		tracef("NAT: gateway is broken (%s)", err)
		t.nat = nil
		return nil
	}

	external_ip, err := t.nat.GetExternalAddress()
	if err != nil {
		tracef("NAT: gateway is broken (%s)", err)
		t.nat = nil
		return nil
	}

	internal_ip, err := t.nat.GetInternalAddress()
	if err != nil {
		tracef("NAT: gateway is broken (%s)", err)
		t.nat = nil
		return nil
	}

	internal_ip = internal_ip.To16()
	tracef("NAT: Using gateway %s (internal=%s external=%s)", gateway_ip, internal_ip, external_ip)

	for _, addr := range t.t.LocalAddresses() {
		nataddr, ok := addr.(NATableAddr)
		if !ok {
			tracef("NAT: not a nat address: %s", addr)
			continue
		}

		proto, ip, internal_port := nataddr.InternalAddr()
		if proto == "" || ip == nil || internal_port <= 0 {
			tracef("NAT: not a nat address: %s", addr)
			continue
		}

		if !bytes.Equal(ip.To16(), internal_ip) {
			tracef("NAT: not a nat address: %s (internal=%s)", ip, internal_ip)
			continue
		}

		tracef("NAT: mapping %s", addr)
		external_port, err := t.nat.AddPortMapping(proto, internal_port, "Telehash", 60*time.Second)
		if err != nil {
			tracef("NAT: failed to map %s %d", internal_ip, internal_port)
			continue
		}

		globaddr := nataddr.MakeGlobal(external_ip, external_port)
		if globaddr == nil {
			tracef("NAT: failed to map %s %d", internal_ip, internal_port)
			t.nat.DeletePortMapping(proto, internal_port)
			continue
		}

		tracef("NAT: mapped %s to %s", addr, globaddr)
		mappedAddrs = append(mappedAddrs, globaddr)
	}

	if len(mappedAddrs) == 0 {
		tracef("NAT: no mappable addresses")
	}

	return mappedAddrs
}

func detectClosed(f func()) (closed bool) {
	defer func() { closed = recover() != nil }()
	f()
	return false
}
<commit_msg>Flip-flop when an event is available<commit_after>package nat

import (
	"bytes"
	"net"
	"sync"
	"time"

	"bitbucket.org/simonmenke/go-telehash/transports"
	"bitbucket.org/simonmenke/go-telehash/util/events"
	"bitbucket.org/simonmenke/go-telehash/util/nat"
)

var (
	_ transports.Transport = (*transport)(nil)
	_ transports.Config    = Config{}
)

type NATableAddr interface {
	InternalAddr() (proto string, ip net.IP, port int)
	MakeGlobal(ip net.IP, port int) transports.Addr
}

type Config struct {
	Config transports.Config
}

type transport struct {
	wg          sync.WaitGroup
	mtx         sync.Mutex
	t           transports.Transport
	mappedAddrs []transports.Addr
	nat         nat.NAT
	cEventIn    chan events.E
	cEventOut   chan<- events.E
	cTerminate  chan struct{}
	err         error
}

func (c Config) Open(e chan<- events.E) (transports.Transport, error) {
	nt := &transport{
		cEventIn:   make(chan events.E),
		cEventOut:  e,
		cTerminate: make(chan struct{}),
	}

	t, err := c.Config.Open(nt.cEventIn)
	if err != nil {
		return nil, err
	}

	nt.t = t
	nt.mappedAddrs = nt.refresh()
	nt.wg.Add(1)
	go nt.run()

	return nt, nil
}

func (t *transport) Close() error {
	detectClosed(func() { t.cTerminate <- struct{}{} })
	t.wg.Wait()
	return t.err
}

func (t *transport) close() {
	t.err = t.t.Close()
	close(t.cEventIn)
	close(t.cTerminate)
}

func (t *transport) CanHandleAddress(addr transports.Addr) bool {
	return t.t.CanHandleAddress(addr)
}

func (t *transport) LocalAddresses() []transports.Addr {
	t.mtx.Lock()
	m := t.mappedAddrs
	t.mtx.Unlock()

	return append(m, t.t.LocalAddresses()...)
}

func (t *transport) Deliver(pkt []byte, to transports.Addr) error {
	return t.t.Deliver(pkt, to)
}

func (t *transport) Receive(b []byte) (int, transports.Addr, error) {
	return t.t.Receive(b)
}

func (t *transport) run() {

	var (
		ticker    = time.NewTicker(30 * time.Second)
		currEvent events.E
	)

	defer t.wg.Done()
	defer ticker.Stop()

	for {
		var (
			cEventIn  = t.cEventIn
			cEventOut = t.cEventOut
		)

		if currEvent == nil {
			cEventOut = nil
		} else {
			cEventIn = nil
		}

		select {

		case <-t.cTerminate:
			t.close()
			return

		case evt := <-cEventIn:
			currEvent = evt
		case cEventOut <- currEvent:
			currEvent = nil

		case <-ticker.C:
			m := t.refresh()
			t.mtx.Lock()
			t.mappedAddrs = m
			t.mtx.Unlock()

		}
	}
}

func (t *transport) refresh() []transports.Addr {
	var (
		mappedAddrs []transports.Addr
	)

	if t.nat == nil {
		n, err := nat.Discover()
		if err != nil {
			tracef("NAT: no gateway was found. (%s)", err)
			return nil
		}
		t.nat = n
	}

	gateway_ip, err := t.nat.GetDeviceAddress()
	if err != nil {
		tracef("NAT: gateway is broken (%s)", err)
		t.nat = nil
		return nil
	}

	external_ip, err := t.nat.GetExternalAddress()
	if err != nil {
		tracef("NAT: gateway is broken (%s)", err)
		t.nat = nil
		return nil
	}

	internal_ip, err := t.nat.GetInternalAddress()
	if err != nil {
		tracef("NAT: gateway is broken (%s)", err)
		t.nat = nil
		return nil
	}

	internal_ip = internal_ip.To16()
	tracef("NAT: Using gateway %s (internal=%s external=%s)", gateway_ip, internal_ip, external_ip)

	for _, addr := range t.t.LocalAddresses() {
		nataddr, ok := addr.(NATableAddr)
		if !ok {
			tracef("NAT: not a nat address: %s", addr)
			continue
		}

		proto, ip, internal_port := nataddr.InternalAddr()
		if proto == "" || ip == nil || internal_port <= 0 {
			tracef("NAT: not a nat address: %s", addr)
			continue
		}

		if !bytes.Equal(ip.To16(), internal_ip) {
			tracef("NAT: not a nat address: %s (internal=%s)", ip, internal_ip)
			continue
		}

		tracef("NAT: mapping %s", addr)
		external_port, err := t.nat.AddPortMapping(proto, internal_port, "Telehash", 60*time.Second)
		if err != nil {
			tracef("NAT: failed to map %s %d", internal_ip, internal_port)
			continue
		}

		globaddr := nataddr.MakeGlobal(external_ip, external_port)
		if globaddr == nil {
			tracef("NAT: failed to map %s %d", internal_ip, internal_port)
			t.nat.DeletePortMapping(proto, internal_port)
			continue
		}

		tracef("NAT: mapped %s to %s", addr, globaddr)
		mappedAddrs = append(mappedAddrs, globaddr)
	}

	if len(mappedAddrs) == 0 {
		tracef("NAT: no mappable addresses")
	}

	return mappedAddrs
}

func detectClosed(f func()) (closed bool) {
	defer func() { closed = recover() != nil }()
	f()
	return false
}
<|endoftext|>


<commit_before>package engine

import (
	"strconv"
	"strings"
)

func Zhoda(k0, k1 Kombinacia) (zh int) {
	if k0 == nil || k1 == nil {
		return
	}
	for i, j := 0, 0; i < len(k0) && j < len(k1); {
		if k0[i] == k1[j] {
			zh++
			i++
			j++
		} else if k0[i] < k1[j] {
			i++
		} else {
			j++
		}
	}
	return
}

// ZhodaPresun urcuje poziciu presunu cisla
// z Kombinacie k0 do Kombinacie k1
type ZhodaPresun struct {
	p [][2]int
}

func NewZhodaPresun(k0, k1 Kombinacia) ZhodaPresun {
	if k0 == nil || k1 == nil {
		return ZhodaPresun{}
	}
	var zp ZhodaPresun
	for i, j := 0, 0; i < len(k0) && j < len(k1); {
		if k0[i] == k1[j] {
			zp.p = append(zp.p, [2]int{i + 1, j + 1})
			i++
			j++
		} else if k0[i] < k1[j] {
			i++
		} else {
			j++
		}
	}
	return zp
}

func (zp ZhodaPresun) String() string {
	s := make([]string, len(zp.p))
	for i, p := range zp.p {
		s[i] = strconv.Itoa(int(p[0])) + "|" + strconv.Itoa(int(p[1]))
	}
	return strings.Join(s, ", ")
}
<commit_msg>engine: delete ZhodaPresun<commit_after>package engine

func Zhoda(k0, k1 Kombinacia) (zh int) {
	if k0 == nil || k1 == nil {
		return
	}
	for i, j := 0, 0; i < len(k0) && j < len(k1); {
		if k0[i] == k1[j] {
			zh++
			i++
			j++
		} else if k0[i] < k1[j] {
			i++
		} else {
			j++
		}
	}
	return
}
<|endoftext|>


<commit_before>// Copyright ©2011-2012 The bíogo Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package contig

import (
	"code.google.com/p/biogo/alphabet"
	"code.google.com/p/biogo/seq"
	"code.google.com/p/biogo/seq/linear"

	"fmt"
	check "launchpad.net/gocheck"
	"testing"
)

func Test(t *testing.T) { check.TestingT(t) }

type S struct{}

var _ = check.Suite(&S{})

// Tests

type offsetSeq struct {
	seq    seq.Sequence
	offset int
}

type rep struct {
	val   string
	str   string
	fasta string
	rc    string
}

func (s *S) TestContig(c *check.C) {
	for i, t := range []struct {
		id      string
		length  int
		alpha   alphabet.Alphabet
		relaxed bool
		s       []offsetSeq
		rep     rep
		wrap    int
	}{
		{
			id:      "test",
			length:  20,
			alpha:   alphabet.DNA,
			relaxed: true,
			s: []offsetSeq{
				{
					linear.NewSeq("id1", alphabet.BytesToLetters([]byte("AGTC")), alphabet.DNA),
					2,
				},
				{
					linear.NewSeq("id2", alphabet.BytesToLetters([]byte("ACGT")), alphabet.DNA),
					15,
				},
			},
			rep: rep{
				val: `[0:n 2:"id1" AGTC 6:n 15:"id2" ACGT 19:n 20:<nil>]`, // If sequences overlap, this is misleading.
				str: `"test" nnAGTCnnnnnnnnnACGTn`,
				fasta: ">test\n" +
					"nnAGTCnnnnnnnnnACGTn",
				rc: `"test" nACGTnnnnnnnnnGACTnn`,
			},
		},
		{
			id:      "test",
			length:  20,
			alpha:   alphabet.DNA,
			relaxed: true,
			s: []offsetSeq{
				{
					linear.NewSeq("id1", alphabet.BytesToLetters([]byte("AGTC")), alphabet.DNA),
					2,
				},
				{
					linear.NewSeq("id2", alphabet.BytesToLetters([]byte("ACGT")), alphabet.DNA),
					15,
				},
			},
			rep: rep{
				val: `[0:n 2:"id1" AGTC 6:n 15:"id2" ACGT 19:n 20:<nil>]`, // If sequences overlap, this is misleading.
				str: `"test" nnAGTCnnnnnnnnnACGTn`,
				fasta: ">test\n" +
					"nnAGTCnnnn\n" +
					"nnnnnACGTn",
				rc: `"test" nACGTnnnnnnnnnGACTnn`,
			},
			wrap: 10,
		},
	} {
		con, err := New(t.id, t.length, t.alpha)
		c.Check(err, check.Equals, nil)
		con.Relaxed(t.relaxed)
		for _, os := range t.s {
			os.seq.SetOffset(os.offset)
			con.Insert(os.seq)
		}
		c.Check(fmt.Sprintf("%v", con), check.Equals, t.rep.val, check.Commentf("Test %d", i))
		c.Check(fmt.Sprintf("%s", con), check.Equals, t.rep.str, check.Commentf("Test %d", i))
		c.Check(fmt.Sprintf("%*a", t.wrap, con), check.Equals, t.rep.fasta, check.Commentf("Test %d", i))
		con.RevComp()
		c.Check(fmt.Sprintf("%s", con), check.Equals, t.rep.rc)
	}
}
<commit_msg>Update gocheck import paths<commit_after>// Copyright ©2011-2012 The bíogo Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package contig

import (
	"code.google.com/p/biogo/alphabet"
	"code.google.com/p/biogo/seq"
	"code.google.com/p/biogo/seq/linear"

	"fmt"
	"gopkg.in/check.v1"
	"testing"
)

func Test(t *testing.T) { check.TestingT(t) }

type S struct{}

var _ = check.Suite(&S{})

// Tests

type offsetSeq struct {
	seq    seq.Sequence
	offset int
}

type rep struct {
	val   string
	str   string
	fasta string
	rc    string
}

func (s *S) TestContig(c *check.C) {
	for i, t := range []struct {
		id      string
		length  int
		alpha   alphabet.Alphabet
		relaxed bool
		s       []offsetSeq
		rep     rep
		wrap    int
	}{
		{
			id:      "test",
			length:  20,
			alpha:   alphabet.DNA,
			relaxed: true,
			s: []offsetSeq{
				{
					linear.NewSeq("id1", alphabet.BytesToLetters([]byte("AGTC")), alphabet.DNA),
					2,
				},
				{
					linear.NewSeq("id2", alphabet.BytesToLetters([]byte("ACGT")), alphabet.DNA),
					15,
				},
			},
			rep: rep{
				val: `[0:n 2:"id1" AGTC 6:n 15:"id2" ACGT 19:n 20:<nil>]`, // If sequences overlap, this is misleading.
				str: `"test" nnAGTCnnnnnnnnnACGTn`,
				fasta: ">test\n" +
					"nnAGTCnnnnnnnnnACGTn",
				rc: `"test" nACGTnnnnnnnnnGACTnn`,
			},
		},
		{
			id:      "test",
			length:  20,
			alpha:   alphabet.DNA,
			relaxed: true,
			s: []offsetSeq{
				{
					linear.NewSeq("id1", alphabet.BytesToLetters([]byte("AGTC")), alphabet.DNA),
					2,
				},
				{
					linear.NewSeq("id2", alphabet.BytesToLetters([]byte("ACGT")), alphabet.DNA),
					15,
				},
			},
			rep: rep{
				val: `[0:n 2:"id1" AGTC 6:n 15:"id2" ACGT 19:n 20:<nil>]`, // If sequences overlap, this is misleading.
				str: `"test" nnAGTCnnnnnnnnnACGTn`,
				fasta: ">test\n" +
					"nnAGTCnnnn\n" +
					"nnnnnACGTn",
				rc: `"test" nACGTnnnnnnnnnGACTnn`,
			},
			wrap: 10,
		},
	} {
		con, err := New(t.id, t.length, t.alpha)
		c.Check(err, check.Equals, nil)
		con.Relaxed(t.relaxed)
		for _, os := range t.s {
			os.seq.SetOffset(os.offset)
			con.Insert(os.seq)
		}
		c.Check(fmt.Sprintf("%v", con), check.Equals, t.rep.val, check.Commentf("Test %d", i))
		c.Check(fmt.Sprintf("%s", con), check.Equals, t.rep.str, check.Commentf("Test %d", i))
		c.Check(fmt.Sprintf("%*a", t.wrap, con), check.Equals, t.rep.fasta, check.Commentf("Test %d", i))
		con.RevComp()
		c.Check(fmt.Sprintf("%s", con), check.Equals, t.rep.rc)
	}
}
<|endoftext|>


<commit_before>package openstack

import (
	"errors"
	"fmt"
	"github.com/mitchellh/packer/packer"
	"time"
)

// RunConfig contains configuration for running an instance from a source
// image and details on how to access that launched image.
type RunConfig struct {
	SourceImage   string `mapstructure:"source_image"`
	Flavor        string `mapstructure:"flavor"`
	RawSSHTimeout string `mapstructure:"ssh_timeout"`
	SSHUsername   string `mapstructure:"ssh_username"`
	SSHPort       int    `mapstructure:"ssh_port"`

	// Unexported fields that are calculated from others
	sshTimeout time.Duration
}

func (c *RunConfig) Prepare(t *packer.ConfigTemplate) []error {
	if t == nil {
		var err error
		t, err = packer.NewConfigTemplate()
		if err != nil {
			return []error{err}
		}
	}

	// Defaults
	if c.SSHUsername == "" {
		c.SSHUsername = "root"
	}

	if c.SSHPort == 0 {
		c.SSHPort = 22
	}

	if c.RawSSHTimeout == "" {
		c.RawSSHTimeout = "1m"
	}

	// Validation
	var err error
	errs := make([]error, 0)
	if c.SourceImage == "" {
		errs = append(errs, errors.New("A source_image must be specified"))
	}

	if c.Flavor == "" {
		errs = append(errs, errors.New("A flavor must be specified"))
	}

	if c.SSHUsername == "" {
		errs = append(errs, errors.New("An ssh_username must be specified"))
	}

	templates := map[string]*string{
		"flavlor":      &c.Flavor,
		"ssh_timeout":  &c.RawSSHTimeout,
		"ssh_username": &c.SSHUsername,
		"source_image": &c.SourceImage,
	}

	for n, ptr := range templates {
		var err error
		*ptr, err = t.Process(*ptr, nil)
		if err != nil {
			errs = append(
				errs, fmt.Errorf("Error processing %s: %s", n, err))
		}
	}

	c.sshTimeout, err = time.ParseDuration(c.RawSSHTimeout)
	if err != nil {
		errs = append(errs, fmt.Errorf("Failed parsing ssh_timeout: %s", err))
	}

	return errs
}

func (c *RunConfig) SSHTimeout() time.Duration {
	return c.sshTimeout
}
<commit_msg>Increase default SSH timeout for OpenStack from 1m -> 5m<commit_after>package openstack

import (
	"errors"
	"fmt"
	"github.com/mitchellh/packer/packer"
	"time"
)

// RunConfig contains configuration for running an instance from a source
// image and details on how to access that launched image.
type RunConfig struct {
	SourceImage   string `mapstructure:"source_image"`
	Flavor        string `mapstructure:"flavor"`
	RawSSHTimeout string `mapstructure:"ssh_timeout"`
	SSHUsername   string `mapstructure:"ssh_username"`
	SSHPort       int    `mapstructure:"ssh_port"`

	// Unexported fields that are calculated from others
	sshTimeout time.Duration
}

func (c *RunConfig) Prepare(t *packer.ConfigTemplate) []error {
	if t == nil {
		var err error
		t, err = packer.NewConfigTemplate()
		if err != nil {
			return []error{err}
		}
	}

	// Defaults
	if c.SSHUsername == "" {
		c.SSHUsername = "root"
	}

	if c.SSHPort == 0 {
		c.SSHPort = 22
	}

	if c.RawSSHTimeout == "" {
		c.RawSSHTimeout = "5m"
	}

	// Validation
	var err error
	errs := make([]error, 0)
	if c.SourceImage == "" {
		errs = append(errs, errors.New("A source_image must be specified"))
	}

	if c.Flavor == "" {
		errs = append(errs, errors.New("A flavor must be specified"))
	}

	if c.SSHUsername == "" {
		errs = append(errs, errors.New("An ssh_username must be specified"))
	}

	templates := map[string]*string{
		"flavlor":      &c.Flavor,
		"ssh_timeout":  &c.RawSSHTimeout,
		"ssh_username": &c.SSHUsername,
		"source_image": &c.SourceImage,
	}

	for n, ptr := range templates {
		var err error
		*ptr, err = t.Process(*ptr, nil)
		if err != nil {
			errs = append(
				errs, fmt.Errorf("Error processing %s: %s", n, err))
		}
	}

	c.sshTimeout, err = time.ParseDuration(c.RawSSHTimeout)
	if err != nil {
		errs = append(errs, fmt.Errorf("Failed parsing ssh_timeout: %s", err))
	}

	return errs
}

func (c *RunConfig) SSHTimeout() time.Duration {
	return c.sshTimeout
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"time"

	"github.com/hashicorp/terraform/helper/diff"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
	"github.com/mitchellh/goamz/ec2"
)

func resource_aws_internet_gateway_create(
	s *terraform.ResourceState,
	d *terraform.ResourceDiff,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	// Create the gateway
	log.Printf("[DEBUG] Creating internet gateway")
	resp, err := ec2conn.CreateInternetGateway(nil)
	if err != nil {
		return nil, fmt.Errorf("Error creating subnet: %s", err)
	}

	// Get the ID and store it
	ig := &resp.InternetGateway
	s.ID = ig.InternetGatewayId
	log.Printf("[INFO] InternetGateway ID: %s", s.ID)

	// Update our attributes and return
	return resource_aws_internet_gateway_update(s, d, meta)
}

func resource_aws_internet_gateway_update(
	s *terraform.ResourceState,
	d *terraform.ResourceDiff,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	// Merge the diff so we have the latest attributes
	rs := s.MergeDiff(d)

	// A note on the states below: the AWS docs (as of July, 2014) say
	// that the states would be: attached, attaching, detached, detaching,
	// but when running, I noticed that the state is usually "available" when
	// it is attached.

	// If we're already attached, detach it first
	if err := resource_aws_internet_gateway_detach(ec2conn, s); err != nil {
		return s, err
	}

	// Set the VPC ID to empty since we're detached at this point
	delete(rs.Attributes, "vpc_id")

	if attr, ok := d.Attributes["vpc_id"]; ok && attr.New != "" {
		err := resource_aws_internet_gateway_attach(ec2conn, s, attr.New)
		if err != nil {
			return s, err
		}

		rs.Attributes["vpc_id"] = attr.New
	}

	return resource_aws_internet_gateway_update_state(rs, nil)
}

func resource_aws_internet_gateway_destroy(
	s *terraform.ResourceState,
	meta interface{}) error {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	// Detach if it is attached
	if err := resource_aws_internet_gateway_detach(ec2conn, s); err != nil {
		return err
	}

	log.Printf("[INFO] Deleting Internet Gateway: %s", s.ID)
	if _, err := ec2conn.DeleteInternetGateway(s.ID); err != nil {
		ec2err, ok := err.(*ec2.Error)
		if ok && ec2err.Code == "InvalidInternetGatewayID.NotFound" {
			return nil
		}

		return fmt.Errorf("Error deleting internet gateway: %s", err)
	}

	// Wait for the internet gateway to actually delete
	log.Printf("[DEBUG] Waiting for internet gateway (%s) to delete", s.ID)
	stateConf := &resource.StateChangeConf{
		Pending: []string{"available"},
		Target:  "",
		Refresh: IGStateRefreshFunc(ec2conn, s.ID),
		Timeout: 10 * time.Minute,
	}
	if _, err := stateConf.WaitForState(); err != nil {
		return fmt.Errorf(
			"Error waiting for internet gateway (%s) to destroy",
			s.ID, err)
	}

	return nil
}

func resource_aws_internet_gateway_refresh(
	s *terraform.ResourceState,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	igRaw, _, err := IGStateRefreshFunc(ec2conn, s.ID)()
	if err != nil {
		return s, err
	}
	if igRaw == nil {
		return nil, nil
	}

	ig := igRaw.(*ec2.InternetGateway)
	return resource_aws_internet_gateway_update_state(s, ig)
}

func resource_aws_internet_gateway_diff(
	s *terraform.ResourceState,
	c *terraform.ResourceConfig,
	meta interface{}) (*terraform.ResourceDiff, error) {
	b := &diff.ResourceBuilder{
		Attrs: map[string]diff.AttrType{
			"vpc_id": diff.AttrTypeUpdate,
		},
	}

	return b.Diff(s, c)
}

func resource_aws_internet_gateway_attach(
	ec2conn *ec2.EC2,
	s *terraform.ResourceState,
	vpcId string) error {
	log.Printf(
		"[INFO] Attaching Internet Gateway '%s' to VPC '%s'",
		s.ID,
		vpcId)
	_, err := ec2conn.AttachInternetGateway(s.ID, vpcId)
	if err != nil {
		return err
	}

	// Wait for it to be fully attached before continuing
	log.Printf("[DEBUG] Waiting for internet gateway (%s) to attach", s.ID)
	stateConf := &resource.StateChangeConf{
		Pending: []string{"detached", "attaching"},
		Target:  "available",
		Refresh: IGAttachStateRefreshFunc(ec2conn, s.ID),
		Timeout: 1 * time.Minute,
	}
	if _, err := stateConf.WaitForState(); err != nil {
		return fmt.Errorf(
			"Error waiting for internet gateway (%s) to attach: %s",
			s.ID, err)
	}

	return nil
}

func resource_aws_internet_gateway_detach(
	ec2conn *ec2.EC2,
	s *terraform.ResourceState) error {
	if s.Attributes["vpc_id"] == "" {
		return nil
	}

	log.Printf(
		"[INFO] Detaching Internet Gateway '%s' from VPC '%s'",
		s.ID,
		s.Attributes["vpc_id"])
	_, err := ec2conn.DetachInternetGateway(s.ID, s.Attributes["vpc_id"])
	if err != nil {
		ec2err, ok := err.(*ec2.Error)
		if ok && ec2err.Code == "Gateway.NotAttached" {
			err = nil
		}

		if err != nil {
			return err
		}
	}

	delete(s.Attributes, "vpc_id")

	// Wait for it to be fully detached before continuing
	log.Printf("[DEBUG] Waiting for internet gateway (%s) to detach", s.ID)
	stateConf := &resource.StateChangeConf{
		Pending: []string{"attached", "detaching", "available"},
		Target:  "detached",
		Refresh: IGAttachStateRefreshFunc(ec2conn, s.ID),
		Timeout: 1 * time.Minute,
	}
	if _, err := stateConf.WaitForState(); err != nil {
		return fmt.Errorf(
			"Error waiting for internet gateway (%s) to detach: %s",
			s.ID, err)
	}

	return nil
}

func resource_aws_internet_gateway_update_state(
	s *terraform.ResourceState,
	ig *ec2.InternetGateway) (*terraform.ResourceState, error) {
	if s.Attributes["vpc_id"] != "" {
		// We belong to a VPC
		s.Dependencies = []terraform.ResourceDependency{
			terraform.ResourceDependency{ID: s.Attributes["vpc_id"]},
		}
	}

	return s, nil
}

// IGStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
// an internet gateway.
func IGStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		resp, err := conn.DescribeInternetGateways([]string{id}, ec2.NewFilter())
		if err != nil {
			ec2err, ok := err.(*ec2.Error)
			if ok && ec2err.Code == "InvalidInternetGatewayID.NotFound" {
				resp = nil
			} else {
				log.Printf("[ERROR] Error on IGStateRefresh: %s", err)
				return nil, "", err
			}
		}

		if resp == nil {
			// Sometimes AWS just has consistency issues and doesn't see
			// our instance yet. Return an empty state.
			return nil, "", nil
		}

		ig := &resp.InternetGateways[0]
		return ig, "available", nil
	}
}

// IGAttachStateRefreshFunc returns a resource.StateRefreshFunc that is used
// watch the state of an internet gateway's attachment.
func IGAttachStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		resp, err := conn.DescribeInternetGateways([]string{id}, ec2.NewFilter())
		if err != nil {
			ec2err, ok := err.(*ec2.Error)
			if ok && ec2err.Code == "InvalidInternetGatewayID.NotFound" {
				resp = nil
			} else {
				log.Printf("[ERROR] Error on IGStateRefresh: %s", err)
				return nil, "", err
			}
		}

		if resp == nil {
			// Sometimes AWS just has consistency issues and doesn't see
			// our instance yet. Return an empty state.
			return nil, "", nil
		}

		ig := &resp.InternetGateways[0]

		if len(ig.Attachments) == 0 {
			// No attachments, we're detached
			return ig, "detached", nil
		}

		return ig, ig.Attachments[0].State, nil
	}
}
<commit_msg>providers/aws: internet gateway delete is more flexible<commit_after>package aws

import (
	"fmt"
	"log"
	"time"

	"github.com/hashicorp/terraform/helper/diff"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
	"github.com/mitchellh/goamz/ec2"
)

func resource_aws_internet_gateway_create(
	s *terraform.ResourceState,
	d *terraform.ResourceDiff,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	// Create the gateway
	log.Printf("[DEBUG] Creating internet gateway")
	resp, err := ec2conn.CreateInternetGateway(nil)
	if err != nil {
		return nil, fmt.Errorf("Error creating subnet: %s", err)
	}

	// Get the ID and store it
	ig := &resp.InternetGateway
	s.ID = ig.InternetGatewayId
	log.Printf("[INFO] InternetGateway ID: %s", s.ID)

	// Update our attributes and return
	return resource_aws_internet_gateway_update(s, d, meta)
}

func resource_aws_internet_gateway_update(
	s *terraform.ResourceState,
	d *terraform.ResourceDiff,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	// Merge the diff so we have the latest attributes
	rs := s.MergeDiff(d)

	// A note on the states below: the AWS docs (as of July, 2014) say
	// that the states would be: attached, attaching, detached, detaching,
	// but when running, I noticed that the state is usually "available" when
	// it is attached.

	// If we're already attached, detach it first
	if err := resource_aws_internet_gateway_detach(ec2conn, s); err != nil {
		return s, err
	}

	// Set the VPC ID to empty since we're detached at this point
	delete(rs.Attributes, "vpc_id")

	if attr, ok := d.Attributes["vpc_id"]; ok && attr.New != "" {
		err := resource_aws_internet_gateway_attach(ec2conn, s, attr.New)
		if err != nil {
			return s, err
		}

		rs.Attributes["vpc_id"] = attr.New
	}

	return resource_aws_internet_gateway_update_state(rs, nil)
}

func resource_aws_internet_gateway_destroy(
	s *terraform.ResourceState,
	meta interface{}) error {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	// Detach if it is attached
	if err := resource_aws_internet_gateway_detach(ec2conn, s); err != nil {
		return err
	}

	log.Printf("[INFO] Deleting Internet Gateway: %s", s.ID)
	if _, err := ec2conn.DeleteInternetGateway(s.ID); err != nil {
		ec2err, ok := err.(*ec2.Error)
		if ok && ec2err.Code == "InvalidInternetGatewayID.NotFound" {
			return nil
		}

		return fmt.Errorf("Error deleting internet gateway: %s", err)
	}

	// Wait for the internet gateway to actually delete
	log.Printf("[DEBUG] Waiting for internet gateway (%s) to delete", s.ID)
	stateConf := &resource.StateChangeConf{
		Pending: []string{"available"},
		Target:  "",
		Refresh: IGStateRefreshFunc(ec2conn, s.ID),
		Timeout: 10 * time.Minute,
	}
	if _, err := stateConf.WaitForState(); err != nil {
		return fmt.Errorf(
			"Error waiting for internet gateway (%s) to destroy",
			s.ID, err)
	}

	return nil
}

func resource_aws_internet_gateway_refresh(
	s *terraform.ResourceState,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	igRaw, _, err := IGStateRefreshFunc(ec2conn, s.ID)()
	if err != nil {
		return s, err
	}
	if igRaw == nil {
		return nil, nil
	}

	ig := igRaw.(*ec2.InternetGateway)
	return resource_aws_internet_gateway_update_state(s, ig)
}

func resource_aws_internet_gateway_diff(
	s *terraform.ResourceState,
	c *terraform.ResourceConfig,
	meta interface{}) (*terraform.ResourceDiff, error) {
	b := &diff.ResourceBuilder{
		Attrs: map[string]diff.AttrType{
			"vpc_id": diff.AttrTypeUpdate,
		},
	}

	return b.Diff(s, c)
}

func resource_aws_internet_gateway_attach(
	ec2conn *ec2.EC2,
	s *terraform.ResourceState,
	vpcId string) error {
	log.Printf(
		"[INFO] Attaching Internet Gateway '%s' to VPC '%s'",
		s.ID,
		vpcId)
	_, err := ec2conn.AttachInternetGateway(s.ID, vpcId)
	if err != nil {
		return err
	}

	// Wait for it to be fully attached before continuing
	log.Printf("[DEBUG] Waiting for internet gateway (%s) to attach", s.ID)
	stateConf := &resource.StateChangeConf{
		Pending: []string{"detached", "attaching"},
		Target:  "available",
		Refresh: IGAttachStateRefreshFunc(ec2conn, s.ID),
		Timeout: 1 * time.Minute,
	}
	if _, err := stateConf.WaitForState(); err != nil {
		return fmt.Errorf(
			"Error waiting for internet gateway (%s) to attach: %s",
			s.ID, err)
	}

	return nil
}

func resource_aws_internet_gateway_detach(
	ec2conn *ec2.EC2,
	s *terraform.ResourceState) error {
	if s.Attributes["vpc_id"] == "" {
		return nil
	}

	log.Printf(
		"[INFO] Detaching Internet Gateway '%s' from VPC '%s'",
		s.ID,
		s.Attributes["vpc_id"])
	_, err := ec2conn.DetachInternetGateway(s.ID, s.Attributes["vpc_id"])
	if err != nil {
		ec2err, ok := err.(*ec2.Error)
		if ok {
			if ec2err.Code == "InvalidInternetGatewayID.NotFound" {
				err = nil
			} else if ec2err.Code == "Gateway.NotAttached" {
				err = nil
			}
		}

		if err != nil {
			return err
		}
	}

	delete(s.Attributes, "vpc_id")

	// Wait for it to be fully detached before continuing
	log.Printf("[DEBUG] Waiting for internet gateway (%s) to detach", s.ID)
	stateConf := &resource.StateChangeConf{
		Pending: []string{"attached", "detaching", "available"},
		Target:  "detached",
		Refresh: IGAttachStateRefreshFunc(ec2conn, s.ID),
		Timeout: 1 * time.Minute,
	}
	if _, err := stateConf.WaitForState(); err != nil {
		return fmt.Errorf(
			"Error waiting for internet gateway (%s) to detach: %s",
			s.ID, err)
	}

	return nil
}

func resource_aws_internet_gateway_update_state(
	s *terraform.ResourceState,
	ig *ec2.InternetGateway) (*terraform.ResourceState, error) {
	if s.Attributes["vpc_id"] != "" {
		// We belong to a VPC
		s.Dependencies = []terraform.ResourceDependency{
			terraform.ResourceDependency{ID: s.Attributes["vpc_id"]},
		}
	}

	return s, nil
}

// IGStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
// an internet gateway.
func IGStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		resp, err := conn.DescribeInternetGateways([]string{id}, ec2.NewFilter())
		if err != nil {
			ec2err, ok := err.(*ec2.Error)
			if ok && ec2err.Code == "InvalidInternetGatewayID.NotFound" {
				resp = nil
			} else {
				log.Printf("[ERROR] Error on IGStateRefresh: %s", err)
				return nil, "", err
			}
		}

		if resp == nil {
			// Sometimes AWS just has consistency issues and doesn't see
			// our instance yet. Return an empty state.
			return nil, "", nil
		}

		ig := &resp.InternetGateways[0]
		return ig, "available", nil
	}
}

// IGAttachStateRefreshFunc returns a resource.StateRefreshFunc that is used
// watch the state of an internet gateway's attachment.
func IGAttachStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		resp, err := conn.DescribeInternetGateways([]string{id}, ec2.NewFilter())
		if err != nil {
			ec2err, ok := err.(*ec2.Error)
			if ok && ec2err.Code == "InvalidInternetGatewayID.NotFound" {
				resp = nil
			} else {
				log.Printf("[ERROR] Error on IGStateRefresh: %s", err)
				return nil, "", err
			}
		}

		if resp == nil {
			// Sometimes AWS just has consistency issues and doesn't see
			// our instance yet. Return an empty state.
			return nil, "", nil
		}

		ig := &resp.InternetGateways[0]

		if len(ig.Attachments) == 0 {
			// No attachments, we're detached
			return ig, "detached", nil
		}

		return ig, ig.Attachments[0].State, nil
	}
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"strings"

	"github.com/hashicorp/vault/logical"
	"github.com/hashicorp/vault/logical/framework"
)

func pathSTS(b *backend) *framework.Path {
	return &framework.Path{
		Pattern: "sts/" + framework.GenericNameRegex("name"),
		Fields: map[string]*framework.FieldSchema{
			"name": &framework.FieldSchema{
				Type:        framework.TypeString,
				Description: "Name of the role",
			},
			"ttl": &framework.FieldSchema{
				Type: framework.TypeDurationSecond,
				Description: `Lifetime of the token in seconds.
AWS documentation excerpt: The duration, in seconds, that the credentials
should remain valid. Acceptable durations for IAM user sessions range from 900
seconds (15 minutes) to 129600 seconds (36 hours), with 43200 seconds (12
hours) as the default. Sessions for AWS account owners are restricted to a
maximum of 3600 seconds (one hour). If the duration is longer than one hour,
the session for AWS account owners defaults to one hour.`,
				Default: 3600,
			},
		},

		Callbacks: map[logical.Operation]framework.OperationFunc{
			logical.ReadOperation:   b.pathSTSRead,
			logical.UpdateOperation: b.pathSTSRead,
		},

		HelpSynopsis:    pathSTSHelpSyn,
		HelpDescription: pathSTSHelpDesc,
	}
}

func (b *backend) pathSTSRead(
	req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
	policyName := d.Get("name").(string)
	ttl := int64(d.Get("ttl").(int))

	// Read the policy
	policy, err := req.Storage.Get("policy/" + policyName)
	if err != nil {
		return nil, fmt.Errorf("error retrieving role: %s", err)
	}
	if policy == nil {
		return logical.ErrorResponse(fmt.Sprintf(
			"Role '%s' not found", policyName)), nil
	}
	policyValue := string(policy.Value)
	if strings.HasPrefix(policyValue, "arn:") {
		if strings.Contains(policyValue, ":role/") {
			return b.assumeRole(
				req.Storage,
				req.DisplayName, policyName, policyValue,
				ttl,
			)
		} else {
			return logical.ErrorResponse(
					"Can't generate STS credentials for a managed policy; use a role to assume or an inline policy instead"),
				logical.ErrInvalidRequest
		}
	}
	// Use the helper to create the secret
	return b.secretTokenCreate(
		req.Storage,
		req.DisplayName, policyName, policyValue,
		ttl,
	)
}

const pathSTSHelpSyn = `
Generate an access key pair + security token for a specific role.
`

const pathSTSHelpDesc = `
This path will generate a new, never before used key pair + security token for
accessing AWS. The IAM policy used to back this key pair will be
the "name" parameter. For example, if this backend is mounted at "aws",
then "aws/sts/deploy" would generate access keys for the "deploy" role.

Note, these credentials are instantiated using the AWS STS backend.

The access keys will have a lease associated with them. The access keys
can be revoked by using the lease ID.
`
<commit_msg>Document that AWS STS lease revocation is a no-op [fixes #3736] (#3760)<commit_after>package aws

import (
	"fmt"
	"strings"

	"github.com/hashicorp/vault/logical"
	"github.com/hashicorp/vault/logical/framework"
)

func pathSTS(b *backend) *framework.Path {
	return &framework.Path{
		Pattern: "sts/" + framework.GenericNameRegex("name"),
		Fields: map[string]*framework.FieldSchema{
			"name": &framework.FieldSchema{
				Type:        framework.TypeString,
				Description: "Name of the role",
			},
			"ttl": &framework.FieldSchema{
				Type: framework.TypeDurationSecond,
				Description: `Lifetime of the token in seconds.
AWS documentation excerpt: The duration, in seconds, that the credentials
should remain valid. Acceptable durations for IAM user sessions range from 900
seconds (15 minutes) to 129600 seconds (36 hours), with 43200 seconds (12
hours) as the default. Sessions for AWS account owners are restricted to a
maximum of 3600 seconds (one hour). If the duration is longer than one hour,
the session for AWS account owners defaults to one hour.`,
				Default: 3600,
			},
		},

		Callbacks: map[logical.Operation]framework.OperationFunc{
			logical.ReadOperation:   b.pathSTSRead,
			logical.UpdateOperation: b.pathSTSRead,
		},

		HelpSynopsis:    pathSTSHelpSyn,
		HelpDescription: pathSTSHelpDesc,
	}
}

func (b *backend) pathSTSRead(
	req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
	policyName := d.Get("name").(string)
	ttl := int64(d.Get("ttl").(int))

	// Read the policy
	policy, err := req.Storage.Get("policy/" + policyName)
	if err != nil {
		return nil, fmt.Errorf("error retrieving role: %s", err)
	}
	if policy == nil {
		return logical.ErrorResponse(fmt.Sprintf(
			"Role '%s' not found", policyName)), nil
	}
	policyValue := string(policy.Value)
	if strings.HasPrefix(policyValue, "arn:") {
		if strings.Contains(policyValue, ":role/") {
			return b.assumeRole(
				req.Storage,
				req.DisplayName, policyName, policyValue,
				ttl,
			)
		} else {
			return logical.ErrorResponse(
					"Can't generate STS credentials for a managed policy; use a role to assume or an inline policy instead"),
				logical.ErrInvalidRequest
		}
	}
	// Use the helper to create the secret
	return b.secretTokenCreate(
		req.Storage,
		req.DisplayName, policyName, policyValue,
		ttl,
	)
}

const pathSTSHelpSyn = `
Generate an access key pair + security token for a specific role.
`

const pathSTSHelpDesc = `
This path will generate a new, never before used key pair + security token for
accessing AWS. The IAM policy used to back this key pair will be
the "name" parameter. For example, if this backend is mounted at "aws",
then "aws/sts/deploy" would generate access keys for the "deploy" role.

Note, these credentials are instantiated using the AWS STS backend.

The access keys will have a lease associated with them, but revoking the lease
does not revoke the access keys.
`
<|endoftext|>