<commit_before>// Copyright 2014 Hajime Hoshi
//
// 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.

// +build ignore

package main

import (
	"fmt"
	"html/template"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"time"
)

var license = ""

func init() {
	b, err := ioutil.ReadFile("../license.txt")
	if err != nil {
		panic(err)
	}
	license = strings.TrimSpace(string(b))

	year, err := strconv.Atoi(regexp.MustCompile(`^Copyright (\d+)`).FindStringSubmatch(license)[1])
	if err != nil {
		panic(err)
	}
	if year != time.Now().Year() {
		panic("the license's year is not this year")
	}
}

var copyright = ""

func init() {
	copyright = fmt.Sprintf("© %d Hajime Hoshi", time.Now().Year())
}

var stableVersion = ""
var devVersion = ""

func init() {
	b, err := ioutil.ReadFile("../version.txt")
	if err != nil {
		panic(err)
	}
	stableVersion = strings.TrimSpace(string(b))
}

func currentBranch() string {
	r, err := ioutil.ReadFile("../.git/HEAD")
	if err != nil {
		panic(err)
	}
	rr := strings.TrimSpace(string(r))
	return regexp.MustCompile(`^ref: refs/heads/(.+)$`).FindStringSubmatch(rr)[1]
}

func init() {
	b, err := exec.Command("git", "show", "master:version.txt").Output()
	if err != nil {
		panic(err)
	}
	devVersion = strings.TrimSpace(string(b))
}

func comment(text string) template.HTML {
	// TODO: text should be escaped
	return template.HTML("<!--\n" + text + "\n-->")
}

func safeHTML(text string) template.HTML {
	return template.HTML(text)
}

type example struct {
	Name string
}

func (e *example) ThumbWidth() int {
	if e.Name == "blocks" {
		return 256
	}
	return 320
}

func (e *example) ThumbHeight() int {
	if e.Name == "blocks" {
		return 240
	}
	return 240
}

func (e *example) Width() int {
	return e.ThumbWidth() * 2
}

func (e *example) Height() int {
	return e.ThumbHeight() * 2
}

func (e *example) Source() string {
	if e.Name == "blocks" {
		return "// Please read example/blocks/main.go and example/blocks/blocks/*.go"
	}

	path := filepath.Join(os.Getenv("GOPATH"), "src", "github.com", "hajimehoshi", "ebiten", "example", e.Name, "main.go")
	b, err := ioutil.ReadFile(path)
	if err != nil {
		panic(err)
	}
	str := regexp.MustCompile("(?s)^.*?\n\n").ReplaceAllString(string(b), "")
	str = strings.Replace(str, "\t", "    ", -1)
	return str
}

func versions() string {
	return fmt.Sprintf("v%s (dev: v%s)", stableVersion, devVersion)
}

var examples = []example{
	{Name: "hue"},
	{Name: "keyboard"},
	{Name: "mosaic"},
	{Name: "paint"},
	{Name: "perspective"},
	{Name: "rotate"},
	{Name: "blocks"},
}

func clear() error {
	if err := filepath.Walk("public", func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if m, _ := regexp.MatchString("~$", path); m {
			return nil
		}
		// Remove auto-generated html files.
		m, err := regexp.MatchString(".html$", path)
		if err != nil {
			return err
		}
		if m {
			return os.Remove(path)
		}
		// Remove example resources that are copied.
		m, err = regexp.MatchString("^public/example/images$", path)
		if err != nil {
			return err
		}
		if m {
			if err := os.RemoveAll(path); err != nil {
				return err
			}
			return filepath.SkipDir
		}
		return nil
	}); err != nil {
		return err
	}
	return nil
}

func outputMain() error {
	f, err := os.Create("public/index.html")
	if err != nil {
		return err
	}
	defer f.Close()

	funcs := template.FuncMap{
		"comment":  comment,
		"safeHTML": safeHTML,
	}
	const templatePath = "index.tmpl.html"
	name := filepath.Base(templatePath)
	t, err := template.New(name).Funcs(funcs).ParseFiles(templatePath)
	if err != nil {
		return err
	}

	data := map[string]interface{}{
		"License":       license,
		"Copyright":     copyright,
		"StableVersion": stableVersion,
		"DevVersion":    devVersion,
		"Examples":      examples,
	}
	return t.Funcs(funcs).Execute(f, data)
}

func outputExampleContent(e *example) error {
	const dir = "public/example"
	if err := os.MkdirAll(dir, 0755); err != nil {
		return err
	}
	f, err := os.Create(filepath.Join(dir, e.Name+".content.html"))
	if err != nil {
		return err
	}
	defer f.Close()

	funcs := template.FuncMap{
		"comment":  comment,
		"safeHTML": safeHTML,
	}
	const templatePath = "examplecontent.tmpl.html"
	name := filepath.Base(templatePath)
	t, err := template.New(name).Funcs(funcs).ParseFiles(templatePath)
	if err != nil {
		return err
	}

	data := map[string]interface{}{
		"License":       license,
		"Copyright":     copyright,
		"CurrentBranch": currentBranch(),
		"Example":       e,
	}
	if err := t.Funcs(funcs).Execute(f, data); err != nil {
		return err
	}

	out := filepath.Join(dir, e.Name+".js")
	path := "github.com/hajimehoshi/ebiten/example/" + e.Name
	if err := exec.Command("gopherjs", "build", "-m", "-o", out, path).Run(); err != nil {
		return err
	}

	return nil
}

func outputExample(e *example) error {
	const dir = "public/example"
	if err := os.MkdirAll(dir, 0755); err != nil {
		return err
	}
	f, err := os.Create(filepath.Join(dir, e.Name+".html"))
	if err != nil {
		return err
	}
	defer f.Close()

	funcs := template.FuncMap{
		"comment":  comment,
		"safeHTML": safeHTML,
	}
	const templatePath = "example.tmpl.html"
	name := filepath.Base(templatePath)
	t, err := template.New(name).Funcs(funcs).ParseFiles(templatePath)
	if err != nil {
		return err
	}

	data := map[string]interface{}{
		"License":   license,
		"Copyright": copyright,
		"Example":   e,
	}
	return t.Funcs(funcs).Execute(f, data)
}

func main() {
	if err := clear(); err != nil {
		log.Fatal(err)
	}
	if err := outputMain(); err != nil {
		log.Fatal(err)
	}
	for _, e := range examples {
		if err := outputExampleContent(&e); err != nil {
			log.Fatal(err)
		}
		if err := outputExample(&e); err != nil {
			log.Fatal(err)
		}
	}
}
<commit_msg>doc: Escape HTML comments properly<commit_after>// Copyright 2014 Hajime Hoshi
//
// 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.

// +build ignore

package main

import (
	"fmt"
	"html/template"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"time"
)

var license = ""

func init() {
	b, err := ioutil.ReadFile("../license.txt")
	if err != nil {
		panic(err)
	}
	license = strings.TrimSpace(string(b))

	year, err := strconv.Atoi(regexp.MustCompile(`^Copyright (\d+)`).FindStringSubmatch(license)[1])
	if err != nil {
		panic(err)
	}
	if year != time.Now().Year() {
		panic("the license's year is not this year")
	}
}

var copyright = ""

func init() {
	copyright = fmt.Sprintf("© %d Hajime Hoshi", time.Now().Year())
}

var stableVersion = ""
var devVersion = ""

func init() {
	b, err := ioutil.ReadFile("../version.txt")
	if err != nil {
		panic(err)
	}
	stableVersion = strings.TrimSpace(string(b))
}

func currentBranch() string {
	r, err := ioutil.ReadFile("../.git/HEAD")
	if err != nil {
		panic(err)
	}
	rr := strings.TrimSpace(string(r))
	return regexp.MustCompile(`^ref: refs/heads/(.+)$`).FindStringSubmatch(rr)[1]
}

func init() {
	b, err := exec.Command("git", "show", "master:version.txt").Output()
	if err != nil {
		panic(err)
	}
	devVersion = strings.TrimSpace(string(b))
}

func comment(text string) template.HTML {
	// http://www.w3.org/TR/html-markup/syntax.html#comments
	// The text part of comments has the following restrictions:
	// * must not start with a ">" character
	// * must not start with the string "->"
	// * must not contain the string "--"
	// * must not end with a "-" character

	for strings.HasPrefix(text, ">") {
		text = text[1:]
	}
	for strings.HasPrefix(text, "->") {
		text = text[2:]
	}
	text = strings.Replace(text, "--", "", -1)
	for strings.HasSuffix(text, "-") {
		text = text[:len(text)-1]
	}
	return template.HTML("<!--\n" + text + "\n-->")
}

func safeHTML(text string) template.HTML {
	return template.HTML(text)
}

type example struct {
	Name string
}

func (e *example) ThumbWidth() int {
	if e.Name == "blocks" {
		return 256
	}
	return 320
}

func (e *example) ThumbHeight() int {
	if e.Name == "blocks" {
		return 240
	}
	return 240
}

func (e *example) Width() int {
	return e.ThumbWidth() * 2
}

func (e *example) Height() int {
	return e.ThumbHeight() * 2
}

func (e *example) Source() string {
	if e.Name == "blocks" {
		return "// Please read example/blocks/main.go and example/blocks/blocks/*.go"
	}

	path := filepath.Join(os.Getenv("GOPATH"), "src", "github.com", "hajimehoshi", "ebiten", "example", e.Name, "main.go")
	b, err := ioutil.ReadFile(path)
	if err != nil {
		panic(err)
	}
	str := regexp.MustCompile("(?s)^.*?\n\n").ReplaceAllString(string(b), "")
	str = strings.Replace(str, "\t", "    ", -1)
	return str
}

func versions() string {
	return fmt.Sprintf("v%s (dev: v%s)", stableVersion, devVersion)
}

var examples = []example{
	{Name: "hue"},
	{Name: "keyboard"},
	{Name: "mosaic"},
	{Name: "paint"},
	{Name: "perspective"},
	{Name: "rotate"},
	{Name: "blocks"},
}

func clear() error {
	if err := filepath.Walk("public", func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if m, _ := regexp.MatchString("~$", path); m {
			return nil
		}
		// Remove auto-generated html files.
		m, err := regexp.MatchString(".html$", path)
		if err != nil {
			return err
		}
		if m {
			return os.Remove(path)
		}
		// Remove example resources that are copied.
		m, err = regexp.MatchString("^public/example/images$", path)
		if err != nil {
			return err
		}
		if m {
			if err := os.RemoveAll(path); err != nil {
				return err
			}
			return filepath.SkipDir
		}
		return nil
	}); err != nil {
		return err
	}
	return nil
}

func outputMain() error {
	f, err := os.Create("public/index.html")
	if err != nil {
		return err
	}
	defer f.Close()

	funcs := template.FuncMap{
		"comment":  comment,
		"safeHTML": safeHTML,
	}
	const templatePath = "index.tmpl.html"
	name := filepath.Base(templatePath)
	t, err := template.New(name).Funcs(funcs).ParseFiles(templatePath)
	if err != nil {
		return err
	}

	data := map[string]interface{}{
		"License":       license,
		"Copyright":     copyright,
		"StableVersion": stableVersion,
		"DevVersion":    devVersion,
		"Examples":      examples,
	}
	return t.Funcs(funcs).Execute(f, data)
}

func outputExampleContent(e *example) error {
	const dir = "public/example"
	if err := os.MkdirAll(dir, 0755); err != nil {
		return err
	}
	f, err := os.Create(filepath.Join(dir, e.Name+".content.html"))
	if err != nil {
		return err
	}
	defer f.Close()

	funcs := template.FuncMap{
		"comment":  comment,
		"safeHTML": safeHTML,
	}
	const templatePath = "examplecontent.tmpl.html"
	name := filepath.Base(templatePath)
	t, err := template.New(name).Funcs(funcs).ParseFiles(templatePath)
	if err != nil {
		return err
	}

	data := map[string]interface{}{
		"License":       license,
		"Copyright":     copyright,
		"CurrentBranch": currentBranch(),
		"Example":       e,
	}
	if err := t.Funcs(funcs).Execute(f, data); err != nil {
		return err
	}

	out := filepath.Join(dir, e.Name+".js")
	path := "github.com/hajimehoshi/ebiten/example/" + e.Name
	if err := exec.Command("gopherjs", "build", "-m", "-o", out, path).Run(); err != nil {
		return err
	}

	return nil
}

func outputExample(e *example) error {
	const dir = "public/example"
	if err := os.MkdirAll(dir, 0755); err != nil {
		return err
	}
	f, err := os.Create(filepath.Join(dir, e.Name+".html"))
	if err != nil {
		return err
	}
	defer f.Close()

	funcs := template.FuncMap{
		"comment":  comment,
		"safeHTML": safeHTML,
	}
	const templatePath = "example.tmpl.html"
	name := filepath.Base(templatePath)
	t, err := template.New(name).Funcs(funcs).ParseFiles(templatePath)
	if err != nil {
		return err
	}

	data := map[string]interface{}{
		"License":   license,
		"Copyright": copyright,
		"Example":   e,
	}
	return t.Funcs(funcs).Execute(f, data)
}

func main() {
	if err := clear(); err != nil {
		log.Fatal(err)
	}
	if err := outputMain(); err != nil {
		log.Fatal(err)
	}
	for _, e := range examples {
		if err := outputExampleContent(&e); err != nil {
			log.Fatal(err)
		}
		if err := outputExample(&e); err != nil {
			log.Fatal(err)
		}
	}
}
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements.  See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You 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 exec

import (
	"context"
	"fmt"
	"path"

	"github.com/apache/beam/sdks/go/pkg/beam/core/funcx"
	"github.com/apache/beam/sdks/go/pkg/beam/core/graph"
	"github.com/apache/beam/sdks/go/pkg/beam/core/graph/mtime"
	"github.com/apache/beam/sdks/go/pkg/beam/core/graph/window"
	"github.com/apache/beam/sdks/go/pkg/beam/core/metrics"
	"github.com/apache/beam/sdks/go/pkg/beam/core/typex"
	"github.com/apache/beam/sdks/go/pkg/beam/internal/errors"
	"github.com/apache/beam/sdks/go/pkg/beam/util/errorx"
)

// ParDo is a DoFn executor.
type ParDo struct {
	UID     UnitID
	Fn      *graph.DoFn
	Inbound []*graph.Inbound
	Side    []SideInputAdapter
	Out     []Node

	PID      string
	emitters []ReusableEmitter
	ctx      context.Context
	inv      *invoker

	side  StateReader
	cache *cacheElm

	status Status
	err    errorx.GuardedError
}

// GetPID returns the PTransformID for this ParDo.
func (n *ParDo) GetPID() string {
	return n.PID
}

// cacheElm holds per-window cached information about side input.
type cacheElm struct {
	key       typex.Window
	sideinput []ReusableInput
	extra     []interface{}
}

// ID returns the UnitID for this ParDo.
func (n *ParDo) ID() UnitID {
	return n.UID
}

// Up initializes this ParDo and does one-time DoFn setup.
func (n *ParDo) Up(ctx context.Context) error {
	if n.status != Initializing {
		return errors.Errorf("invalid status for pardo %v: %v, want Initializing", n.UID, n.status)
	}
	n.status = Up
	n.inv = newInvoker(n.Fn.ProcessElementFn())

	if _, err := InvokeWithoutEventTime(ctx, n.Fn.SetupFn(), nil); err != nil {
		return n.fail(err)
	}

	emitters, err := makeEmitters(n.Fn.ProcessElementFn(), n.Out)
	if err != nil {
		return n.fail(err)
	}
	n.emitters = emitters
	return nil
}

// StartBundle does pre-bundle processing operation for the DoFn.
func (n *ParDo) StartBundle(ctx context.Context, id string, data DataContext) error {
	if n.status != Up {
		return errors.Errorf("invalid status for pardo %v: %v, want Up", n.UID, n.status)
	}
	n.status = Active
	n.side = data.State
	// Allocating contexts all the time is expensive, but we seldom re-write them,
	// and never accept modified contexts from users, so we will cache them per-bundle
	// per-unit, to avoid the constant allocation overhead.
	n.ctx = metrics.SetPTransformID(ctx, n.PID)

	if err := MultiStartBundle(n.ctx, id, data, n.Out...); err != nil {
		return n.fail(err)
	}

	// TODO(BEAM-3303): what to set for StartBundle/FinishBundle window and emitter timestamp?

	if _, err := n.invokeDataFn(n.ctx, window.SingleGlobalWindow, mtime.ZeroTimestamp, n.Fn.StartBundleFn(), nil); err != nil {
		return n.fail(err)
	}
	return nil
}

// ProcessElement processes each parallel element with the DoFn.
func (n *ParDo) ProcessElement(ctx context.Context, elm *FullValue, values ...ReStream) error {
	if n.status != Active {
		return errors.Errorf("invalid status for pardo %v: %v, want Active", n.UID, n.status)
	}
	// If the function observes windows, we must invoke it for each window. The expected fast path
	// is that either there is a single window or the function doesn't observes windows.

	if !mustExplodeWindows(n.inv.fn, elm, len(n.Side) > 0) {
		val, err := n.invokeProcessFn(n.ctx, elm.Windows, elm.Timestamp, &MainInput{Key: *elm, Values: values})
		if err != nil {
			return n.fail(err)
		}

		// Forward direct output, if any. It is always a main output.
		if val != nil {
			return n.Out[0].ProcessElement(n.ctx, val)
		}
	} else {
		for _, w := range elm.Windows {
			wElm := FullValue{Elm: elm.Elm, Elm2: elm.Elm2, Timestamp: elm.Timestamp, Windows: []typex.Window{w}}

			val, err := n.invokeProcessFn(n.ctx, wElm.Windows, wElm.Timestamp, &MainInput{Key: wElm, Values: values})
			if err != nil {
				return n.fail(err)
			}

			// Forward direct output, if any. It is always a main output.
			if val != nil {
				return n.Out[0].ProcessElement(n.ctx, val)
			}
		}
	}
	return nil
}

// mustExplodeWindows returns true iif we need to call the function
// for each window. It is needed if the function either observes the
// window, either directly or indirectly via (windowed) side inputs.
func mustExplodeWindows(fn *funcx.Fn, elm *FullValue, usesSideInput bool) bool {
	if len(elm.Windows) < 2 {
		return false
	}
	_, explode := fn.Window()
	return explode || usesSideInput
}

// FinishBundle does post-bundle processing operations for the DoFn.
// Note: This is not a "FinalizeBundle" operation. Data is not yet durably
// persisted at this point.
func (n *ParDo) FinishBundle(ctx context.Context) error {
	if n.status != Active {
		return errors.Errorf("invalid status for pardo %v: %v, want Active", n.UID, n.status)
	}
	n.status = Up
	n.inv.Reset()

	if _, err := n.invokeDataFn(n.ctx, window.SingleGlobalWindow, mtime.ZeroTimestamp, n.Fn.FinishBundleFn(), nil); err != nil {
		return n.fail(err)
	}
	n.side = nil
	n.cache = nil

	if err := MultiFinishBundle(n.ctx, n.Out...); err != nil {
		return n.fail(err)
	}
	return nil
}

// Down performs best-effort teardown of DoFn resources. (May not run.)
func (n *ParDo) Down(ctx context.Context) error {
	if n.status == Down {
		return n.err.Error()
	}
	n.status = Down
	n.side = nil
	n.cache = nil

	if _, err := InvokeWithoutEventTime(ctx, n.Fn.TeardownFn(), nil); err != nil {
		n.err.TrySetError(err)
	}
	return n.err.Error()
}

func (n *ParDo) initSideInput(ctx context.Context, w typex.Window) error {
	if n.cache == nil {
		// First time: init single-element cache. We know that side input
		// must come before emitters in the signature.

		sideCount := len(n.Side)
		emitCount := len(n.emitters)

		n.cache = &cacheElm{
			key:   w,
			extra: make([]interface{}, sideCount+emitCount, sideCount+emitCount),
		}
		for i, emit := range n.emitters {
			n.cache.extra[i+sideCount] = emit.Value()
		}
	} else if w.Equals(n.cache.key) {
		// Fast path: same window. Just unwind the side inputs.

		for _, s := range n.cache.sideinput {
			if err := s.Init(); err != nil {
				return err
			}
		}
		return nil
	}

	// Slow path: init side input for the given window

	streams := make([]ReStream, len(n.Side), len(n.Side))
	for i, adapter := range n.Side {
		s, err := adapter.NewIterable(ctx, n.side, w)
		if err != nil {
			return err
		}
		streams[i] = s
	}

	sideinput, err := makeSideInputs(n.Fn.ProcessElementFn(), n.Inbound, streams)
	if err != nil {
		return err
	}
	n.cache.sideinput = sideinput
	for i := 0; i < len(n.Side); i++ {
		n.cache.extra[i] = sideinput[i].Value()
	}

	for _, s := range n.cache.sideinput {
		if err := s.Init(); err != nil {
			return err
		}
	}
	return nil
}

// invokeDataFn handle non-per element invocations.
func (n *ParDo) invokeDataFn(ctx context.Context, ws []typex.Window, ts typex.EventTime, fn *funcx.Fn, opt *MainInput) (*FullValue, error) {
	if fn == nil {
		return nil, nil
	}
	if err := n.preInvoke(ctx, ws, ts); err != nil {
		return nil, err
	}
	val, err := Invoke(ctx, ws, ts, fn, opt, n.cache.extra...)
	if err != nil {
		return nil, err
	}
	if err := n.postInvoke(); err != nil {
		return nil, err
	}
	return val, nil
}

// invokeProcessFn handles the per element invocations
func (n *ParDo) invokeProcessFn(ctx context.Context, ws []typex.Window, ts typex.EventTime, opt *MainInput) (*FullValue, error) {
	if err := n.preInvoke(ctx, ws, ts); err != nil {
		return nil, err
	}
	val, err := n.inv.Invoke(ctx, ws, ts, opt, n.cache.extra...)
	if err != nil {
		return nil, err
	}
	if err := n.postInvoke(); err != nil {
		return nil, err
	}
	return val, nil
}

func (n *ParDo) preInvoke(ctx context.Context, ws []typex.Window, ts typex.EventTime) error {
	for _, e := range n.emitters {
		if err := e.Init(ctx, ws, ts); err != nil {
			return err
		}
	}
	return n.initSideInput(ctx, ws[0])
}

func (n *ParDo) postInvoke() error {
	for _, s := range n.cache.sideinput {
		if err := s.Reset(); err != nil {
			return err
		}
	}
	return nil
}

func (n *ParDo) fail(err error) error {
	n.status = Broken
	n.err.TrySetError(err)
	return err
}

func (n *ParDo) String() string {
	return fmt.Sprintf("ParDo[%v] Out:%v", path.Base(n.Fn.Name()), IDs(n.Out...))
}
<commit_msg>[BEAM-9667] Allow metrics in DoFn Setup (#11287)<commit_after>// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements.  See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You 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 exec

import (
	"context"
	"fmt"
	"path"

	"github.com/apache/beam/sdks/go/pkg/beam/core/funcx"
	"github.com/apache/beam/sdks/go/pkg/beam/core/graph"
	"github.com/apache/beam/sdks/go/pkg/beam/core/graph/mtime"
	"github.com/apache/beam/sdks/go/pkg/beam/core/graph/window"
	"github.com/apache/beam/sdks/go/pkg/beam/core/metrics"
	"github.com/apache/beam/sdks/go/pkg/beam/core/typex"
	"github.com/apache/beam/sdks/go/pkg/beam/internal/errors"
	"github.com/apache/beam/sdks/go/pkg/beam/util/errorx"
)

// ParDo is a DoFn executor.
type ParDo struct {
	UID     UnitID
	Fn      *graph.DoFn
	Inbound []*graph.Inbound
	Side    []SideInputAdapter
	Out     []Node

	PID      string
	emitters []ReusableEmitter
	ctx      context.Context
	inv      *invoker

	side  StateReader
	cache *cacheElm

	status Status
	err    errorx.GuardedError
}

// GetPID returns the PTransformID for this ParDo.
func (n *ParDo) GetPID() string {
	return n.PID
}

// cacheElm holds per-window cached information about side input.
type cacheElm struct {
	key       typex.Window
	sideinput []ReusableInput
	extra     []interface{}
}

// ID returns the UnitID for this ParDo.
func (n *ParDo) ID() UnitID {
	return n.UID
}

// Up initializes this ParDo and does one-time DoFn setup.
func (n *ParDo) Up(ctx context.Context) error {
	if n.status != Initializing {
		return errors.Errorf("invalid status for pardo %v: %v, want Initializing", n.UID, n.status)
	}
	n.status = Up
	n.inv = newInvoker(n.Fn.ProcessElementFn())

	// We can't cache the context during Setup since it runs only once per bundle.
	// Subsequent bundles might run this same node, and the context here would be
	// incorrectly refering to the older bundleId.
	setupCtx :=  metrics.SetPTransformID(ctx, n.PID)
	if _, err := InvokeWithoutEventTime(setupCtx, n.Fn.SetupFn(), nil); err != nil {
		return n.fail(err)
	}

	emitters, err := makeEmitters(n.Fn.ProcessElementFn(), n.Out)
	if err != nil {
		return n.fail(err)
	}
	n.emitters = emitters
	return nil
}

// StartBundle does pre-bundle processing operation for the DoFn.
func (n *ParDo) StartBundle(ctx context.Context, id string, data DataContext) error {
	if n.status != Up {
		return errors.Errorf("invalid status for pardo %v: %v, want Up", n.UID, n.status)
	}
	n.status = Active
	n.side = data.State
	// Allocating contexts all the time is expensive, but we seldom re-write them,
	// and never accept modified contexts from users, so we will cache them per-bundle
	// per-unit, to avoid the constant allocation overhead.
	n.ctx = metrics.SetPTransformID(ctx, n.PID)

	if err := MultiStartBundle(n.ctx, id, data, n.Out...); err != nil {
		return n.fail(err)
	}

	// TODO(BEAM-3303): what to set for StartBundle/FinishBundle window and emitter timestamp?

	if _, err := n.invokeDataFn(n.ctx, window.SingleGlobalWindow, mtime.ZeroTimestamp, n.Fn.StartBundleFn(), nil); err != nil {
		return n.fail(err)
	}
	return nil
}

// ProcessElement processes each parallel element with the DoFn.
func (n *ParDo) ProcessElement(ctx context.Context, elm *FullValue, values ...ReStream) error {
	if n.status != Active {
		return errors.Errorf("invalid status for pardo %v: %v, want Active", n.UID, n.status)
	}
	// If the function observes windows, we must invoke it for each window. The expected fast path
	// is that either there is a single window or the function doesn't observes windows.

	if !mustExplodeWindows(n.inv.fn, elm, len(n.Side) > 0) {
		val, err := n.invokeProcessFn(n.ctx, elm.Windows, elm.Timestamp, &MainInput{Key: *elm, Values: values})
		if err != nil {
			return n.fail(err)
		}

		// Forward direct output, if any. It is always a main output.
		if val != nil {
			return n.Out[0].ProcessElement(n.ctx, val)
		}
	} else {
		for _, w := range elm.Windows {
			wElm := FullValue{Elm: elm.Elm, Elm2: elm.Elm2, Timestamp: elm.Timestamp, Windows: []typex.Window{w}}

			val, err := n.invokeProcessFn(n.ctx, wElm.Windows, wElm.Timestamp, &MainInput{Key: wElm, Values: values})
			if err != nil {
				return n.fail(err)
			}

			// Forward direct output, if any. It is always a main output.
			if val != nil {
				return n.Out[0].ProcessElement(n.ctx, val)
			}
		}
	}
	return nil
}

// mustExplodeWindows returns true iif we need to call the function
// for each window. It is needed if the function either observes the
// window, either directly or indirectly via (windowed) side inputs.
func mustExplodeWindows(fn *funcx.Fn, elm *FullValue, usesSideInput bool) bool {
	if len(elm.Windows) < 2 {
		return false
	}
	_, explode := fn.Window()
	return explode || usesSideInput
}

// FinishBundle does post-bundle processing operations for the DoFn.
// Note: This is not a "FinalizeBundle" operation. Data is not yet durably
// persisted at this point.
func (n *ParDo) FinishBundle(ctx context.Context) error {
	if n.status != Active {
		return errors.Errorf("invalid status for pardo %v: %v, want Active", n.UID, n.status)
	}
	n.status = Up
	n.inv.Reset()

	if _, err := n.invokeDataFn(n.ctx, window.SingleGlobalWindow, mtime.ZeroTimestamp, n.Fn.FinishBundleFn(), nil); err != nil {
		return n.fail(err)
	}
	n.side = nil
	n.cache = nil

	if err := MultiFinishBundle(n.ctx, n.Out...); err != nil {
		return n.fail(err)
	}
	return nil
}

// Down performs best-effort teardown of DoFn resources. (May not run.)
func (n *ParDo) Down(ctx context.Context) error {
	if n.status == Down {
		return n.err.Error()
	}
	n.status = Down
	n.side = nil
	n.cache = nil

	if _, err := InvokeWithoutEventTime(ctx, n.Fn.TeardownFn(), nil); err != nil {
		n.err.TrySetError(err)
	}
	return n.err.Error()
}

func (n *ParDo) initSideInput(ctx context.Context, w typex.Window) error {
	if n.cache == nil {
		// First time: init single-element cache. We know that side input
		// must come before emitters in the signature.

		sideCount := len(n.Side)
		emitCount := len(n.emitters)

		n.cache = &cacheElm{
			key:   w,
			extra: make([]interface{}, sideCount+emitCount, sideCount+emitCount),
		}
		for i, emit := range n.emitters {
			n.cache.extra[i+sideCount] = emit.Value()
		}
	} else if w.Equals(n.cache.key) {
		// Fast path: same window. Just unwind the side inputs.

		for _, s := range n.cache.sideinput {
			if err := s.Init(); err != nil {
				return err
			}
		}
		return nil
	}

	// Slow path: init side input for the given window

	streams := make([]ReStream, len(n.Side), len(n.Side))
	for i, adapter := range n.Side {
		s, err := adapter.NewIterable(ctx, n.side, w)
		if err != nil {
			return err
		}
		streams[i] = s
	}

	sideinput, err := makeSideInputs(n.Fn.ProcessElementFn(), n.Inbound, streams)
	if err != nil {
		return err
	}
	n.cache.sideinput = sideinput
	for i := 0; i < len(n.Side); i++ {
		n.cache.extra[i] = sideinput[i].Value()
	}

	for _, s := range n.cache.sideinput {
		if err := s.Init(); err != nil {
			return err
		}
	}
	return nil
}

// invokeDataFn handle non-per element invocations.
func (n *ParDo) invokeDataFn(ctx context.Context, ws []typex.Window, ts typex.EventTime, fn *funcx.Fn, opt *MainInput) (*FullValue, error) {
	if fn == nil {
		return nil, nil
	}
	if err := n.preInvoke(ctx, ws, ts); err != nil {
		return nil, err
	}
	val, err := Invoke(ctx, ws, ts, fn, opt, n.cache.extra...)
	if err != nil {
		return nil, err
	}
	if err := n.postInvoke(); err != nil {
		return nil, err
	}
	return val, nil
}

// invokeProcessFn handles the per element invocations
func (n *ParDo) invokeProcessFn(ctx context.Context, ws []typex.Window, ts typex.EventTime, opt *MainInput) (*FullValue, error) {
	if err := n.preInvoke(ctx, ws, ts); err != nil {
		return nil, err
	}
	val, err := n.inv.Invoke(ctx, ws, ts, opt, n.cache.extra...)
	if err != nil {
		return nil, err
	}
	if err := n.postInvoke(); err != nil {
		return nil, err
	}
	return val, nil
}

func (n *ParDo) preInvoke(ctx context.Context, ws []typex.Window, ts typex.EventTime) error {
	for _, e := range n.emitters {
		if err := e.Init(ctx, ws, ts); err != nil {
			return err
		}
	}
	return n.initSideInput(ctx, ws[0])
}

func (n *ParDo) postInvoke() error {
	for _, s := range n.cache.sideinput {
		if err := s.Reset(); err != nil {
			return err
		}
	}
	return nil
}

func (n *ParDo) fail(err error) error {
	n.status = Broken
	n.err.TrySetError(err)
	return err
}

func (n *ParDo) String() string {
	return fmt.Sprintf("ParDo[%v] Out:%v", path.Base(n.Fn.Name()), IDs(n.Out...))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os/exec"
	"testing"
)

// these tests need a freshly started empty private docker registry

// pulling an image from the central registry should work
func TestPushBusyboxImage(t *testing.T) {
	// skip this test until we're able to use a registry
	t.Skip()
	// tag the image to upload it tot he private registry
	repoName := fmt.Sprintf("%v/busybox", privateRegistryURL)
	tagCmd := exec.Command(dockerBinary, "tag", "busybox", repoName)
	out, exitCode, err := runCommandWithOutput(tagCmd)
	errorOut(err, t, fmt.Sprintf("%v %v", out, err))

	if err != nil || exitCode != 0 {
		t.Fatal("image tagging failed")
	}

	pushCmd := exec.Command(dockerBinary, "push", repoName)
	out, exitCode, err = runCommandWithOutput(pushCmd)
	errorOut(err, t, fmt.Sprintf("%v %v", out, err))

	deleteImages(repoName)

	if err != nil || exitCode != 0 {
		t.Fatal("pushing the image to the private registry has failed")
	}
	logDone("push - push busybox to private registry")
}

// pushing an image without a prefix should throw an error
func TestPushUnprefixedRepo(t *testing.T) {
	// skip this test until we're able to use a registry
	t.Skip()
	pushCmd := exec.Command(dockerBinary, "push", "busybox")
	_, exitCode, err := runCommandWithOutput(pushCmd)

	if err == nil || exitCode == 0 {
		t.Fatal("pushing an unprefixed repo didn't result in a non-zero exit status")
	}
	logDone("push - push unprefixed busybox repo --> must fail")
}
<commit_msg>Cleanup errorOut resp in push tests<commit_after>package main

import (
	"fmt"
	"os/exec"
	"testing"
)

// these tests need a freshly started empty private docker registry

// pulling an image from the central registry should work
func TestPushBusyboxImage(t *testing.T) {
	// skip this test until we're able to use a registry
	t.Skip()
	// tag the image to upload it tot he private registry
	repoName := fmt.Sprintf("%v/busybox", privateRegistryURL)
	tagCmd := exec.Command(dockerBinary, "tag", "busybox", repoName)
	if out, _, err := runCommandWithOutput(tagCmd); err != nil {
		t.Fatal("image tagging failed: %s, %v", out, err)
	}

	pushCmd := exec.Command(dockerBinary, "push", repoName)
	if out, _, err := runCommandWithOutput(pushCmd); err != nil {
		t.Fatal("pushing the image to the private registry has failed: %s, %v", out, err)
	}

	deleteImages(repoName)

	logDone("push - push busybox to private registry")
}

// pushing an image without a prefix should throw an error
func TestPushUnprefixedRepo(t *testing.T) {
	// skip this test until we're able to use a registry
	t.Skip()
	pushCmd := exec.Command(dockerBinary, "push", "busybox")
	if out, _, err := runCommandWithOutput(pushCmd); err == nil {
		t.Fatal("pushing an unprefixed repo didn't result in a non-zero exit status: %s", out)
	}
	logDone("push - push unprefixed busybox repo --> must fail")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"time"
	"net/http"
	"strings"
	"github.com/tarm/serial"
	"log"
	"errors"
	"strconv"
	"math"
	"b00lduck/datalogger/serial/parser"
	"io/ioutil"
)

func main() {

    c := &serial.Config{Name: "/dev/ttyUSB0", Baud: 9600, ReadTimeout: time.Second * 2}
    s, err := serial.OpenPort(c)

    if err != nil {
        log.Fatal(err)
    }

    for {
		err = requestDatagram(s)
		if err != nil {
			fmt.Println(err)
			time.Sleep(1 * time.Second)
		} else {
			time.Sleep(5 * time.Second)
		}
    }
}

func requestDatagram(s *serial.Port) error {

    n, err := s.Write([]byte("DUMP\r"))
    if err != nil {
        return err
    }

    buf := make([]byte, 38) // Datagram length is 38 bytes incl. \n
    n, err = s.Read(buf)
    if err != nil {
        return err
    }

    // check for correct size
    if n != 38 {
	return errors.New("received datagram with invalid size (must: 38, was: " + strconv.Itoa(n) + ")")
    }

    return processDatagram(buf)

}

var oldval_brauchwasser = float32(0)
var oldval_aussen = float32(0)
var oldval_kessel = float32(0)

func processDatagram(data []byte) error {

    if data[37] != 10 {
	return errors.New("last char in datagram must be newline (0x0a)")
    }

    // Check ADC values
    for i:=0;i<8;i++ {
	index := 4 * i
	// check first ADC digit (0,1,2,3)
	if err := parser.IsSmallHexDigit(data,index); err != nil {
	    return err
	}

	// check second and third ADC digit (0-9,a-f)
	for i:=0;i<2;i++ {
	    index += 1
	    if err := parser.IsHexDigit(data,index); err != nil {
		return err
	    }
	}

	// check spaces between values
	index += 1
        if data[index] != 32 {
    	    return errors.New("char at index " + strconv.Itoa(index) + " must be a space (0x20)")
	}
    }

    // check DIGITAL values
    if data[31] != 32 {
        return errors.New("char at index 31 must be a space (0x20)")
    }

    if err := parser.IsHexDigit(data,32); err != nil {
	return err
    }

    if err := parser.IsHexDigit(data,33); err != nil {
	return err
    }

    // check CRC value (format only, real CRC check later)
    if data[34] != 32 {
        return errors.New("char at index 34 must be a space (0x20)")
    }

    if err := parser.IsHexDigit(data,35); err != nil {
	return err
    }

    if err := parser.IsHexDigit(data,36); err != nil {
	return err
    }

    adc_brauchwasser := parser.ParseADCSensorC(5, data)
    if math.Abs(float64(adc_brauchwasser - oldval_brauchwasser)) > 0.2 {
		sendReading("HEIZ_BRAUCHW", adc_brauchwasser)
		fmt.Println("Brauchwasser: " + fmt.Sprintf("%.1f", adc_brauchwasser) + " C")
		oldval_brauchwasser = adc_brauchwasser
	}

	adc_aussen := parser.ParseADCSensorB(6, data)
	if math.Abs(float64(adc_aussen - oldval_aussen)) > 0.2 {
		sendReading("HEIZ_AUSSEN", adc_aussen)
		fmt.Println("Aussen: " + fmt.Sprintf("%.1f", adc_aussen) + " C")
		oldval_aussen = adc_aussen
	}

    adc_kessel := parser.ParseADCSensorA(7, data)
	if math.Abs(float64(adc_kessel - oldval_kessel)) > 0.5 {
		sendReading("HEIZ_KESSEL", adc_kessel)
		fmt.Println("Kessel: " + fmt.Sprintf("%.1f", adc_kessel) + " C")
		oldval_kessel = adc_kessel
	}

    return nil
}

func sendReading(code string, temp float32) {

	intval := fmt.Sprintf("%d", temp * 1000)

	client := &http.Client{}
	request, err := http.NewRequest("POST", "http://localhost:8080/thermometer/" + code + "/reading", strings.NewReader(intval))
	if err != nil {
		fmt.Println("Error creating thermometer request to dataservice")
		fmt.Println(err)
		return
	}
	request.ContentLength = 0
	x, err := client.Do(request)
	if err != nil {
		fmt.Println("Error sending thermometer request to dataservice")
		fmt.Println(err)
	}

	if x.StatusCode != 200 {
		fmt.Println("Error sending thermometer request to dataservice")
		fmt.Println( string(ioutil.ReadAll(x.Body)) )
	}

}
<commit_msg>ACQUISITION-SERIAL: test<commit_after>package main

import (
	"fmt"
	"time"
	"net/http"
	"strings"
	"github.com/tarm/serial"
	"log"
	"errors"
	"strconv"
	"math"
	"b00lduck/datalogger/serial/parser"
	"io/ioutil"
)

func main() {

    c := &serial.Config{Name: "/dev/ttyUSB0", Baud: 9600, ReadTimeout: time.Second * 2}
    s, err := serial.OpenPort(c)

    if err != nil {
        log.Fatal(err)
    }

    for {
		err = requestDatagram(s)
		if err != nil {
			fmt.Println(err)
			time.Sleep(1 * time.Second)
		} else {
			time.Sleep(5 * time.Second)
		}
    }
}

func requestDatagram(s *serial.Port) error {

    n, err := s.Write([]byte("DUMP\r"))
    if err != nil {
        return err
    }

    buf := make([]byte, 38) // Datagram length is 38 bytes incl. \n
    n, err = s.Read(buf)
    if err != nil {
        return err
    }

    // check for correct size
    if n != 38 {
	return errors.New("received datagram with invalid size (must: 38, was: " + strconv.Itoa(n) + ")")
    }

    return processDatagram(buf)

}

var oldval_brauchwasser = float32(0)
var oldval_aussen = float32(0)
var oldval_kessel = float32(0)

func processDatagram(data []byte) error {

    if data[37] != 10 {
	return errors.New("last char in datagram must be newline (0x0a)")
    }

    // Check ADC values
    for i:=0;i<8;i++ {
	index := 4 * i
	// check first ADC digit (0,1,2,3)
	if err := parser.IsSmallHexDigit(data,index); err != nil {
	    return err
	}

	// check second and third ADC digit (0-9,a-f)
	for i:=0;i<2;i++ {
	    index += 1
	    if err := parser.IsHexDigit(data,index); err != nil {
		return err
	    }
	}

	// check spaces between values
	index += 1
        if data[index] != 32 {
    	    return errors.New("char at index " + strconv.Itoa(index) + " must be a space (0x20)")
	}
    }

    // check DIGITAL values
    if data[31] != 32 {
        return errors.New("char at index 31 must be a space (0x20)")
    }

    if err := parser.IsHexDigit(data,32); err != nil {
	return err
    }

    if err := parser.IsHexDigit(data,33); err != nil {
	return err
    }

    // check CRC value (format only, real CRC check later)
    if data[34] != 32 {
        return errors.New("char at index 34 must be a space (0x20)")
    }

    if err := parser.IsHexDigit(data,35); err != nil {
	return err
    }

    if err := parser.IsHexDigit(data,36); err != nil {
	return err
    }

    adc_brauchwasser := parser.ParseADCSensorC(5, data)
    if math.Abs(float64(adc_brauchwasser - oldval_brauchwasser)) > 0.2 {
		sendReading("HEIZ_BRAUCHW", adc_brauchwasser)
		fmt.Println("Brauchwasser: " + fmt.Sprintf("%.1f", adc_brauchwasser) + " C")
		oldval_brauchwasser = adc_brauchwasser
	}

	adc_aussen := parser.ParseADCSensorB(6, data)
	if math.Abs(float64(adc_aussen - oldval_aussen)) > 0.2 {
		sendReading("HEIZ_AUSSEN", adc_aussen)
		fmt.Println("Aussen: " + fmt.Sprintf("%.1f", adc_aussen) + " C")
		oldval_aussen = adc_aussen
	}

    adc_kessel := parser.ParseADCSensorA(7, data)
	if math.Abs(float64(adc_kessel - oldval_kessel)) > 0.5 {
		sendReading("HEIZ_KESSEL", adc_kessel)
		fmt.Println("Kessel: " + fmt.Sprintf("%.1f", adc_kessel) + " C")
		oldval_kessel = adc_kessel
	}

    return nil
}

func sendReading(code string, temp float32) {

	intval := fmt.Sprintf("%d", temp * 1000)

	client := &http.Client{}
	request, err := http.NewRequest("POST", "http://localhost:8080/thermometer/" + code + "/reading", strings.NewReader(intval))
	if err != nil {
		fmt.Println("Error creating thermometer request to dataservice")
		fmt.Println(err)
		return
	}
	request.ContentLength = 0
	x, err := client.Do(request)
	if err != nil {
		fmt.Println("Error sending thermometer request to dataservice")
		fmt.Println(err)
	}

	if x.StatusCode != 200 {
		fmt.Println("Error sending thermometer request to dataservice")
		str, _ := ioutil.ReadAll(x.Body)
		fmt.Println( string(str) )
	}

}
<|endoftext|>


<commit_before>// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0

package fix

import (
	"os"
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/stretchr/testify/assert"
	testutils_test "sigs.k8s.io/kustomize/kustomize/v4/commands/internal/testutils"
	"sigs.k8s.io/kustomize/kyaml/filesys"
)

func TestFix(t *testing.T) {
	fSys := filesys.MakeFsInMemory()
	testutils_test.WriteTestKustomizationWith(fSys, []byte(`nameprefix: some-prefix-`))

	cmd := NewCmdFix(fSys, os.Stdout)
	assert.NoError(t, cmd.RunE(cmd, nil))

	content, err := testutils_test.ReadTestKustomization(fSys)
	assert.NoError(t, err)

	assert.Contains(t, string(content), "apiVersion: ")
	assert.Contains(t, string(content), "kind: Kustomization")
}

func TestFixOutdatedPatchesFieldTitle(t *testing.T) {
	kustomizationContentWithOutdatedPatchesFieldTitle := []byte(`
patchesJson6902:
- path: patch1.yaml
  target:
    kind: Service
- path: patch2.yaml
  target:
    group: apps
    kind: Deployment
    version: v1
`)

	expected := []byte(`
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
patches:
- path: patch1.yaml
  target:
    kind: Service
- path: patch2.yaml
  target:
    group: apps
    kind: Deployment
    version: v1
`)
	fSys := filesys.MakeFsInMemory()
	testutils_test.WriteTestKustomizationWith(fSys, kustomizationContentWithOutdatedPatchesFieldTitle)
	cmd := NewCmdFix(fSys, os.Stdout)
	assert.NoError(t, cmd.RunE(cmd, nil))

	content, err := testutils_test.ReadTestKustomization(fSys)
	assert.NoError(t, err)
	assert.Contains(t, string(content), "apiVersion: ")
	assert.Contains(t, string(content), "kind: Kustomization")

	if diff := cmp.Diff(expected, content); diff != "" {
		t.Errorf("Mismatch (-expected, +actual):\n%s", diff)
	}
}

func TestRenameAndKeepOutdatedPatchesField(t *testing.T) {
	kustomizationContentWithOutdatedPatchesFieldTitle := []byte(`
patchesJson6902:
- path: patch1.yaml
  target:
    kind: Deployment
patches:
- path: patch2.yaml
  target:
    kind: Deployment
- path: patch3.yaml
  target:
    kind: Service
`)

	expected := []byte(`
patches:
- path: patch2.yaml
  target:
    kind: Deployment
- path: patch3.yaml
  target:
    kind: Service
- path: patch1.yaml
  target:
    kind: Deployment
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
`)
	fSys := filesys.MakeFsInMemory()
	testutils_test.WriteTestKustomizationWith(fSys, kustomizationContentWithOutdatedPatchesFieldTitle)
	cmd := NewCmdFix(fSys, os.Stdout)
	assert.NoError(t, cmd.RunE(cmd, nil))

	content, err := testutils_test.ReadTestKustomization(fSys)
	assert.NoError(t, err)
	assert.Contains(t, string(content), "apiVersion: ")
	assert.Contains(t, string(content), "kind: Kustomization")

	if diff := cmp.Diff(expected, content); diff != "" {
		t.Errorf("Mismatch (-expected, +actual):\n%s", diff)
	}
}

func TestFixOutdatedPatchesStrategicMergeFieldTitle(t *testing.T) {
	kustomizationContentWithOutdatedPatchesFieldTitle := []byte(`
patchesStrategicMerge:
- |-
  apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: nginx
  spec:
    template:
      spec:
        containers:
          - name: nginx
            image: nignx:latest
`)

	expected := []byte(`
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
patches:
- patch: |-
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx
    spec:
      template:
        spec:
          containers:
            - name: nginx
              image: nignx:latest
`)
	fSys := filesys.MakeFsInMemory()
	testutils_test.WriteTestKustomizationWith(fSys, kustomizationContentWithOutdatedPatchesFieldTitle)
	cmd := NewCmdFix(fSys, os.Stdout)
	assert.NoError(t, cmd.RunE(cmd, nil))

	content, err := testutils_test.ReadTestKustomization(fSys)
	assert.NoError(t, err)
	assert.Contains(t, string(content), "apiVersion: ")
	assert.Contains(t, string(content), "kind: Kustomization")

	if diff := cmp.Diff(expected, content); diff != "" {
		t.Errorf("Mismatch (-expected, +actual):\n%s", diff)
	}
}

func TestFixAndMergeOutdatedPatchesStrategicMergeFieldTitle(t *testing.T) {
	kustomizationContentWithOutdatedPatchesFieldTitle := []byte(`
patchesStrategicMerge:
- |-
  apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: nginx
  spec:
    template:
      spec:
        containers:
          - name: nginx
            image: nignx:latest
patches:
- path: patch2.yaml
  target:
    kind: Deployment
`)

	expected := []byte(`
patches:
- path: patch2.yaml
  target:
    kind: Deployment
- patch: |-
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx
    spec:
      template:
        spec:
          containers:
            - name: nginx
              image: nignx:latest
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
`)
	fSys := filesys.MakeFsInMemory()
	testutils_test.WriteTestKustomizationWith(fSys, kustomizationContentWithOutdatedPatchesFieldTitle)
	cmd := NewCmdFix(fSys, os.Stdout)
	assert.NoError(t, cmd.RunE(cmd, nil))

	content, err := testutils_test.ReadTestKustomization(fSys)
	assert.NoError(t, err)
	assert.Contains(t, string(content), "apiVersion: ")
	assert.Contains(t, string(content), "kind: Kustomization")

	if diff := cmp.Diff(expected, content); diff != "" {
		t.Errorf("Mismatch (-expected, +actual):\n%s", diff)
	}
}

func TestFixOutdatedPatchesStrategicMergeToPathFieldTitle(t *testing.T) {
	kustomizationContentWithOutdatedPatchesFieldTitle := []byte(`
patchesStrategicMerge:
- deploy.yaml
`)

	expected := []byte(`
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
patches:
- path: deploy.yaml
`)
	fSys := filesys.MakeFsInMemory()
	testutils_test.WriteTestKustomizationWith(fSys, kustomizationContentWithOutdatedPatchesFieldTitle)
	cmd := NewCmdFix(fSys, os.Stdout)
	assert.NoError(t, cmd.RunE(cmd, nil))

	content, err := testutils_test.ReadTestKustomization(fSys)
	assert.NoError(t, err)
	assert.Contains(t, string(content), "apiVersion: ")
	assert.Contains(t, string(content), "kind: Kustomization")

	if diff := cmp.Diff(expected, content); diff != "" {
		t.Errorf("Mismatch (-expected, +actual):\n%s", diff)
	}
}

func TestFixOutdatedPatchesStrategicMergeToPathFieldYMLTitle(t *testing.T) {
	kustomizationContentWithOutdatedPatchesFieldTitle := []byte(`
patchesStrategicMerge:
- deploy.yml
`)

	expected := []byte(`
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
patches:
- path: deploy.yml
`)
	fSys := filesys.MakeFsInMemory()
	testutils_test.WriteTestKustomizationWith(fSys, kustomizationContentWithOutdatedPatchesFieldTitle)
	cmd := NewCmdFix(fSys, os.Stdout)
	assert.NoError(t, cmd.RunE(cmd, nil))

	content, err := testutils_test.ReadTestKustomization(fSys)
	assert.NoError(t, err)
	assert.Contains(t, string(content), "apiVersion: ")
	assert.Contains(t, string(content), "kind: Kustomization")

	if diff := cmp.Diff(expected, content); diff != "" {
		t.Errorf("Mismatch (-expected, +actual):\n%s", diff)
	}
}

func TestFixOutdatedPatchesStrategicMergeFieldPatchEndOfYamlTitle(t *testing.T) {
	kustomizationContentWithOutdatedPatchesFieldTitle := []byte(`
patchesStrategicMerge:
- |-
  apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: nginx
  spec:
    template:
      spec:
        containers:
          - name: nginx
            env:
              - name: CONFIG_FILE_PATH
                value: home.yaml
`)

	expected := []byte(`
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
patches:
- patch: |-
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx
    spec:
      template:
        spec:
          containers:
            - name: nginx
              env:
                - name: CONFIG_FILE_PATH
                  value: home.yaml
`)
	fSys := filesys.MakeFsInMemory()
	testutils_test.WriteTestKustomizationWith(fSys, kustomizationContentWithOutdatedPatchesFieldTitle)
	cmd := NewCmdFix(fSys, os.Stdout)
	assert.NoError(t, cmd.RunE(cmd, nil))

	content, err := testutils_test.ReadTestKustomization(fSys)
	assert.NoError(t, err)
	assert.Contains(t, string(content), "apiVersion: ")
	assert.Contains(t, string(content), "kind: Kustomization")

	if diff := cmp.Diff(expected, content); diff != "" {
		t.Errorf("Mismatch (-expected, +actual):\n%s", diff)
	}
}

func TestFixOutdatedCommonLabels(t *testing.T) {
	kustomizationContentWithOutdatedCommonLabels := []byte(`
commonLabels:
  foo: bar
labels:
- pairs:
    a: b
`)

	expected := []byte(`
labels:
- pairs:
    a: b
- includeSelectors: true
  pairs:
    foo: bar
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
`)
	fSys := filesys.MakeFsInMemory()
	testutils_test.WriteTestKustomizationWith(fSys, kustomizationContentWithOutdatedCommonLabels)
	cmd := NewCmdFix(fSys, os.Stdout)
	assert.NoError(t, cmd.RunE(cmd, nil))

	content, err := testutils_test.ReadTestKustomization(fSys)
	assert.NoError(t, err)
	assert.Contains(t, string(content), "apiVersion: ")
	assert.Contains(t, string(content), "kind: Kustomization")

	if diff := cmp.Diff(expected, content); diff != "" {
		t.Errorf("Mismatch (-expected, +actual):\n%s", diff)
	}
}

func TestFixOutdatedCommonLabelsDuplicate(t *testing.T) {
	kustomizationContentWithOutdatedCommonLabels := []byte(`
commonLabels:
  foo: bar
labels:
- pairs:
    foo: baz
    a: b
`)

	fSys := filesys.MakeFsInMemory()
	testutils_test.WriteTestKustomizationWith(fSys, kustomizationContentWithOutdatedCommonLabels)
	cmd := NewCmdFix(fSys, os.Stdout)
	err := cmd.RunE(cmd, nil)
	assert.Error(t, err)
	assert.Equal(t, err.Error(), "label name 'foo' exists in both commonLabels and labels")
}
<commit_msg>refactor edit fix test cases<commit_after>// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0

package fix

import (
	"os"
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/stretchr/testify/assert"
	testutils_test "sigs.k8s.io/kustomize/kustomize/v4/commands/internal/testutils"
	"sigs.k8s.io/kustomize/kyaml/filesys"
)

func TestFix(t *testing.T) {
	fSys := filesys.MakeFsInMemory()
	testutils_test.WriteTestKustomizationWith(fSys, []byte(`nameprefix: some-prefix-`))

	cmd := NewCmdFix(fSys, os.Stdout)
	assert.NoError(t, cmd.RunE(cmd, nil))

	content, err := testutils_test.ReadTestKustomization(fSys)
	assert.NoError(t, err)

	assert.Contains(t, string(content), "apiVersion: ")
	assert.Contains(t, string(content), "kind: Kustomization")
}

func TestFixCommand(t *testing.T) {
	tests := []struct {
		name     string
		input    string
		expected string
	}{
		{
			name: "FixOutdatedPatchesFieldTitle",
			input: `
patchesJson6902:
- path: patch1.yaml
  target:
    kind: Service
- path: patch2.yaml
  target:
    group: apps
    kind: Deployment
    version: v1
`,
			expected: `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
patches:
- path: patch1.yaml
  target:
    kind: Service
- path: patch2.yaml
  target:
    group: apps
    kind: Deployment
    version: v1
`,
		},
		{
			name: "TestRenameAndKeepOutdatedPatchesField",
			input: `
patchesJson6902:
- path: patch1.yaml
  target:
    kind: Deployment
patches:
- path: patch2.yaml
  target:
    kind: Deployment
- path: patch3.yaml
  target:
    kind: Service
`,
			expected: `
patches:
- path: patch2.yaml
  target:
    kind: Deployment
- path: patch3.yaml
  target:
    kind: Service
- path: patch1.yaml
  target:
    kind: Deployment
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
`,
		},
		{
			name: "TestFixOutdatedPatchesStrategicMergeFieldTitle",
			input: `
patchesStrategicMerge:
- |-
  apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: nginx
  spec:
    template:
      spec:
        containers:
          - name: nginx
            image: nignx:latest
`,
			expected: `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
patches:
- patch: |-
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx
    spec:
      template:
        spec:
          containers:
            - name: nginx
              image: nignx:latest
`,
		},
		{
			name: "TestFixAndMergeOutdatedPatchesStrategicMergeFieldTitle",
			input: `
patchesStrategicMerge:
- |-
  apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: nginx
  spec:
    template:
      spec:
        containers:
          - name: nginx
            image: nignx:latest
patches:
- path: patch2.yaml
  target:
    kind: Deployment
`,
			expected: `
patches:
- path: patch2.yaml
  target:
    kind: Deployment
- patch: |-
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx
    spec:
      template:
        spec:
          containers:
            - name: nginx
              image: nignx:latest
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
`,
		},
		{
			name: "TestFixOutdatedPatchesStrategicMergeToPathFieldTitle",
			input: `
patchesStrategicMerge:
- deploy.yaml
`,
			expected: `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
patches:
- path: deploy.yaml
`,
		},
		{
			name: "TestFixOutdatedPatchesStrategicMergeToPathFieldYMLTitle",
			input: `
patchesStrategicMerge:
- deploy.yml
`,
			expected: `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
patches:
- path: deploy.yml
`,
		},
		{
			name: "TestFixOutdatedPatchesStrategicMergeFieldPatchEndOfYamlTitle",
			input: `
patchesStrategicMerge:
- |-
  apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: nginx
  spec:
    template:
      spec:
        containers:
          - name: nginx
            env:
              - name: CONFIG_FILE_PATH
                value: home.yaml
`,
			expected: `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
patches:
- patch: |-
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx
    spec:
      template:
        spec:
          containers:
            - name: nginx
              env:
                - name: CONFIG_FILE_PATH
                  value: home.yaml
`,
		},
		{
			name: "TestFixOutdatedCommonLabels",
			input: `
commonLabels:
  foo: bar
labels:
- pairs:
    a: b
`,
			expected: `
labels:
- pairs:
    a: b
- includeSelectors: true
  pairs:
    foo: bar
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
`,
		},
	}
	for _, test := range tests {
		fSys := filesys.MakeFsInMemory()
		testutils_test.WriteTestKustomizationWith(fSys, []byte(test.input))
		cmd := NewCmdFix(fSys, os.Stdout)
		assert.NoError(t, cmd.RunE(cmd, nil))

		content, err := testutils_test.ReadTestKustomization(fSys)
		assert.NoError(t, err)
		assert.Contains(t, string(content), "apiVersion: ")
		assert.Contains(t, string(content), "kind: Kustomization")

		if diff := cmp.Diff([]byte(test.expected), content); diff != "" {
			t.Errorf("%s: Mismatch (-expected, +actual):\n%s", test.name, diff)
		}
	}
}

func TestFixOutdatedCommonLabelsDuplicate(t *testing.T) {
	kustomizationContentWithOutdatedCommonLabels := []byte(`
commonLabels:
  foo: bar
labels:
- pairs:
    foo: baz
    a: b
`)

	fSys := filesys.MakeFsInMemory()
	testutils_test.WriteTestKustomizationWith(fSys, kustomizationContentWithOutdatedCommonLabels)
	cmd := NewCmdFix(fSys, os.Stdout)
	err := cmd.RunE(cmd, nil)
	assert.Error(t, err)
	assert.Equal(t, err.Error(), "label name 'foo' exists in both commonLabels and labels")
}
<|endoftext|>


<commit_before>package apidApigeeSync

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"net/url"
	"path"
	"sync"
	"time"
)

var (
	refreshFloatTime = time.Minute
	getTokenLock     sync.Mutex
)

/*
Usage:
   man := createTokenManager()
   bearer := man.getBearerToken()
   // will automatically update config(configBearerToken) for other modules
   // optionally, when done...
   man.close()
*/

func createTokenManager() *tokenMan {
	t := &tokenMan{}
	t.doRefresh = make(chan bool, 1)
	t.quitPollingForToken = make(chan bool, 1)
	t.tokenRefreshed = make(chan bool)
	t.closed = make(chan bool)
	t.retrieveNewToken()
	t.maintainToken()
	return t
}

type tokenMan struct {
	token     *oauthToken
	doRefresh chan bool
	quitPollingForToken chan bool
	tokenRefreshed chan bool
	closed chan bool
}

func (t *tokenMan) getBearerToken() string {
	return t.getToken().AccessToken
}

func (t *tokenMan) maintainToken() {
	go func() {
		for {
			select {

			case _, ok := <-t.doRefresh:
				if !ok {
					log.Debug("closed tokenMan")
					t.closed <- true
					return
				}
				log.Debug("force token refresh")
				t.retrieveNewToken()
				t.tokenRefreshed <- true
				continue
			case <-time.After(t.token.refreshIn()):
				log.Debug("auto refresh token")
				getTokenLock.Lock()
				t.retrieveNewToken()
				getTokenLock.Unlock()
				continue

			}
		}
	}()
}

func (t *tokenMan) invalidateToken() {
	log.Debug("invalidating token")
	getTokenLock.Lock()
	t.token = nil
	t.doRefresh <- true
	//ensure refresh signal has been received
	<-t.tokenRefreshed
	getTokenLock.Unlock()
}

// will block until valid
//assumption is that if we can get the lock, then it's valid
func (t *tokenMan) getToken() *oauthToken {
	getTokenLock.Lock()
	defer getTokenLock.Unlock()
	return t.token
}

func (t *tokenMan) close() {
	log.Debug("close token manager")
	t.quitPollingForToken <- true
	close(t.doRefresh)
	//block until close signal has been received by maintenance routine
	<-t.closed
}

// don't call externally. will block until success.
func (t *tokenMan) retrieveNewToken() {

	log.Debug("Getting OAuth token...")
	uriString := config.GetString(configProxyServerBaseURI)
	uri, err := url.Parse(uriString)
	if err != nil {
		log.Panicf("unable to parse uri config '%s' value: '%s': %v", configProxyServerBaseURI, uriString, err)
	}
	uri.Path = path.Join(uri.Path, "/accesstoken")

	pollWithBackoff(t.quitPollingForToken, t.getRetrieveNewTokenClosure(uri), func(err error) {log.Errorf("Error getting new token : ", err)})
}

func (t *tokenMan) getRetrieveNewTokenClosure(uri *url.URL) func(chan bool) error {
	return func(_ chan bool) error {
		form := url.Values{}
		form.Set("grant_type", "client_credentials")
		form.Add("client_id", config.GetString(configConsumerKey))
		form.Add("client_secret", config.GetString(configConsumerSecret))
		req, err := http.NewRequest("POST", uri.String(), bytes.NewBufferString(form.Encode()))
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
		req.Header.Set("display_name", apidInfo.InstanceName)
		req.Header.Set("apid_instance_id", apidInfo.InstanceID)
		req.Header.Set("apid_cluster_Id", apidInfo.ClusterID)
		req.Header.Set("status", "ONLINE")
		req.Header.Set("plugin_details", apidPluginDetails)

		if newInstanceID {
			req.Header.Set("created_at_apid", time.Now().Format(time.RFC3339))
		} else {
			req.Header.Set("updated_at_apid", time.Now().Format(time.RFC3339))
		}

		client := &http.Client{Timeout: httpTimeout}
		resp, err := client.Do(req)
		if err != nil {
			log.Errorf("Unable to Connect to Edge Proxy Server: %v", err)
			return err
		}

		body, err := ioutil.ReadAll(resp.Body)
		resp.Body.Close()
		if err != nil {
			log.Errorf("Unable to read EdgeProxy Sever response: %v", err)
			return err
		}

		if resp.StatusCode != 200 {
			log.Errorf("Oauth Request Failed with Resp Code: %d. Body: %s", resp.StatusCode, string(body))
			return expected200Error{}
		}

		var token oauthToken
		err = json.Unmarshal(body, &token)
		if err != nil {
			log.Errorf("unable to unmarshal JSON response '%s': %v", string(body), err)
			return err
		}

		if token.ExpiresIn > 0 {
			token.ExpiresAt = time.Now().Add(time.Duration(token.ExpiresIn) * time.Millisecond)
		} else {
			// no expiration, arbitrarily expire about a year from now
			token.ExpiresAt = time.Now().Add(365 * 24 * time.Hour)
		}

		log.Debugf("Got new token: %#v", token)

		if newInstanceID {
			newInstanceID = false
			err = updateApidInstanceInfo()
			if err != nil {
				log.Errorf("unable to unmarshal update apid instance info : %v", string(body), err)
				return err

			}
		}

		t.token = &token
		config.Set(configBearerToken, token.AccessToken)

		return nil
	}
}

type oauthToken struct {
	IssuedAt       int64    `json:"issuedAt"`
	AppName        string   `json:"applicationName"`
	Scope          string   `json:"scope"`
	Status         string   `json:"status"`
	ApiProdList    []string `json:"apiProductList"`
	ExpiresIn      int64    `json:"expiresIn"`
	DeveloperEmail string   `json:"developerEmail"`
	TokenType      string   `json:"tokenType"`
	ClientId       string   `json:"clientId"`
	AccessToken    string   `json:"accessToken"`
	RefreshExpIn   int64    `json:"refreshTokenExpiresIn"`
	RefreshCount   int64    `json:"refreshCount"`
	ExpiresAt      time.Time
}

var noTime time.Time

func (t *oauthToken) isValid() bool {
	if t == nil || t.AccessToken == "" {
		return false
	}
	return t.AccessToken != "" && time.Now().Before(t.ExpiresAt)
}

func (t *oauthToken) refreshIn() time.Duration {
	if t == nil || t.ExpiresAt == noTime {
		return time.Duration(0)
	}
	return t.ExpiresAt.Sub(time.Now()) - refreshFloatTime
}

func (t *oauthToken) needsRefresh() bool {
	if t == nil || t.ExpiresAt == noTime {
		return true
	}
	return time.Now().Add(refreshFloatTime).After(t.ExpiresAt)
}
<commit_msg>only 1 race now<commit_after>package apidApigeeSync

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"net/url"
	"path"
	"sync"
	"time"
)

var (
	refreshFloatTime = time.Minute
)

/*
Usage:
   man := createTokenManager()
   bearer := man.getBearerToken()
   // will automatically update config(configBearerToken) for other modules
   // optionally, when done...
   man.close()
*/

func createTokenManager() *tokenMan {

	t := &tokenMan{}
	t.doRefresh = make(chan bool, 1)
	t.quitPollingForToken = make(chan bool, 1)
	t.tokenRefreshed = make(chan bool)
	t.closed = make(chan bool)
	t.retrieveNewToken()
	t.maintainToken()
	return t
}

type tokenMan struct {
	sync.Mutex
	token     *oauthToken
	doRefresh chan bool
	quitPollingForToken chan bool
	tokenRefreshed chan bool
	closed chan bool
}

func (t *tokenMan) getBearerToken() string {
	return t.getToken().AccessToken
}

func (t *tokenMan) maintainToken() {
	go func() {
		for {
			t.Lock()
			token := t.token
			t.Unlock()
			select {

			case _, ok := <-t.doRefresh:
				if !ok {
					log.Debug("closed tokenMan")
					t.closed <- true
					return
				}
				log.Debug("force token refresh")
				t.retrieveNewToken()
				t.tokenRefreshed <- true
			case <-time.After(token.refreshIn()):
				log.Debug("auto refresh token")
				t.retrieveNewToken()

			}
		}
	}()
}

func (t *tokenMan) invalidateToken() {
	log.Debug("invalidating token")
	t.Lock()
	t.token = nil
	t.Unlock()
	t.doRefresh <- true
	//ensure refresh signal has been received
	<-t.tokenRefreshed
}

// will block until valid
//assumption is that if we can get the lock, then it's valid
func (t *tokenMan) getToken() *oauthToken {
	t.Lock()
	defer t.Unlock()
	return t.token
}

func (t *tokenMan) close() {
	log.Debug("close token manager")
	t.quitPollingForToken <- true
	close(t.doRefresh)
	//block until close signal has been received by maintenance routine
	<-t.closed
}

// don't call externally. will block until success.
func (t *tokenMan) retrieveNewToken() {

	log.Debug("Getting OAuth token...")
	uriString := config.GetString(configProxyServerBaseURI)
	uri, err := url.Parse(uriString)
	if err != nil {
		log.Panicf("unable to parse uri config '%s' value: '%s': %v", configProxyServerBaseURI, uriString, err)
	}
	uri.Path = path.Join(uri.Path, "/accesstoken")

	pollWithBackoff(t.quitPollingForToken, t.getRetrieveNewTokenClosure(uri), func(err error) {log.Errorf("Error getting new token : ", err)})
}

func (t *tokenMan) getRetrieveNewTokenClosure(uri *url.URL) func(chan bool) error {
	return func(_ chan bool) error {
		form := url.Values{}
		form.Set("grant_type", "client_credentials")
		form.Add("client_id", config.GetString(configConsumerKey))
		form.Add("client_secret", config.GetString(configConsumerSecret))
		req, err := http.NewRequest("POST", uri.String(), bytes.NewBufferString(form.Encode()))
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
		req.Header.Set("display_name", apidInfo.InstanceName)
		req.Header.Set("apid_instance_id", apidInfo.InstanceID)
		req.Header.Set("apid_cluster_Id", apidInfo.ClusterID)
		req.Header.Set("status", "ONLINE")
		req.Header.Set("plugin_details", apidPluginDetails)

		if newInstanceID {
			req.Header.Set("created_at_apid", time.Now().Format(time.RFC3339))
		} else {
			req.Header.Set("updated_at_apid", time.Now().Format(time.RFC3339))
		}

		client := &http.Client{Timeout: httpTimeout}
		resp, err := client.Do(req)
		if err != nil {
			log.Errorf("Unable to Connect to Edge Proxy Server: %v", err)
			return err
		}

		body, err := ioutil.ReadAll(resp.Body)
		resp.Body.Close()
		if err != nil {
			log.Errorf("Unable to read EdgeProxy Sever response: %v", err)
			return err
		}

		if resp.StatusCode != 200 {
			log.Errorf("Oauth Request Failed with Resp Code: %d. Body: %s", resp.StatusCode, string(body))
			return expected200Error{}
		}

		var token oauthToken
		err = json.Unmarshal(body, &token)
		if err != nil {
			log.Errorf("unable to unmarshal JSON response '%s': %v", string(body), err)
			return err
		}

		if token.ExpiresIn > 0 {
			token.ExpiresAt = time.Now().Add(time.Duration(token.ExpiresIn) * time.Millisecond)
		} else {
			// no expiration, arbitrarily expire about a year from now
			token.ExpiresAt = time.Now().Add(365 * 24 * time.Hour)
		}

		log.Debugf("Got new token: %#v", token)

		if newInstanceID {
			newInstanceID = false
			err = updateApidInstanceInfo()
			if err != nil {
				log.Errorf("unable to unmarshal update apid instance info : %v", string(body), err)
				return err

			}
		}
		t.Lock()
		t.token = &token
		t.Unlock()
		config.Set(configBearerToken, token.AccessToken)

		return nil
	}
}

type oauthToken struct {
	IssuedAt       int64    `json:"issuedAt"`
	AppName        string   `json:"applicationName"`
	Scope          string   `json:"scope"`
	Status         string   `json:"status"`
	ApiProdList    []string `json:"apiProductList"`
	ExpiresIn      int64    `json:"expiresIn"`
	DeveloperEmail string   `json:"developerEmail"`
	TokenType      string   `json:"tokenType"`
	ClientId       string   `json:"clientId"`
	AccessToken    string   `json:"accessToken"`
	RefreshExpIn   int64    `json:"refreshTokenExpiresIn"`
	RefreshCount   int64    `json:"refreshCount"`
	ExpiresAt      time.Time
}

var noTime time.Time

func (t *oauthToken) isValid() bool {
	if t == nil || t.AccessToken == "" {
		return false
	}
	return t.AccessToken != "" && time.Now().Before(t.ExpiresAt)
}

func (t *oauthToken) refreshIn() time.Duration {
	if t == nil || t.ExpiresAt == noTime {
		return time.Duration(0)
	}
	return t.ExpiresAt.Sub(time.Now()) - refreshFloatTime
}

func (t *oauthToken) needsRefresh() bool {
	if t == nil || t.ExpiresAt == noTime {
		return true
	}
	return time.Now().Add(refreshFloatTime).After(t.ExpiresAt)
}
<|endoftext|>


<commit_before>package lexinator

import "fmt"

type Token struct {
	Typ  TokenType
	Val  string
	File string
	Line int
}

type TokenType int

const (
	TokenStopped TokenType = -1 - iota
	TokenError
	TokenEOF
)

func (i Token) String() string {
	switch i.Typ {
	case TokenError:
		return i.Val
	case TokenEOF:
		return "EOF"
	}
	if len(i.Val) > 10 {
		return fmt.Sprintf("%.15q...", i.Val)
	}
	return fmt.Sprintf("%q", i.Val)
}
<commit_msg>Added standard TokenType: TokenEmpty (0)<commit_after>package lexinator

import "fmt"

type Token struct {
	Typ  TokenType
	Val  string
	File string
	Line int
}

type TokenType int

const (
	TokenEmpty TokenType = -iota
	TokenStopped
	TokenError
	TokenEOF
)

func (i Token) String() string {
	switch i.Typ {
	case TokenError:
		return i.Val
	case TokenEOF:
		return "EOF"
	}
	if len(i.Val) > 10 {
		return fmt.Sprintf("%.15q...", i.Val)
	}
	return fmt.Sprintf("%q", i.Val)
}
<|endoftext|>


<commit_before>package boardgame

import (
	"container/heap"
	"time"
)

//A Timer is a type of property that can be used in states that represents a
//countdown. The MutableTimer interface includes mutator methods as well. See
//the package documentation for more on timers.
type Timer interface {
	Active() bool
	TimeLeft() time.Duration
	copy() Timer
	id() int
	state() *state
	setState(*state)
}

//MutableTimer is a Timer that also includes mutator methods.
type MutableTimer interface {
	Timer
	Start(time.Duration, Move)
	Cancel() bool
	mutableCopy() MutableTimer
}

type timer struct {
	//Id will be an opaque identifier that is used to keep track of the
	//corresponding underlying Timer object in the game engine. It is not
	//meaningful to inspect yourself and should not be modified.
	Id       int
	statePtr *state
}

func NewTimer() MutableTimer {
	return &timer{}
}

func (t *timer) id() int {
	return t.Id
}

func (t *timer) state() *state {
	return t.statePtr
}

func (t *timer) setState(state *state) {
	t.statePtr = state
}

func (t *timer) copy() Timer {
	return t.mutableCopy()
}

func (t *timer) mutableCopy() MutableTimer {
	var result timer
	result = *t
	return &result
}

func (t *timer) MarshalJSON() ([]byte, error) {
	obj := map[string]interface{}{
		"Id": t.Id,
		//TimeLeft is only ever for the client (it's not read back in when
		//deserialized), so put it in the more traditional milliseconds units,
		//not nanoseconds.
		"TimeLeft": t.TimeLeft() / time.Millisecond,
	}

	return DefaultMarshalJSON(obj)
}

//Active returns true if the timer is active and counting down.
func (t *timer) Active() bool {
	return t.statePtr.game.manager.timers.TimerActive(t.Id)
}

//TimeLeft returns the number of nanoseconds left until this timer fires.
func (t *timer) TimeLeft() time.Duration {
	return t.statePtr.game.manager.timers.GetTimerRemaining(t.Id)
}

//Start starts the timer. After duration has passed, the Move will be proposed
//via proposeMove. If the timer is already active, it will be canceled before
//the new timer is configured.
func (t *timer) Start(duration time.Duration, move Move) {

	if t.Active() {
		t.Cancel()
	}

	game := t.statePtr.game
	manager := game.manager

	t.Id = manager.timers.PrepareTimer(duration, game, move)

	t.statePtr.timersToStart = append(t.statePtr.timersToStart, t.Id)
}

//Cancel cancels an active timer. If the timer is not active, it has no
//effect. Returns true if the timer was active and canceled, false if the
//timer was not active.
func (t *timer) Cancel() bool {

	wasActive := t.Active()

	manager := t.statePtr.game.manager

	manager.timers.CancelTimer(t.Id)

	//Technically there's a case where Start() was called, but the state was
	//never fully committed. However, StartTimer() on a canceled timer is a
	//no-op so it's fine.

	t.Id = 0

	return wasActive
}

type timerRecord struct {
	id    int
	index int
	//When the timer should fire. Set after the timer is fully Started().
	//Before that it is impossibly far in the future.
	fireTime time.Time
	//The duration we were configured with. Only set when the timer is
	//Prepared() but not yet Started().
	duration time.Duration
	game     *Game
	move     Move
}

func (t *timerRecord) TimeRemaining() time.Duration {

	//Before a timer is Started(), just say its duration as the time
	//remaining.
	if t.duration > 0 {
		return t.duration
	}

	duration := t.fireTime.Sub(time.Now())

	if duration < 0 {
		duration = 0
	}

	return duration
}

type timerQueue []*timerRecord

type timerManager struct {
	nextId      int
	records     timerQueue
	recordsById map[int]*timerRecord
	manager     *GameManager
}

func newTimerManager(gameManager *GameManager) *timerManager {
	return &timerManager{
		//the default id in TimerProps is 0, so we should start beyond that.
		nextId:      1,
		records:     make(timerQueue, 0),
		recordsById: make(map[int]*timerRecord),
		manager:     gameManager,
	}
}

//PrepareTimer creates a timer entry and gets it ready and an Id allocated.
//However, the timer doesn't actually start counting down until
//manager.StartTimer(id) is called.
func (t *timerManager) PrepareTimer(duration time.Duration, game *Game, move Move) int {
	record := &timerRecord{
		id:       t.nextId,
		index:    -1,
		duration: duration,
		//fireTime will be set when StartTimer is called. For now, set it to
		//something impossibly far in the future.
		fireTime: time.Now().Add(time.Hour * 100000),
		game:     game,
		move:     move,
	}
	t.nextId++

	t.recordsById[record.id] = record

	heap.Push(&t.records, record)

	return record.id
}

//StartTimer actually triggers a timer that was previously PrepareTimer'd to
//start counting down.
func (t *timerManager) StartTimer(id int) {

	if t.TimerActive(id) {
		return
	}

	record := t.recordsById[id]

	if record == nil {
		return
	}

	record.fireTime = time.Now().Add(record.duration)
	record.duration = 0

	heap.Fix(&t.records, record.index)
}

//TimerActive returns if the timer is active and counting down.
func (t *timerManager) TimerActive(id int) bool {
	record := t.recordsById[id]

	if record == nil {
		return false
	}

	if record.duration > 0 {
		return false
	}

	return true
}

func (t *timerManager) GetTimerRemaining(id int) time.Duration {
	record := t.recordsById[id]

	if record == nil {
		return 0
	}

	return record.TimeRemaining()
}

func (t *timerManager) CancelTimer(id int) {
	record := t.recordsById[id]

	if record == nil {
		return
	}

	heap.Remove(&t.records, record.index)

	record.index = -1

	delete(t.recordsById, record.id)

}

//Should be called regularly by the manager to tell this to check and see if
//any timers have fired, and execute them if so.
func (t *timerManager) Tick() {
	for t.nextTimerFired() {
		record := t.popNext()
		if record == nil {
			continue
		}

		if err := <-record.game.ProposeMove(record.move, AdminPlayerIndex); err != nil {
			//TODO: log the error or something
			t.manager.Logger().Info("When timer failed the move could not be made: ", err, record.move)
		}
	}
}

//Whether the next timer in the queue is already fired
func (t *timerManager) nextTimerFired() bool {
	if len(t.records) == 0 {
		return false
	}

	record := t.records[0]

	return record.TimeRemaining() <= 0
}

func (t *timerManager) popNext() *timerRecord {
	if !t.nextTimerFired() {
		return nil
	}

	x := heap.Pop(&t.records)

	record := x.(*timerRecord)

	delete(t.recordsById, record.id)

	return record
}

func (t timerQueue) Len() int {
	return len(t)
}

func (t timerQueue) Less(i, j int) bool {
	return t[i].fireTime.Sub(t[j].fireTime) < 0
}

func (t timerQueue) Swap(i, j int) {
	t[i], t[j] = t[j], t[i]
	t[i].index = i
	t[j].index = j
}

//DO NOT USE THIS DIRECTLY. Use heap.Push(t)
func (t *timerQueue) Push(x interface{}) {
	n := len(*t)
	item := x.(*timerRecord)
	item.index = n
	*t = append(*t, item)
}

//DO NOT USE THIS DIRECTLY. Use heap.Pop()
func (t *timerQueue) Pop() interface{} {
	old := *t
	n := len(old)
	item := old[n-1]
	item.index = -1
	*t = old[0 : n-1]
	return item
}
<commit_msg>Timer gets private importFrom method. Part of #519.<commit_after>package boardgame

import (
	"container/heap"
	"time"
)

//A Timer is a type of property that can be used in states that represents a
//countdown. The MutableTimer interface includes mutator methods as well. See
//the package documentation for more on timers.
type Timer interface {
	Active() bool
	TimeLeft() time.Duration
	copy() Timer
	id() int
	state() *state
	setState(*state)
}

//MutableTimer is a Timer that also includes mutator methods.
type MutableTimer interface {
	Timer
	Start(time.Duration, Move)
	Cancel() bool
	importFrom(other Timer) error
	mutableCopy() MutableTimer
}

type timer struct {
	//Id will be an opaque identifier that is used to keep track of the
	//corresponding underlying Timer object in the game engine. It is not
	//meaningful to inspect yourself and should not be modified.
	Id       int
	statePtr *state
}

func NewTimer() MutableTimer {
	return &timer{}
}

func (t *timer) importFrom(other Timer) error {
	t.Id = other.id()
	return nil
}

func (t *timer) id() int {
	return t.Id
}

func (t *timer) state() *state {
	return t.statePtr
}

func (t *timer) setState(state *state) {
	t.statePtr = state
}

func (t *timer) copy() Timer {
	return t.mutableCopy()
}

func (t *timer) mutableCopy() MutableTimer {
	var result timer
	result = *t
	return &result
}

func (t *timer) MarshalJSON() ([]byte, error) {
	obj := map[string]interface{}{
		"Id": t.Id,
		//TimeLeft is only ever for the client (it's not read back in when
		//deserialized), so put it in the more traditional milliseconds units,
		//not nanoseconds.
		"TimeLeft": t.TimeLeft() / time.Millisecond,
	}

	return DefaultMarshalJSON(obj)
}

//Active returns true if the timer is active and counting down.
func (t *timer) Active() bool {
	return t.statePtr.game.manager.timers.TimerActive(t.Id)
}

//TimeLeft returns the number of nanoseconds left until this timer fires.
func (t *timer) TimeLeft() time.Duration {
	return t.statePtr.game.manager.timers.GetTimerRemaining(t.Id)
}

//Start starts the timer. After duration has passed, the Move will be proposed
//via proposeMove. If the timer is already active, it will be canceled before
//the new timer is configured.
func (t *timer) Start(duration time.Duration, move Move) {

	if t.Active() {
		t.Cancel()
	}

	game := t.statePtr.game
	manager := game.manager

	t.Id = manager.timers.PrepareTimer(duration, game, move)

	t.statePtr.timersToStart = append(t.statePtr.timersToStart, t.Id)
}

//Cancel cancels an active timer. If the timer is not active, it has no
//effect. Returns true if the timer was active and canceled, false if the
//timer was not active.
func (t *timer) Cancel() bool {

	wasActive := t.Active()

	manager := t.statePtr.game.manager

	manager.timers.CancelTimer(t.Id)

	//Technically there's a case where Start() was called, but the state was
	//never fully committed. However, StartTimer() on a canceled timer is a
	//no-op so it's fine.

	t.Id = 0

	return wasActive
}

type timerRecord struct {
	id    int
	index int
	//When the timer should fire. Set after the timer is fully Started().
	//Before that it is impossibly far in the future.
	fireTime time.Time
	//The duration we were configured with. Only set when the timer is
	//Prepared() but not yet Started().
	duration time.Duration
	game     *Game
	move     Move
}

func (t *timerRecord) TimeRemaining() time.Duration {

	//Before a timer is Started(), just say its duration as the time
	//remaining.
	if t.duration > 0 {
		return t.duration
	}

	duration := t.fireTime.Sub(time.Now())

	if duration < 0 {
		duration = 0
	}

	return duration
}

type timerQueue []*timerRecord

type timerManager struct {
	nextId      int
	records     timerQueue
	recordsById map[int]*timerRecord
	manager     *GameManager
}

func newTimerManager(gameManager *GameManager) *timerManager {
	return &timerManager{
		//the default id in TimerProps is 0, so we should start beyond that.
		nextId:      1,
		records:     make(timerQueue, 0),
		recordsById: make(map[int]*timerRecord),
		manager:     gameManager,
	}
}

//PrepareTimer creates a timer entry and gets it ready and an Id allocated.
//However, the timer doesn't actually start counting down until
//manager.StartTimer(id) is called.
func (t *timerManager) PrepareTimer(duration time.Duration, game *Game, move Move) int {
	record := &timerRecord{
		id:       t.nextId,
		index:    -1,
		duration: duration,
		//fireTime will be set when StartTimer is called. For now, set it to
		//something impossibly far in the future.
		fireTime: time.Now().Add(time.Hour * 100000),
		game:     game,
		move:     move,
	}
	t.nextId++

	t.recordsById[record.id] = record

	heap.Push(&t.records, record)

	return record.id
}

//StartTimer actually triggers a timer that was previously PrepareTimer'd to
//start counting down.
func (t *timerManager) StartTimer(id int) {

	if t.TimerActive(id) {
		return
	}

	record := t.recordsById[id]

	if record == nil {
		return
	}

	record.fireTime = time.Now().Add(record.duration)
	record.duration = 0

	heap.Fix(&t.records, record.index)
}

//TimerActive returns if the timer is active and counting down.
func (t *timerManager) TimerActive(id int) bool {
	record := t.recordsById[id]

	if record == nil {
		return false
	}

	if record.duration > 0 {
		return false
	}

	return true
}

func (t *timerManager) GetTimerRemaining(id int) time.Duration {
	record := t.recordsById[id]

	if record == nil {
		return 0
	}

	return record.TimeRemaining()
}

func (t *timerManager) CancelTimer(id int) {
	record := t.recordsById[id]

	if record == nil {
		return
	}

	heap.Remove(&t.records, record.index)

	record.index = -1

	delete(t.recordsById, record.id)

}

//Should be called regularly by the manager to tell this to check and see if
//any timers have fired, and execute them if so.
func (t *timerManager) Tick() {
	for t.nextTimerFired() {
		record := t.popNext()
		if record == nil {
			continue
		}

		if err := <-record.game.ProposeMove(record.move, AdminPlayerIndex); err != nil {
			//TODO: log the error or something
			t.manager.Logger().Info("When timer failed the move could not be made: ", err, record.move)
		}
	}
}

//Whether the next timer in the queue is already fired
func (t *timerManager) nextTimerFired() bool {
	if len(t.records) == 0 {
		return false
	}

	record := t.records[0]

	return record.TimeRemaining() <= 0
}

func (t *timerManager) popNext() *timerRecord {
	if !t.nextTimerFired() {
		return nil
	}

	x := heap.Pop(&t.records)

	record := x.(*timerRecord)

	delete(t.recordsById, record.id)

	return record
}

func (t timerQueue) Len() int {
	return len(t)
}

func (t timerQueue) Less(i, j int) bool {
	return t[i].fireTime.Sub(t[j].fireTime) < 0
}

func (t timerQueue) Swap(i, j int) {
	t[i], t[j] = t[j], t[i]
	t[i].index = i
	t[j].index = j
}

//DO NOT USE THIS DIRECTLY. Use heap.Push(t)
func (t *timerQueue) Push(x interface{}) {
	n := len(*t)
	item := x.(*timerRecord)
	item.index = n
	*t = append(*t, item)
}

//DO NOT USE THIS DIRECTLY. Use heap.Pop()
func (t *timerQueue) Pop() interface{} {
	old := *t
	n := len(old)
	item := old[n-1]
	item.index = -1
	*t = old[0 : n-1]
	return item
}
<|endoftext|>