<commit_before>// +build ignore

package main

import (
	"fmt"
	"os"
	"sort"
	"strings"

	"github.com/PuerkitoBio/goquery"
)

type Event struct {
	Name string
	Link string
	Desc string
}

func main() {
	nameMap := map[string]string{
		"afterprint":               "AfterPrint",
		"animationend":             "AnimationEnd",
		"animationiteration":       "AnimationIteration",
		"animationstart":           "AnimationStart",
		"audioprocess":             "AudioProcess",
		"audioend":                 "AudioEnd",
		"audiostart":               "AudioStart",
		"beforeprint":              "BeforePrint",
		"beforeunload":             "BeforeUnload",
		"canplay":                  "CanPlay",
		"canplaythrough":           "CanPlayThrough",
		"chargingchange":           "ChargingChange",
		"chargingtimechange":       "ChargingTimeChange",
		"compassneedscalibration":  "CompassNeedsCalibration",
		"compositionend":           "CompositionEnd",
		"compositionstart":         "CompositionStart",
		"compositionupdate":        "CompositionUpdate",
		"contextmenu":              "ContextMenu",
		"dblclick":                 "DoubleClick",
		"devicelight":              "DeviceLight",
		"devicemotion":             "DeviceMotion",
		"deviceorientation":        "DeviceOrientation",
		"deviceproximity":          "DeviceProximity",
		"dischargingtimechange":    "DischargingTimeChange",
		"dragend":                  "DragEnd",
		"dragenter":                "DragEnter",
		"dragleave":                "DragLeave",
		"dragover":                 "DragOver",
		"dragstart":                "DragStart",
		"durationchange":           "DurationChange",
		"focusin":                  "FocusIn",
		"focusout":                 "FocusOut",
		"fullscreenchange":         "FullScreenChange",
		"fullscreenerror":          "FullScreenError",
		"gamepadconnected":         "GamepadConnected",
		"gamepaddisconnected":      "GamepadDisconnected",
		"gotpointercapture":        "GotPointerCapture",
		"hashchange":               "HashChange",
		"keydown":                  "KeyDown",
		"keypress":                 "KeyPress",
		"keyup":                    "KeyUp",
		"languagechange":           "LanguageChange",
		"levelchange":              "LevelChange",
		"loadeddata":               "LoadedData",
		"loadedmetadata":           "LoadedMetadata",
		"loadend":                  "LoadEnd",
		"loadstart":                "LoadStart",
		"lostpointercapture":       "LostPointerCapture",
		"mousedown":                "MouseDown",
		"mouseenter":               "MouseEnter",
		"mouseleave":               "MouseLeave",
		"mousemove":                "MouseMove",
		"mouseout":                 "MouseOut",
		"mouseover":                "MouseOver",
		"mouseup":                  "MouseUp",
		"noupdate":                 "NoUpdate",
		"nomatch":                  "NoMatch",
		"notificationclick":        "NotificationClick",
		"orientationchange":        "OrientationChange",
		"pagehide":                 "PageHide",
		"pageshow":                 "PageShow",
		"pointercancel":            "PointerCancel",
		"pointerdown":              "PointerDown",
		"pointerenter":             "PointerEnter",
		"pointerleave":             "PointerLeave",
		"pointerlockchange":        "PointerLockChange",
		"pointerlockerror":         "PointerLockError",
		"pointermove":              "PointerMove",
		"pointerout":               "PointerOut",
		"pointerover":              "PointerOver",
		"pointerup":                "PointerUp",
		"popstate":                 "PopState",
		"pushsubscriptionchange":   "PushSubscriptionChange",
		"ratechange":               "RateChange",
		"readystatechange":         "ReadyStateChange",
		"resourcetimingbufferfull": "ResourceTimingBufferFull",
		"selectstart":              "SelectStart",
		"selectionchange":          "SelectionChange",
		"soundend":                 "SoundEnd",
		"soundstart":               "SoundStart",
		"speechend":                "SpeechEnd",
		"speechstart":              "SpeechStart",
		"timeupdate":               "TimeUpdate",
		"touchcancel":              "TouchCancel",
		"touchend":                 "TouchEnd",
		"touchenter":               "TouchEnter",
		"touchleave":               "TouchLeave",
		"touchmove":                "TouchMove",
		"touchstart":               "TouchStart",
		"transitionend":            "TransitionEnd",
		"updateready":              "UpdateReady",
		"upgradeneeded":            "UpgradeNeeded",
		"userproximity":            "UserProximity",
		"versionchange":            "VersionChange",
		"visibilitychange":         "VisibilityChange",
		"voiceschanged":            "VoicesChanged",
		"volumechange":             "VolumeChange",
	}

	doc, err := goquery.NewDocument("https://developer.mozilla.org/en-US/docs/Web/Events")
	if err != nil {
		panic(err)
	}

	events := make(map[string]*Event)

	doc.Find(".standard-table").Eq(0).Find("tr").Each(func(i int, s *goquery.Selection) {
		cols := s.Find("td")
		if cols.Length() == 0 || cols.Find(".icon-thumbs-down-alt").Length() != 0 {
			return
		}
		link := cols.Eq(0).Find("a").Eq(0)
		var e Event
		e.Name = link.Text()
		e.Link, _ = link.Attr("href")
		e.Desc = strings.TrimSpace(cols.Eq(3).Text())
		if e.Desc == "" {
			e.Desc = "(no documentation)"
		}

		funName := nameMap[e.Name]
		if funName == "" {
			funName = capitalize(e.Name)
		}

		events[funName] = &e
	})

	var names []string
	for name := range events {
		names = append(names, name)
	}
	sort.Strings(names)

	file, err := os.Create("event.gen.go")
	if err != nil {
		panic(err)
	}
	defer file.Close()

	fmt.Fprint(file, `//go:generate go run generate.go

// Package event defines markup to bind DOM events.
//
// Generated from "Event reference" by Mozilla Contributors, https://developer.mozilla.org/en-US/docs/Web/Events, licensed under CC-BY-SA 2.5.
package event

import "github.com/gopherjs/vecty"
`)

	for _, name := range names {
		e := events[name]
		fmt.Fprintf(file, `
// %s
//
// https://developer.mozilla.org%s
func %s(listener func(*vecty.Event)) *vecty.EventListener {
	return &vecty.EventListener{Name: "%s", Listener: listener}
}
`, e.Desc, e.Link[6:], name, e.Name)
	}
}

func capitalize(s string) string {
	return strings.ToUpper(s[:1]) + s[1:]
}
<commit_msg>event: add name translations for vrdisplay*** event types<commit_after>// +build ignore

package main

import (
	"fmt"
	"os"
	"sort"
	"strings"

	"github.com/PuerkitoBio/goquery"
)

type Event struct {
	Name string
	Link string
	Desc string
}

func main() {
	nameMap := map[string]string{
		"afterprint":               "AfterPrint",
		"animationend":             "AnimationEnd",
		"animationiteration":       "AnimationIteration",
		"animationstart":           "AnimationStart",
		"audioprocess":             "AudioProcess",
		"audioend":                 "AudioEnd",
		"audiostart":               "AudioStart",
		"beforeprint":              "BeforePrint",
		"beforeunload":             "BeforeUnload",
		"canplay":                  "CanPlay",
		"canplaythrough":           "CanPlayThrough",
		"chargingchange":           "ChargingChange",
		"chargingtimechange":       "ChargingTimeChange",
		"compassneedscalibration":  "CompassNeedsCalibration",
		"compositionend":           "CompositionEnd",
		"compositionstart":         "CompositionStart",
		"compositionupdate":        "CompositionUpdate",
		"contextmenu":              "ContextMenu",
		"dblclick":                 "DoubleClick",
		"devicelight":              "DeviceLight",
		"devicemotion":             "DeviceMotion",
		"deviceorientation":        "DeviceOrientation",
		"deviceproximity":          "DeviceProximity",
		"dischargingtimechange":    "DischargingTimeChange",
		"dragend":                  "DragEnd",
		"dragenter":                "DragEnter",
		"dragleave":                "DragLeave",
		"dragover":                 "DragOver",
		"dragstart":                "DragStart",
		"durationchange":           "DurationChange",
		"focusin":                  "FocusIn",
		"focusout":                 "FocusOut",
		"fullscreenchange":         "FullScreenChange",
		"fullscreenerror":          "FullScreenError",
		"gamepadconnected":         "GamepadConnected",
		"gamepaddisconnected":      "GamepadDisconnected",
		"gotpointercapture":        "GotPointerCapture",
		"hashchange":               "HashChange",
		"keydown":                  "KeyDown",
		"keypress":                 "KeyPress",
		"keyup":                    "KeyUp",
		"languagechange":           "LanguageChange",
		"levelchange":              "LevelChange",
		"loadeddata":               "LoadedData",
		"loadedmetadata":           "LoadedMetadata",
		"loadend":                  "LoadEnd",
		"loadstart":                "LoadStart",
		"lostpointercapture":       "LostPointerCapture",
		"mousedown":                "MouseDown",
		"mouseenter":               "MouseEnter",
		"mouseleave":               "MouseLeave",
		"mousemove":                "MouseMove",
		"mouseout":                 "MouseOut",
		"mouseover":                "MouseOver",
		"mouseup":                  "MouseUp",
		"noupdate":                 "NoUpdate",
		"nomatch":                  "NoMatch",
		"notificationclick":        "NotificationClick",
		"orientationchange":        "OrientationChange",
		"pagehide":                 "PageHide",
		"pageshow":                 "PageShow",
		"pointercancel":            "PointerCancel",
		"pointerdown":              "PointerDown",
		"pointerenter":             "PointerEnter",
		"pointerleave":             "PointerLeave",
		"pointerlockchange":        "PointerLockChange",
		"pointerlockerror":         "PointerLockError",
		"pointermove":              "PointerMove",
		"pointerout":               "PointerOut",
		"pointerover":              "PointerOver",
		"pointerup":                "PointerUp",
		"popstate":                 "PopState",
		"pushsubscriptionchange":   "PushSubscriptionChange",
		"ratechange":               "RateChange",
		"readystatechange":         "ReadyStateChange",
		"resourcetimingbufferfull": "ResourceTimingBufferFull",
		"selectstart":              "SelectStart",
		"selectionchange":          "SelectionChange",
		"soundend":                 "SoundEnd",
		"soundstart":               "SoundStart",
		"speechend":                "SpeechEnd",
		"speechstart":              "SpeechStart",
		"timeupdate":               "TimeUpdate",
		"touchcancel":              "TouchCancel",
		"touchend":                 "TouchEnd",
		"touchenter":               "TouchEnter",
		"touchleave":               "TouchLeave",
		"touchmove":                "TouchMove",
		"touchstart":               "TouchStart",
		"transitionend":            "TransitionEnd",
		"updateready":              "UpdateReady",
		"upgradeneeded":            "UpgradeNeeded",
		"userproximity":            "UserProximity",
		"versionchange":            "VersionChange",
		"visibilitychange":         "VisibilityChange",
		"voiceschanged":            "VoicesChanged",
		"volumechange":             "VolumeChange",
		"vrdisplayconnected":       "VRDisplayConnected",
		"vrdisplaydisconnected":    "VRDisplayDisconnected",
		"vrdisplaypresentchange":   "VRDisplayPresentChange",
	}

	doc, err := goquery.NewDocument("https://developer.mozilla.org/en-US/docs/Web/Events")
	if err != nil {
		panic(err)
	}

	events := make(map[string]*Event)

	doc.Find(".standard-table").Eq(0).Find("tr").Each(func(i int, s *goquery.Selection) {
		cols := s.Find("td")
		if cols.Length() == 0 || cols.Find(".icon-thumbs-down-alt").Length() != 0 {
			return
		}
		link := cols.Eq(0).Find("a").Eq(0)
		var e Event
		e.Name = link.Text()
		e.Link, _ = link.Attr("href")
		e.Desc = strings.TrimSpace(cols.Eq(3).Text())
		if e.Desc == "" {
			e.Desc = "(no documentation)"
		}

		funName := nameMap[e.Name]
		if funName == "" {
			funName = capitalize(e.Name)
		}

		events[funName] = &e
	})

	var names []string
	for name := range events {
		names = append(names, name)
	}
	sort.Strings(names)

	file, err := os.Create("event.gen.go")
	if err != nil {
		panic(err)
	}
	defer file.Close()

	fmt.Fprint(file, `//go:generate go run generate.go

// Package event defines markup to bind DOM events.
//
// Generated from "Event reference" by Mozilla Contributors, https://developer.mozilla.org/en-US/docs/Web/Events, licensed under CC-BY-SA 2.5.
package event

import "github.com/gopherjs/vecty"
`)

	for _, name := range names {
		e := events[name]
		fmt.Fprintf(file, `
// %s
//
// https://developer.mozilla.org%s
func %s(listener func(*vecty.Event)) *vecty.EventListener {
	return &vecty.EventListener{Name: "%s", Listener: listener}
}
`, e.Desc, e.Link[6:], name, e.Name)
	}
}

func capitalize(s string) string {
	return strings.ToUpper(s[:1]) + s[1:]
}
<|endoftext|>


<commit_before>// Copyright 2016 OpenConfigd Project.
//
// 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 main

import (
	"fmt"
	"os"
	"os/signal"
	"runtime"
	"syscall"

	"github.com/coreswitch/component"
	"github.com/coreswitch/openconfigd/config"
	"github.com/jessevdk/go-flags"
	log "github.com/sirupsen/logrus"
)

func EsiHook() {
	if _, err := os.Stat("/etc/esi/env"); err == nil {
		config.RibdAsyncUpdate = true
	}
}

func main() {
	fmt.Println("Starting openconfigd.")

	EsiHook()

	var opts struct {
		ConfigActiveFile string `short:"c" long:"config-file" description:"active config file name" default:"openconfigd.conf"`
		ConfigFileDir    string `short:"p" long:"config-dir" description:"config file directory" default:"/usr/local/etc"`
		YangPaths        string `short:"y" long:"yang-paths" description:"comma separated YANG load path directories"`
		TwoPhaseCommit   bool   `short:"2" long:"two-phase" description:"two phase commit"`
		ZeroConfig       bool   `short:"z" long:"zero-config" description:"Do not save or load config other than openconfigd.conf"`
	}

	args, err := flags.Parse(&opts)
	if err != nil {
		os.Exit(1)
	}

	// Arguments are YANG module names. When no modules is specified "coreswitch"
	// is set as default YANG module name.
	if len(args) == 0 {
		args = []string{"coreswitch"}
	}

	// Set log output.
	log.SetOutput(os.Stdout)
	log.SetFormatter(&log.JSONFormatter{})

	// Set maxprocs
	runtime.GOMAXPROCS(runtime.NumCPU())

	// YANG Component
	yangComponent := &config.YangComponent{
		YangPaths:   opts.YangPaths,
		YangModules: args,
	}

	// Config component
	configComponent := &config.ConfigComponent{
		ConfigFileDir:    opts.ConfigFileDir,
		ConfigActiveFile: opts.ConfigActiveFile,
		TwoPhaseCommit:   opts.TwoPhaseCommit,
		ZeroConfig:       opts.ZeroConfig,
	}

	// CLI component
	cliComponent := &config.CliComponent{}

	// Rpc Component
	rpcComponent := &config.RpcComponent{}

	systemMap := component.SystemMap{
		"yang":   yangComponent,
		"cli":    component.ComponentWith(cliComponent, "yang"),
		"config": component.ComponentWith(configComponent, "yang", "cli"),
		"rpc":    component.ComponentWith(rpcComponent, "config"),
	}

	// Register clearn up function.
	c := make(chan os.Signal, 2)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go func() {
		<-c
		systemMap.Stop()
		os.Exit(1)
	}()

	// Start components.
	systemMap.Start()
}
<commit_msg>Set default RpcEndPoint.<commit_after>// Copyright 2016 OpenConfigd Project.
//
// 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 main

import (
	"fmt"
	"os"
	"os/signal"
	"runtime"
	"syscall"

	"github.com/coreswitch/component"
	"github.com/coreswitch/openconfigd/config"
	"github.com/jessevdk/go-flags"
	log "github.com/sirupsen/logrus"
)

func EsiHook() {
	if _, err := os.Stat("/etc/esi/env"); err == nil {
		config.RibdAsyncUpdate = true
	}
}

func main() {
	fmt.Println("Starting openconfigd.")

	EsiHook()

	var opts struct {
		ConfigActiveFile string `short:"c" long:"config-file" description:"active config file name" default:"openconfigd.conf"`
		ConfigFileDir    string `short:"p" long:"config-dir" description:"config file directory" default:"/usr/local/etc"`
		RpcEndPoint      string `short:"g" long:"grpc-endpoint" description:"Grpc End Point" default:"127.0.0.1:2650"`
		YangPaths        string `short:"y" long:"yang-paths" description:"comma separated YANG load path directories"`
		TwoPhaseCommit   bool   `short:"2" long:"two-phase" description:"two phase commit"`
		ZeroConfig       bool   `short:"z" long:"zero-config" description:"Do not save or load config other than openconfigd.conf"`
	}

	args, err := flags.Parse(&opts)
	if err != nil {
		os.Exit(1)
	}

	// Arguments are YANG module names. When no modules is specified "coreswitch"
	// is set as default YANG module name.
	if len(args) == 0 {
		args = []string{"coreswitch"}
	}

	// Set log output.
	log.SetOutput(os.Stdout)
	log.SetFormatter(&log.JSONFormatter{})

	// Set maxprocs
	runtime.GOMAXPROCS(runtime.NumCPU())

	// YANG Component
	yangComponent := &config.YangComponent{
		YangPaths:   opts.YangPaths,
		YangModules: args,
	}

	// Config component
	configComponent := &config.ConfigComponent{
		ConfigFileDir:    opts.ConfigFileDir,
		ConfigActiveFile: opts.ConfigActiveFile,
		TwoPhaseCommit:   opts.TwoPhaseCommit,
		ZeroConfig:       opts.ZeroConfig,
	}

	// CLI component
	cliComponent := &config.CliComponent{}

	// Rpc Component
	rpcComponent := &config.RpcComponent{
		GrpcEndpoint: opts.RpcEndPoint,
	}

	systemMap := component.SystemMap{
		"yang":   yangComponent,
		"cli":    component.ComponentWith(cliComponent, "yang"),
		"config": component.ComponentWith(configComponent, "yang", "cli"),
		"rpc":    component.ComponentWith(rpcComponent, "config"),
	}

	// Register clearn up function.
	c := make(chan os.Signal, 2)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go func() {
		<-c
		systemMap.Stop()
		os.Exit(1)
	}()

	// Start components.
	systemMap.Start()
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Gocov Authors.
//
// 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 main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/axw/gocov"
	"go/ast"
	"go/build"
	"go/parser"
	"go/printer"
	"go/token"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"sort"
	"strings"
)

const gocovPackagePath = "github.com/axw/gocov"
const instrumentedPathPrefix = gocovPackagePath + "/instrumented"

func usage() {
	fmt.Fprintf(os.Stderr, "Usage:\n\n\tgocov command [arguments]\n\n")
	fmt.Fprintf(os.Stderr, "The commands are:\n\n")
	fmt.Fprintf(os.Stderr, "\tannotate\n")
	fmt.Fprintf(os.Stderr, "\ttest\n")
	fmt.Fprintf(os.Stderr, "\treport\n")
	fmt.Fprintf(os.Stderr, "\n")
	flag.PrintDefaults()
	os.Exit(2)
}

var (
	testFlags       = flag.NewFlagSet("test", flag.ExitOnError)
	testExcludeFlag = testFlags.String(
		"exclude", "",
		"print the name of the temporary work directory "+
			"and do not delete it when exiting.")
	testExcludeGorootFlag = testFlags.Bool(
		"exclude-goroot", true,
		"exclude packages in GOROOT from instrumentation")
	testWorkFlag = testFlags.Bool(
		"work", false,
		"packages to exclude, separated by comma")
	verbose bool
)

func init() {
	testFlags.BoolVar(&verbose, "v", false, "verbose")
}

type instrumenter struct {
	gopath       string // temporary gopath
	excluded     []string
	instrumented map[string]*gocov.Package
	processed    map[string]struct{}
}

func putenv(env []string, key, value string) []string {
	for i, s := range env {
		if strings.HasPrefix(s, key+"=") {
			env[i] = key + "=" + value
			return env
		}
	}
	return append(env, key+"="+value)
}

func parsePackage(path string, fset *token.FileSet) (*build.Package, *ast.Package, error) {
	cwd, err := os.Getwd()
	if err != nil {
		return nil, nil, err
	}
	p, err := build.Import(path, cwd, 0)
	if err != nil {
		return nil, nil, err
	}
	goFiles := append(p.GoFiles[:], p.CgoFiles...)
	sort.Strings(goFiles)
	filter := func(f os.FileInfo) bool {
		name := f.Name()
		i := sort.SearchStrings(goFiles, name)
		return i < len(goFiles) && goFiles[i] == name
	}
	mode := parser.DeclarationErrors | parser.ParseComments
	pkgs, err := parser.ParseDir(fset, p.Dir, filter, mode)
	if err != nil {
		return nil, nil, err
	}
	return p, pkgs[p.Name], err
}

func symlinkHierarchy(src, dst string) error {
	fn := func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		rel, err := filepath.Rel(src, path)
		if err != nil {
			return err
		}

		target := filepath.Join(dst, rel)
		if _, err = os.Stat(target); err == nil {
			return nil
		}

		if info.IsDir() {
			return os.MkdirAll(target, 0700)
		} else {
			err = os.Symlink(path, target)
			if err != nil {
				srcfile, err := os.Open(path)
				if err != nil {
					return err
				}
				defer srcfile.Close()
				dstfile, err := os.OpenFile(
					target, os.O_RDWR|os.O_CREATE, 0600)
				if err != nil {
					return err
				}
				defer dstfile.Close()
				_, err = io.Copy(dstfile, srcfile)
				return err
			}
		}
		return nil
	}
	return filepath.Walk(src, fn)
}

// FIXME(axw)
//
// As we change the name of the package to avoid being obscured by GOROOT, we
// can't instrument packages that have Go functions implemented in C, such as
// those below.
//
// It may be preferable to have a faked GOROOT, but we'll need to come up with
// a way to avoid the import loop introduced by importing gocov into the
// instrumented pakcage.
//
func instrumentable(path string) bool {
	switch path {
	case "C": fallthrough
	case "reflect": fallthrough
	case "runtime": fallthrough
	case "os": fallthrough
	case "sync": fallthrough
	case "syscall": fallthrough
	case "time": fallthrough
	case "testing": fallthrough
	case "unsafe": return false
	}
	return true
}

func (in *instrumenter) instrumentPackage(pkgpath string) error {
	if _, already := in.processed[pkgpath]; already {
		return nil
	}
	defer func(){
		if _, already := in.instrumented[pkgpath]; !already {
			in.processed[pkgpath] = struct{}{}
		}
	}()

	// Certain packages should always be skipped.
	if !instrumentable(pkgpath) {
		if verbose {
			fmt.Fprintf(os.Stderr, "skipping uninstrumentable package %q\n", pkgpath)
		}
		return nil
	}

	// Ignore explicitly excluded packages.
	if i := sort.SearchStrings(in.excluded, pkgpath); i < len(in.excluded) {
		if in.excluded[i] == pkgpath {
			if verbose {
				fmt.Fprintf(os.Stderr, "skipping excluded package %q\n", pkgpath)
			}
			return nil
		}
	}

	fset := token.NewFileSet()
	buildpkg, pkg, err := parsePackage(pkgpath, fset)
	if err != nil {
		return err
	}
	if buildpkg.Goroot && *testExcludeGorootFlag {
		if verbose {
			fmt.Fprintf(os.Stderr, "skipping GOROOT package %q\n", pkgpath)
		}
		return nil
	}

	in.instrumented[pkgpath] = nil // created in first instrumented file
	if verbose {
		fmt.Fprintf(os.Stderr, "instrumenting package %q\n", pkgpath)
	}

	imports := buildpkg.Imports[:]
	imports = append(imports, buildpkg.TestImports...)
	imports = append(imports, buildpkg.XTestImports...)
	for _, subpkgpath := range imports {
		if _, done := in.instrumented[subpkgpath]; !done {
			err = in.instrumentPackage(subpkgpath)
			if err != nil {
				return err
			}
		}
	}

	// Fix imports in test files, but don't instrument them.
	rewriteFiles := make(map[string]*ast.File)
	testGoFiles := buildpkg.TestGoFiles[:]
	testGoFiles = append(testGoFiles, buildpkg.XTestGoFiles...)
	for _, filename := range testGoFiles {
		path := filepath.Join(buildpkg.Dir, filename)
		mode := parser.DeclarationErrors | parser.ParseComments
		file, err := parser.ParseFile(fset, path, nil, mode)
		if err != nil {
			return err
		}
		in.redirectImports(file)
		rewriteFiles[filename] = file
	}

	// Clone the directory structure, symlinking files (if possible),
	// otherwise copying the files. Instrumented files will replace
	// the symlinks with new files.
	cloneDir := filepath.Join(in.gopath, "src", instrumentedPathPrefix, pkgpath)
	err = symlinkHierarchy(buildpkg.Dir, cloneDir)
	if err != nil {
		return err
	}
	for filename, f := range pkg.Files {
		err := in.instrumentFile(f, fset, pkgpath)
		if err != nil {
			return err
		}
		rewriteFiles[filename] = f
	}
	for filename, f := range rewriteFiles {
		filepath := filepath.Join(cloneDir, filepath.Base(filename))
		err = os.Remove(filepath)
		if err != nil {
			return err
		}
		file, err := os.OpenFile(filepath, os.O_RDWR|os.O_CREATE, 0600)
		if err != nil {
			return err
		}
		printer.Fprint(file, fset, f) // TODO check err?
		err = file.Close()
		if err != nil {
			return err
		}
	}

	return nil
}

func marshalJson(packages []*gocov.Package) ([]byte, error) {
	return json.Marshal(struct{ Packages []*gocov.Package }{packages})
}

func unmarshalJson(data []byte) (packages []*gocov.Package, err error) {
	result := &struct{ Packages []*gocov.Package }{}
	err = json.Unmarshal(data, result)
	if err == nil {
		packages = result.Packages
	}
	return
}

func instrumentAndTest() (rc int) {
	testFlags.Parse(os.Args[2:])
	packageName := "."
	if testFlags.NArg() > 0 {
		packageName = testFlags.Arg(0)
	}

	tempDir, err := ioutil.TempDir("", "gocov")
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to create temporary GOPATH: %s", err)
		return 1
	}
	if *testWorkFlag {
		fmt.Fprintf(os.Stderr, "WORK=%s\n", tempDir)
	} else {
		defer func() {
			err := os.RemoveAll(tempDir)
			if err != nil {
				fmt.Fprintf(os.Stderr,
					"warning: failed to delete temporary GOPATH (%s)", tempDir)
			}
		}()
	}

	err = os.Mkdir(filepath.Join(tempDir, "src"), 0700)
	if err != nil {
		fmt.Fprintf(os.Stderr,
			"failed to create temporary src directory: %s", err)
		return 1
	}

	// Copy gocov into the temporary GOPATH, since otherwise it'll
	// be eclipsed by the instrumented packages root.
	if p, err := build.Import(gocovPackagePath, "", build.FindOnly); err == nil {
		err = symlinkHierarchy(p.Dir, filepath.Join(tempDir, "src", gocovPackagePath))
		if err != nil {
			fmt.Fprintf(os.Stderr, "failed to symlink gocov: %s", err)
			return 1
		}
	} else {
		fmt.Fprintf(os.Stderr, "failed to locate gocov: %s", err)
		return 1
	}

	var excluded []string
	if len(*testExcludeFlag) > 0 {
		excluded = strings.Split(*testExcludeFlag, ",")
		sort.Strings(excluded)
	}

	in := &instrumenter{
		gopath:       tempDir,
		instrumented: make(map[string]*gocov.Package),
		excluded:     excluded,
		processed:    make(map[string]struct{})}
	err = in.instrumentPackage(packageName)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to instrument package(%s): %s\n",
			packageName, err)
		return 1
	}

	// Run "go test".
	// TODO pass through test flags.
	outfilePath := filepath.Join(tempDir, "gocov.out")
	env := os.Environ()
	env = putenv(env, "GOCOVOUT", outfilePath)
	if gopath := os.Getenv("GOPATH"); gopath != "" {
		gopath = fmt.Sprintf("%s%c%s", tempDir, os.PathListSeparator, gopath)
		env = putenv(env, "GOPATH", gopath)
	} else {
		env = putenv(env, "GOPATH", tempDir)
	}
	args := []string{"test"}
	if verbose {
		args = append(args, "-v")
	}
	args = append(args, instrumentedPathPrefix + "/" + packageName)
	cmd := exec.Command("go", args...)
	cmd.Env = env
	cmd.Stdout = os.Stderr
	cmd.Stderr = os.Stderr
	err = cmd.Run()

	if err != nil {
		fmt.Fprintf(os.Stderr, "go test failed: %s\n", err)
		rc = 1
	}

	packages, err := gocov.ParseTrace(outfilePath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to parse gocov output: %s\n", err)
	} else {
		data, err := marshalJson(packages)
		if err != nil {
			fmt.Fprintf(os.Stderr, "failed to format as JSON: %s\n", err)
		} else {
			fmt.Println(string(data))
		}
	}
	return
}

func main() {
	flag.Usage = usage
	flag.Parse()
	command := ""
	if flag.NArg() > 0 {
		command = flag.Arg(0)
		switch command {
		case "annotate":
			os.Exit(annotateSource())
		case "report":
			os.Exit(reportCoverage())
		case "test":
			os.Exit(instrumentAndTest())
		//case "run"
		default:
			fmt.Fprintf(os.Stderr, "Unknown command: %#q\n\n", command)
			usage()
		}
	} else {
		usage()
	}
}
<commit_msg>Fix gocov test help usage, run go fmt.<commit_after>// Copyright (c) 2012 The Gocov Authors.
//
// 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 main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/axw/gocov"
	"go/ast"
	"go/build"
	"go/parser"
	"go/printer"
	"go/token"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"sort"
	"strings"
)

const gocovPackagePath = "github.com/axw/gocov"
const instrumentedPathPrefix = gocovPackagePath + "/instrumented"

func usage() {
	fmt.Fprintf(os.Stderr, "Usage:\n\n\tgocov command [arguments]\n\n")
	fmt.Fprintf(os.Stderr, "The commands are:\n\n")
	fmt.Fprintf(os.Stderr, "\tannotate\n")
	fmt.Fprintf(os.Stderr, "\ttest\n")
	fmt.Fprintf(os.Stderr, "\treport\n")
	fmt.Fprintf(os.Stderr, "\n")
	flag.PrintDefaults()
	os.Exit(2)
}

var (
	testFlags       = flag.NewFlagSet("test", flag.ExitOnError)
	testExcludeFlag = testFlags.String(
		"exclude", "",
		"packages to exclude, separated by comma")
	testExcludeGorootFlag = testFlags.Bool(
		"exclude-goroot", true,
		"exclude packages in GOROOT from instrumentation")
	testWorkFlag = testFlags.Bool(
		"work", false,
		"print the name of the temporary work directory "+
			"and do not delete it when exiting")
	verbose bool
)

func init() {
	testFlags.BoolVar(&verbose, "v", false, "verbose")
}

type instrumenter struct {
	gopath       string // temporary gopath
	excluded     []string
	instrumented map[string]*gocov.Package
	processed    map[string]struct{}
}

func putenv(env []string, key, value string) []string {
	for i, s := range env {
		if strings.HasPrefix(s, key+"=") {
			env[i] = key + "=" + value
			return env
		}
	}
	return append(env, key+"="+value)
}

func parsePackage(path string, fset *token.FileSet) (*build.Package, *ast.Package, error) {
	cwd, err := os.Getwd()
	if err != nil {
		return nil, nil, err
	}
	p, err := build.Import(path, cwd, 0)
	if err != nil {
		return nil, nil, err
	}
	goFiles := append(p.GoFiles[:], p.CgoFiles...)
	sort.Strings(goFiles)
	filter := func(f os.FileInfo) bool {
		name := f.Name()
		i := sort.SearchStrings(goFiles, name)
		return i < len(goFiles) && goFiles[i] == name
	}
	mode := parser.DeclarationErrors | parser.ParseComments
	pkgs, err := parser.ParseDir(fset, p.Dir, filter, mode)
	if err != nil {
		return nil, nil, err
	}
	return p, pkgs[p.Name], err
}

func symlinkHierarchy(src, dst string) error {
	fn := func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		rel, err := filepath.Rel(src, path)
		if err != nil {
			return err
		}

		target := filepath.Join(dst, rel)
		if _, err = os.Stat(target); err == nil {
			return nil
		}

		if info.IsDir() {
			return os.MkdirAll(target, 0700)
		} else {
			err = os.Symlink(path, target)
			if err != nil {
				srcfile, err := os.Open(path)
				if err != nil {
					return err
				}
				defer srcfile.Close()
				dstfile, err := os.OpenFile(
					target, os.O_RDWR|os.O_CREATE, 0600)
				if err != nil {
					return err
				}
				defer dstfile.Close()
				_, err = io.Copy(dstfile, srcfile)
				return err
			}
		}
		return nil
	}
	return filepath.Walk(src, fn)
}

// FIXME(axw)
//
// As we change the name of the package to avoid being obscured by GOROOT, we
// can't instrument packages that have Go functions implemented in C, such as
// those below.
//
// It may be preferable to have a faked GOROOT, but we'll need to come up with
// a way to avoid the import loop introduced by importing gocov into the
// instrumented pakcage.
//
func instrumentable(path string) bool {
	switch path {
	case "C":
		fallthrough
	case "reflect":
		fallthrough
	case "runtime":
		fallthrough
	case "os":
		fallthrough
	case "sync":
		fallthrough
	case "syscall":
		fallthrough
	case "time":
		fallthrough
	case "testing":
		fallthrough
	case "unsafe":
		return false
	}
	return true
}

func (in *instrumenter) instrumentPackage(pkgpath string) error {
	if _, already := in.processed[pkgpath]; already {
		return nil
	}
	defer func() {
		if _, already := in.instrumented[pkgpath]; !already {
			in.processed[pkgpath] = struct{}{}
		}
	}()

	// Certain packages should always be skipped.
	if !instrumentable(pkgpath) {
		if verbose {
			fmt.Fprintf(os.Stderr, "skipping uninstrumentable package %q\n", pkgpath)
		}
		return nil
	}

	// Ignore explicitly excluded packages.
	if i := sort.SearchStrings(in.excluded, pkgpath); i < len(in.excluded) {
		if in.excluded[i] == pkgpath {
			if verbose {
				fmt.Fprintf(os.Stderr, "skipping excluded package %q\n", pkgpath)
			}
			return nil
		}
	}

	fset := token.NewFileSet()
	buildpkg, pkg, err := parsePackage(pkgpath, fset)
	if err != nil {
		return err
	}
	if buildpkg.Goroot && *testExcludeGorootFlag {
		if verbose {
			fmt.Fprintf(os.Stderr, "skipping GOROOT package %q\n", pkgpath)
		}
		return nil
	}

	in.instrumented[pkgpath] = nil // created in first instrumented file
	if verbose {
		fmt.Fprintf(os.Stderr, "instrumenting package %q\n", pkgpath)
	}

	imports := buildpkg.Imports[:]
	imports = append(imports, buildpkg.TestImports...)
	imports = append(imports, buildpkg.XTestImports...)
	for _, subpkgpath := range imports {
		if _, done := in.instrumented[subpkgpath]; !done {
			err = in.instrumentPackage(subpkgpath)
			if err != nil {
				return err
			}
		}
	}

	// Fix imports in test files, but don't instrument them.
	rewriteFiles := make(map[string]*ast.File)
	testGoFiles := buildpkg.TestGoFiles[:]
	testGoFiles = append(testGoFiles, buildpkg.XTestGoFiles...)
	for _, filename := range testGoFiles {
		path := filepath.Join(buildpkg.Dir, filename)
		mode := parser.DeclarationErrors | parser.ParseComments
		file, err := parser.ParseFile(fset, path, nil, mode)
		if err != nil {
			return err
		}
		in.redirectImports(file)
		rewriteFiles[filename] = file
	}

	// Clone the directory structure, symlinking files (if possible),
	// otherwise copying the files. Instrumented files will replace
	// the symlinks with new files.
	cloneDir := filepath.Join(in.gopath, "src", instrumentedPathPrefix, pkgpath)
	err = symlinkHierarchy(buildpkg.Dir, cloneDir)
	if err != nil {
		return err
	}
	for filename, f := range pkg.Files {
		err := in.instrumentFile(f, fset, pkgpath)
		if err != nil {
			return err
		}
		rewriteFiles[filename] = f
	}
	for filename, f := range rewriteFiles {
		filepath := filepath.Join(cloneDir, filepath.Base(filename))
		err = os.Remove(filepath)
		if err != nil {
			return err
		}
		file, err := os.OpenFile(filepath, os.O_RDWR|os.O_CREATE, 0600)
		if err != nil {
			return err
		}
		printer.Fprint(file, fset, f) // TODO check err?
		err = file.Close()
		if err != nil {
			return err
		}
	}

	return nil
}

func marshalJson(packages []*gocov.Package) ([]byte, error) {
	return json.Marshal(struct{ Packages []*gocov.Package }{packages})
}

func unmarshalJson(data []byte) (packages []*gocov.Package, err error) {
	result := &struct{ Packages []*gocov.Package }{}
	err = json.Unmarshal(data, result)
	if err == nil {
		packages = result.Packages
	}
	return
}

func instrumentAndTest() (rc int) {
	testFlags.Parse(os.Args[2:])
	packageName := "."
	if testFlags.NArg() > 0 {
		packageName = testFlags.Arg(0)
	}

	tempDir, err := ioutil.TempDir("", "gocov")
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to create temporary GOPATH: %s", err)
		return 1
	}
	if *testWorkFlag {
		fmt.Fprintf(os.Stderr, "WORK=%s\n", tempDir)
	} else {
		defer func() {
			err := os.RemoveAll(tempDir)
			if err != nil {
				fmt.Fprintf(os.Stderr,
					"warning: failed to delete temporary GOPATH (%s)", tempDir)
			}
		}()
	}

	err = os.Mkdir(filepath.Join(tempDir, "src"), 0700)
	if err != nil {
		fmt.Fprintf(os.Stderr,
			"failed to create temporary src directory: %s", err)
		return 1
	}

	// Copy gocov into the temporary GOPATH, since otherwise it'll
	// be eclipsed by the instrumented packages root.
	if p, err := build.Import(gocovPackagePath, "", build.FindOnly); err == nil {
		err = symlinkHierarchy(p.Dir, filepath.Join(tempDir, "src", gocovPackagePath))
		if err != nil {
			fmt.Fprintf(os.Stderr, "failed to symlink gocov: %s", err)
			return 1
		}
	} else {
		fmt.Fprintf(os.Stderr, "failed to locate gocov: %s", err)
		return 1
	}

	var excluded []string
	if len(*testExcludeFlag) > 0 {
		excluded = strings.Split(*testExcludeFlag, ",")
		sort.Strings(excluded)
	}

	in := &instrumenter{
		gopath:       tempDir,
		instrumented: make(map[string]*gocov.Package),
		excluded:     excluded,
		processed:    make(map[string]struct{})}
	err = in.instrumentPackage(packageName)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to instrument package(%s): %s\n",
			packageName, err)
		return 1
	}

	// Run "go test".
	// TODO pass through test flags.
	outfilePath := filepath.Join(tempDir, "gocov.out")
	env := os.Environ()
	env = putenv(env, "GOCOVOUT", outfilePath)
	if gopath := os.Getenv("GOPATH"); gopath != "" {
		gopath = fmt.Sprintf("%s%c%s", tempDir, os.PathListSeparator, gopath)
		env = putenv(env, "GOPATH", gopath)
	} else {
		env = putenv(env, "GOPATH", tempDir)
	}
	args := []string{"test"}
	if verbose {
		args = append(args, "-v")
	}
	args = append(args, instrumentedPathPrefix+"/"+packageName)
	cmd := exec.Command("go", args...)
	cmd.Env = env
	cmd.Stdout = os.Stderr
	cmd.Stderr = os.Stderr
	err = cmd.Run()

	if err != nil {
		fmt.Fprintf(os.Stderr, "go test failed: %s\n", err)
		rc = 1
	}

	packages, err := gocov.ParseTrace(outfilePath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to parse gocov output: %s\n", err)
	} else {
		data, err := marshalJson(packages)
		if err != nil {
			fmt.Fprintf(os.Stderr, "failed to format as JSON: %s\n", err)
		} else {
			fmt.Println(string(data))
		}
	}
	return
}

func main() {
	flag.Usage = usage
	flag.Parse()
	command := ""
	if flag.NArg() > 0 {
		command = flag.Arg(0)
		switch command {
		case "annotate":
			os.Exit(annotateSource())
		case "report":
			os.Exit(reportCoverage())
		case "test":
			os.Exit(instrumentAndTest())
		//case "run"
		default:
			fmt.Fprintf(os.Stderr, "Unknown command: %#q\n\n", command)
			usage()
		}
	} else {
		usage()
	}
}
<|endoftext|>


<commit_before>package gosideways

import (
	"bufio"
	"errors"
	"fmt"
	"log"
	"net"
	"strconv"
	"strings"
	"time"
)

type Node struct {
	Addr     string
	Port     int
	Data     map[string]Data
	Siblings map[string]*Node

	save chan Data
	repl chan Data
}

type Data struct {
	Key     string
	Text    string
	Date    time.Time
	Expires time.Time
}

func (n *Node) AddSibling(addr string, port int) error {
	key := addr + ":" + fmt.Sprint(port)
	if _, exists := n.Siblings[key]; exists {
		return errors.New("Sibling " + key + " already registered")
	}

	n.Siblings[key] = newNode(addr, port)

	return nil
}

func Listen(port int) *Node {
	node := newNode("127.0.0.1", port)
	go node.clean()
	go node.Run()
	return node
}

func (n *Node) Run() {
	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", n.Port))
	if err != nil {
		log.Println(err.Error())
		return
	}
	defer listener.Close()

	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Println(err.Error())
			continue
		}

		go n.handleConnection(conn)
	}
}

func (n *Node) Get(key string) *Data {
	return n.get(key)
}

func (n *Node) Set(key string, data string, valid time.Duration) {
	d := n.newData(key, data, valid)

	n.save <- d
	n.repl <- d
}

func (n *Node) newData(key string, data string, valid time.Duration) Data {
	return Data{
		Key:     key,
		Text:    data,
		Date:    time.Now(),
		Expires: time.Now().Add(valid),
	}
}

func (n *Node) replicate(d Data) {
	for _, s := range n.Siblings {
		if s.Addr == n.Addr && s.Port == n.Port {
			continue
		}

		addr := fmt.Sprintf("%s:%d", s.Addr, s.Port)
		conn, err := net.Dial("tcp", addr)
		if err != nil {
			log.Println(err.Error())
			continue
		}

		exp := int(d.Expires.Sub(time.Now()).Seconds() + .5)

		fmt.Fprintf(conn, "REPLICATE %s %d %s", d.Key, exp, d.Text)
		conn.Close()
	}
}

func (n *Node) get(key string) *Data {
	var data *Data

	if aux, ok := n.Data[key]; ok {
		if aux.Expires.Before(time.Now()) {
			n.del(key)
		} else {
			data = &aux
		}
	}

	return data
}

func (n *Node) del(key string) {
	if _, ok := n.Data[key]; ok {
		delete(n.Data, key)
	}
}

func (n *Node) clean() {
	for {
		now := time.Now()
		for key, data := range n.Data {
			if data.Expires.Before(now) {
				n.del(key)
			}
		}

		time.Sleep(time.Second)
	}
}

func newNode(addr string, port int) *Node {
	node := &Node{
		Addr:     addr,
		Port:     port,
		Data:     make(map[string]Data),
		Siblings: make(map[string]*Node),

		save: make(chan Data, 1024),
		repl: make(chan Data, 1024),
	}

	go func() {
		for d := range node.save {
			node.Data[d.Key] = d
		}
	}()

	go func() {
		for d := range node.repl {
			node.replicate(d)
		}
	}()

	return node
}

func (n *Node) handleConnection(c net.Conn) {
	defer c.Close()

	scanner := bufio.NewScanner(c)
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if line == "" {
			continue
		}

		command := strings.SplitN(line, " ", 3)
		if len(command) < 2 {
			continue
		}

		command[0] = strings.ToUpper(command[0])
		for i := 1; i < len(command); i++ {
			command[i] = strings.TrimSpace(command[i])
		}

		switch command[0] {
		case "GET":
			data := n.get(command[1])
			if data != nil {
				fmt.Fprintln(c, data.Text)
			}
			break
		case "SET", "REPLICATE":
			if len(command) < 3 {
				continue
			}

			aux := strings.SplitN(command[2], " ", 2)
			if len(aux) < 2 {
				continue
			}

			seconds, _ := strconv.Atoi(aux[0])
			if seconds <= 0 {
				continue
			}

			d := n.newData(command[1], aux[1], time.Duration(seconds)*time.Second)

			n.save <- d

			if command[0] == "SET" {
				n.repl <- d
			}
			break
		case "DELETE":
			n.del(command[1])
			break
		}
	}
}
<commit_msg>Providing length on SET and REPLICATE commands for multiline data<commit_after>package gosideways

import (
	"bufio"
	"errors"
	"fmt"
	"log"
	"net"
	"strconv"
	"strings"
	"time"
)

type Node struct {
	Addr     string
	Port     int
	Data     map[string]Data
	Siblings map[string]*Node

	save chan Data
	repl chan Data
}

type Data struct {
	Key     string
	Text    string
	Date    time.Time
	Expires time.Time
}

func (n *Node) AddSibling(addr string, port int) error {
	key := addr + ":" + fmt.Sprint(port)
	if _, exists := n.Siblings[key]; exists {
		return errors.New("Sibling " + key + " already registered")
	}

	n.Siblings[key] = newNode(addr, port)

	return nil
}

func Listen(port int) *Node {
	node := newNode("127.0.0.1", port)
	go node.clean()
	go node.Run()
	return node
}

func (n *Node) Run() {
	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", n.Port))
	if err != nil {
		log.Println(err.Error())
		return
	}
	defer listener.Close()

	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Println(err.Error())
			continue
		}

		go n.handleConnection(conn)
	}
}

func (n *Node) Get(key string) *Data {
	return n.get(key)
}

func (n *Node) Set(key string, data string, valid time.Duration) {
	d := n.newData(key, data, valid)

	n.save <- d
	n.repl <- d
}

func (n *Node) newData(key string, data string, valid time.Duration) Data {
	return Data{
		Key:     key,
		Text:    data,
		Date:    time.Now(),
		Expires: time.Now().Add(valid),
	}
}

func (n *Node) replicate(d Data) {
	for _, s := range n.Siblings {
		if s.Addr == n.Addr && s.Port == n.Port {
			continue
		}

		addr := fmt.Sprintf("%s:%d", s.Addr, s.Port)
		conn, err := net.Dial("tcp", addr)
		if err != nil {
			log.Println(err.Error())
			continue
		}

		exp := int(d.Expires.Sub(time.Now()).Seconds() + .5)

		fmt.Fprintf(conn, "REPLICATE %s %d %d %s", d.Key, exp, len(d.Text), d.Text)
		conn.Close()
	}
}

func (n *Node) get(key string) *Data {
	var data *Data

	if aux, ok := n.Data[key]; ok {
		if aux.Expires.Before(time.Now()) {
			n.del(key)
		} else {
			data = &aux
		}
	}

	return data
}

func (n *Node) del(key string) {
	if _, ok := n.Data[key]; ok {
		delete(n.Data, key)
	}
}

func (n *Node) clean() {
	for {
		now := time.Now()
		for key, data := range n.Data {
			if data.Expires.Before(now) {
				n.del(key)
			}
		}

		time.Sleep(time.Second)
	}
}

func newNode(addr string, port int) *Node {
	node := &Node{
		Addr:     addr,
		Port:     port,
		Data:     make(map[string]Data),
		Siblings: make(map[string]*Node),

		save: make(chan Data, 1024),
		repl: make(chan Data, 1024),
	}

	go func() {
		for d := range node.save {
			node.Data[d.Key] = d
		}
	}()

	go func() {
		for d := range node.repl {
			node.replicate(d)
		}
	}()

	return node
}

func (n *Node) handleConnection(c net.Conn) {
	defer c.Close()

	scanner := bufio.NewScanner(c)
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if line == "" {
			continue
		}

		command := strings.SplitN(line, " ", 3)
		if len(command) < 2 {
			continue
		}

		command[0] = strings.ToUpper(command[0])
		for i := 1; i < len(command); i++ {
			command[i] = strings.TrimSpace(command[i])
		}

		switch command[0] {
		case "GET":
			data := n.get(command[1])
			if data != nil {
				fmt.Fprintln(c, data.Text)
			}
			break
		case "SET", "REPLICATE":
			if len(command) < 3 {
				continue
			}

			aux := strings.SplitN(command[2], " ", 3)
			if len(aux) < 3 {
				continue
			}

			seconds, _ := strconv.Atoi(aux[0])
			if seconds <= 0 {
				continue
			}

			length, _ := strconv.Atoi(aux[1])
			if length <= 0 {
				continue
			}

			d := n.newData(command[1], aux[2], time.Duration(seconds)*time.Second)

			for len(d.Text) < length {
				scanner.Scan()
				d.Text += "\n" + scanner.Text()
			}

			n.save <- d

			if command[0] == "SET" {
				n.repl <- d
			}
			break
		case "DELETE":
			n.del(command[1])
			break
		}
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 AlexRuzin (stan.ruzin@gmail.com)
 *
 * 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 govfs

import (
    "testing"
    "time"
    "os"
    "io"
    _"bytes"
    "bytes"
    "runtime"
)

const FS_DATABASE_FILE string = "test_db"

func TestFSWriter(t *testing.T) {
    /*
     * This test will generate the raw fs stream file, along with some contents
     *  that will be later loaded by the TestFSReader() method
     */
    out("[+] Running Standard I/O Sanity Test...")

    /* Remove the test database if it exists */
    var filename = gen_raw_filename(FS_DATABASE_FILE)
    if _, err := os.Stat(filename); os.IsExist(err) {
        os.Remove(filename)
    }

    var header = CreateDatabase(filename, 0)
    if header == nil {
        drive_fail("TEST1: Failed to obtain header", t)
    }
    out("[+] Test 1 PASS")

    // The root file "/" must at least exist
    if file, err := header.Create("/"); file != nil && err == nil {
        drive_fail("TEST2: Failed to return root handle", t)
    }
    out("[+] Test 2 PASS")

    /*
     * Try to delete the root file "/"
     */
    if header.Delete("/") == nil {
        drive_fail("TEST3: Cannot delete root -- critical", t)
    }
    out("[+] Test 3 PASS")

    /*
     * Attempt to write to a nonexistant file
     */
    var data = []byte{ 1, 2 }
    if header.Write("/folder5/folder5/file5", data) == nil {
        drive_fail("TEST4: Cannot write to a nonexistant file", t)
    }
    out("[+] Test 4 PASS")

    /*
     * Create empty file file9
     */
    if file, err := header.Create("/folder5/folder4/folder2/file9"); file == nil || err != nil {
        drive_fail("TEST4.1: file9 cannot be created", t)
    }
    out("[+] Test 4.1 PASS")

    /*
     * Attempt to create a new file0
     */
    if file, err := header.Create("/folder0/folder0/file0"); file == nil || err != nil {
        drive_fail("TEST5.0: file0 cannot be created", t)
    }
    out("[+] Test 5.0 PASS")

    /*
     * Attempt to create a new file0, this will fail since it should already exist
     */
    if file, err := header.Create("/folder0/folder0/file0"); file != nil && err == nil {
        drive_fail("TEST5.1: file0 cannot be created twice", t)
    }
    out("[+] Test 5.1 PASS")

    /*
     * Write some data into file0
     */
    data = []byte{ 1, 2, 3, 4 }
    if header.Write("/folder0/folder0/file0", data) != nil {
        drive_fail("TEST6: Failed to write data in file0", t)
    }
    out("[+] Test 6 PASS")

    /*
     * Check that the size of file0 is 4
     */
    if k, _ := header.get_file_size("/folder0/folder0/file0"); k != uint(len(data)) {
        drive_fail("TEST6.1: The size of data does not match", t)
    }
    out("[+] Test 6.1 PASS")

    /*
     * Attempt to create a new file3
     */
    if file, err := header.Create("/folder1/folder0/file3"); file == nil || err != nil {
        drive_fail("TEST7: file3 cannot be created", t)
    }
    out("[+] Test 7 PASS")

    /*
     * Write some data into file3
     */
    var data2 = []byte{ 1, 2, 3, 4, 5, 6, 7 }
    if header.Write("/folder1/folder0/file3", data2) != nil {
        drive_fail("TEST8: Failed to write data in file3", t)
    }
    out("[+] Test 8 PASS")

    /*
     * Write some data into file3
     */
    if header.Write("/folder1/folder0/file3", data2) != nil {
        drive_fail("TEST8.1: Failed to write data in file3", t)
    }
    out("[+] Test 8.1 PASS")

    /*
     * Read the written data from file0 and compare
     */
    output_data, _ := header.Read("/folder0/folder0/file0")
    if output_data == nil || len(output_data) != len(data) || header.t_size - 7 /* len(file3) */ != uint(len(data)) {
        drive_fail("TEST9: Failed to read data from file0", t)
    }
    out("[+] Test 9 PASS")

    /*
     * Read the written data from file3 and compare
     */
    output_data, _ = header.Read("/folder1/folder0/file3")
    if output_data == nil || len(output_data) != len(data2) || header.t_size - 4 /* len(file0) */ != uint(len(data2)) {
        drive_fail("TEST10: Failed to read data from file3", t)
    }
    out("[+] Test 10 PASS")

    /*
     * Write other data to file0
     */
    data = []byte{ 1, 2, 3 }
    if header.Write("/folder0/folder0/file0", data) != nil {
        drive_fail("TEST11: Failed to write data in file1", t)
    }
    out("[+] Test 11 PASS")

    /*
     * Read the new data from file0
     */
    output_data, _ = header.Read("/folder0/folder0/file0")
    if output_data == nil || len(output_data) != len(data) {
        drive_fail("TEST12: Failed to read data from file1", t)
    }
    out("[+] Test 12 PASS")

    /*
     * Attempt to create a new file5. This will be a blank file
     */
    if file, err := header.Create("/folder2/file7"); file == nil || err != nil {
        drive_fail("TEST13: file3 cannot be created", t)
    }
    out("[+] Test 13 PASS")

    /*
     * Delete file0 -- complete this
     */
    // FIXME/ADDME

    /*
     * Create just a folder
     */
    if file, err := header.Create("/folder2/file5/"); file == nil || err != nil {
        drive_fail("TEST15: folder file5 cannot be created", t)
    }
    out("[+] Test 15 PASS")

    /*
     * Tests the Reader interface
     */
    reader, err := header.NewReader("/folder0/folder0/file0")
    if err != nil {
        drive_fail("TEST15.1: Failed to create Reader", t)
    }

    file0data := make([]byte, 3)
    data_read, err := reader.Read(file0data)
    if data_read != len(data) || err != io.EOF || bytes.Compare(file0data, data) != 0 {
        drive_fail("TEST15.2: Failed to read from NewReader", t)
    }

    /* Test the reader interface again */
    file0data = make([]byte, 1)
    data_read, err = reader.Read(file0data)
    if data_read != 1 || err != nil || file0data[0] != 1 {
        drive_fail("TEST15.3: Invalid Reader interface behaviour", t)
    }
    out("[+] Test 15.1, 15.2, 15.3 PASS -- Reader interface")

    /*
     * Tests the Writer interface
     */
    file0data = []byte{1, 2, 3, 4, 5, 6, 7, 8}
    writer, err := header.NewWriter("/folder0/folder0/file0")
    if writer == nil || err != nil {
        drive_fail("TEST15.4: Invalid Writer object", t)
    }

    written, err := writer.Write(file0data)
    if written != len(file0data) || err != io.EOF {
        drive_fail("TEST15.4: Invalid Writer response", t)
    }

    file0data = make([]byte, 8)
    data_read, err = reader.Read(file0data)
    if data_read != 8 || err != io.EOF || file0data[0] != 1 || file0data[1] != 2 {
        drive_fail("TEST15.5: Invalid Reader data",t )
    }
    out("[+] Test 15.4, 15.5 PASS -- Writer interface")

    /*
     * Print out files
     */
    file_list := header.get_file_list()
    for _, e := range file_list {
        out(e)
    }

    /*
     * Unmount/commit database to file
     */
    if err := header.unmount_db(); err != nil {
        drive_fail("TEST16: Failed to commit database", t)
    }
    out("[+] Test 16 PASS. Raw FS stream written to: " + header.filename)

    time.Sleep(10000)
}

func TestFSReader(t *testing.T) {
    /*
     * Read in FS_DATABASE_FILE and do basic tests
     */
    var filename = gen_raw_filename(FS_DATABASE_FILE)
    out("[+] Loading Raw FS stream file: " + filename)

    /* Remove the test database if it exists */
    if _, err := os.Stat(filename); os.IsNotExist(err) {
        drive_fail("error: Standard raw fs stream " + filename + " does not exist", t)
    }

    var header = CreateDatabase(filename, 0)
    if header == nil {
        drive_fail("TEST1: Failed to obtain header", t)
    }
    out("[+] Test 1 PASS (Loaded FS stream)")
}

func gen_raw_filename(suffix string) string {
    if runtime.GOOS == "windows" {
        return os.Getenv("TEMP") + "\\" + suffix + ".db"
    }

    if runtime.GOOS == "linux" {
        return suffix + ".db"
    }

    return suffix + ".db"
}

func drive_fail(output string, t *testing.T) {
    t.Errorf(output)
    t.FailNow()
}
<commit_msg>Implemented the StartIOController() method<commit_after>/*
 * Copyright (c) 2017 AlexRuzin (stan.ruzin@gmail.com)
 *
 * 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 govfs

import (
    "testing"
    "time"
    "os"
    "io"
    _"bytes"
    "bytes"
    "runtime"
)

const FS_DATABASE_FILE string = "test_db"

func TestFSWriter(t *testing.T) {
    /*
     * This test will generate the raw fs stream file, along with some contents
     *  that will be later loaded by the TestFSReader() method
     */
    out("[+] Running Standard I/O Sanity Test...")

    /* Remove the test database if it exists */
    var filename = gen_raw_filename(FS_DATABASE_FILE)
    if _, err := os.Stat(filename); os.IsExist(err) {
        os.Remove(filename)
    }

    var header = CreateDatabase(filename, 0)
    if header == nil {
        drive_fail("TEST1: Failed to obtain header", t)
    }
    if err := header.StartIOController(); err != nil {
        drive_fail("TEST1.1: Failed to start IOController", t)
    }
    out("[+] Test 1 PASS")

    // The root file "/" must at least exist
    if file, err := header.Create("/"); file != nil && err == nil {
        drive_fail("TEST2: Failed to return root handle", t)
    }
    out("[+] Test 2 PASS")

    /*
     * Try to delete the root file "/"
     */
    if header.Delete("/") == nil {
        drive_fail("TEST3: Cannot delete root -- critical", t)
    }
    out("[+] Test 3 PASS")

    /*
     * Attempt to write to a nonexistant file
     */
    var data = []byte{ 1, 2 }
    if header.Write("/folder5/folder5/file5", data) == nil {
        drive_fail("TEST4: Cannot write to a nonexistant file", t)
    }
    out("[+] Test 4 PASS")

    /*
     * Create empty file file9
     */
    if file, err := header.Create("/folder5/folder4/folder2/file9"); file == nil || err != nil {
        drive_fail("TEST4.1: file9 cannot be created", t)
    }
    out("[+] Test 4.1 PASS")

    /*
     * Attempt to create a new file0
     */
    if file, err := header.Create("/folder0/folder0/file0"); file == nil || err != nil {
        drive_fail("TEST5.0: file0 cannot be created", t)
    }
    out("[+] Test 5.0 PASS")

    /*
     * Attempt to create a new file0, this will fail since it should already exist
     */
    if file, err := header.Create("/folder0/folder0/file0"); file != nil && err == nil {
        drive_fail("TEST5.1: file0 cannot be created twice", t)
    }
    out("[+] Test 5.1 PASS")

    /*
     * Write some data into file0
     */
    data = []byte{ 1, 2, 3, 4 }
    if header.Write("/folder0/folder0/file0", data) != nil {
        drive_fail("TEST6: Failed to write data in file0", t)
    }
    out("[+] Test 6 PASS")

    /*
     * Check that the size of file0 is 4
     */
    if k, _ := header.get_file_size("/folder0/folder0/file0"); k != uint(len(data)) {
        drive_fail("TEST6.1: The size of data does not match", t)
    }
    out("[+] Test 6.1 PASS")

    /*
     * Attempt to create a new file3
     */
    if file, err := header.Create("/folder1/folder0/file3"); file == nil || err != nil {
        drive_fail("TEST7: file3 cannot be created", t)
    }
    out("[+] Test 7 PASS")

    /*
     * Write some data into file3
     */
    var data2 = []byte{ 1, 2, 3, 4, 5, 6, 7 }
    if header.Write("/folder1/folder0/file3", data2) != nil {
        drive_fail("TEST8: Failed to write data in file3", t)
    }
    out("[+] Test 8 PASS")

    /*
     * Write some data into file3
     */
    if header.Write("/folder1/folder0/file3", data2) != nil {
        drive_fail("TEST8.1: Failed to write data in file3", t)
    }
    out("[+] Test 8.1 PASS")

    /*
     * Read the written data from file0 and compare
     */
    output_data, _ := header.Read("/folder0/folder0/file0")
    if output_data == nil || len(output_data) != len(data) || header.t_size - 7 /* len(file3) */ != uint(len(data)) {
        drive_fail("TEST9: Failed to read data from file0", t)
    }
    out("[+] Test 9 PASS")

    /*
     * Read the written data from file3 and compare
     */
    output_data, _ = header.Read("/folder1/folder0/file3")
    if output_data == nil || len(output_data) != len(data2) || header.t_size - 4 /* len(file0) */ != uint(len(data2)) {
        drive_fail("TEST10: Failed to read data from file3", t)
    }
    out("[+] Test 10 PASS")

    /*
     * Write other data to file0
     */
    data = []byte{ 1, 2, 3 }
    if header.Write("/folder0/folder0/file0", data) != nil {
        drive_fail("TEST11: Failed to write data in file1", t)
    }
    out("[+] Test 11 PASS")

    /*
     * Read the new data from file0
     */
    output_data, _ = header.Read("/folder0/folder0/file0")
    if output_data == nil || len(output_data) != len(data) {
        drive_fail("TEST12: Failed to read data from file1", t)
    }
    out("[+] Test 12 PASS")

    /*
     * Attempt to create a new file5. This will be a blank file
     */
    if file, err := header.Create("/folder2/file7"); file == nil || err != nil {
        drive_fail("TEST13: file3 cannot be created", t)
    }
    out("[+] Test 13 PASS")

    /*
     * Delete file0 -- complete this
     */
    // FIXME/ADDME

    /*
     * Create just a folder
     */
    if file, err := header.Create("/folder2/file5/"); file == nil || err != nil {
        drive_fail("TEST15: folder file5 cannot be created", t)
    }
    out("[+] Test 15 PASS")

    /*
     * Tests the Reader interface
     */
    reader, err := header.NewReader("/folder0/folder0/file0")
    if err != nil {
        drive_fail("TEST15.1: Failed to create Reader", t)
    }

    file0data := make([]byte, 3)
    data_read, err := reader.Read(file0data)
    if data_read != len(data) || err != io.EOF || bytes.Compare(file0data, data) != 0 {
        drive_fail("TEST15.2: Failed to read from NewReader", t)
    }

    /* Test the reader interface again */
    file0data = make([]byte, 1)
    data_read, err = reader.Read(file0data)
    if data_read != 1 || err != nil || file0data[0] != 1 {
        drive_fail("TEST15.3: Invalid Reader interface behaviour", t)
    }
    out("[+] Test 15.1, 15.2, 15.3 PASS -- Reader interface")

    /*
     * Tests the Writer interface
     */
    file0data = []byte{1, 2, 3, 4, 5, 6, 7, 8}
    writer, err := header.NewWriter("/folder0/folder0/file0")
    if writer == nil || err != nil {
        drive_fail("TEST15.4: Invalid Writer object", t)
    }

    written, err := writer.Write(file0data)
    if written != len(file0data) || err != io.EOF {
        drive_fail("TEST15.4: Invalid Writer response", t)
    }

    file0data = make([]byte, 8)
    data_read, err = reader.Read(file0data)
    if data_read != 8 || err != io.EOF || file0data[0] != 1 || file0data[1] != 2 {
        drive_fail("TEST15.5: Invalid Reader data",t )
    }
    out("[+] Test 15.4, 15.5 PASS -- Writer interface")

    /*
     * Print out files
     */
    file_list := header.get_file_list()
    for _, e := range file_list {
        out(e)
    }

    /*
     * Unmount/commit database to file
     */
    if err := header.unmount_db(); err != nil {
        drive_fail("TEST16: Failed to commit database", t)
    }
    out("[+] Test 16 PASS. Raw FS stream written to: " + header.filename)

    time.Sleep(10000)
}

func TestFSReader(t *testing.T) {
    /*
     * Read in FS_DATABASE_FILE and do basic tests
     */
    var filename = gen_raw_filename(FS_DATABASE_FILE)
    out("[+] Loading Raw FS stream file: " + filename)

    /* Remove the test database if it exists */
    if _, err := os.Stat(filename); os.IsNotExist(err) {
        drive_fail("error: Standard raw fs stream " + filename + " does not exist", t)
    }

    var header = CreateDatabase(filename, 0)
    if header == nil {
        drive_fail("TEST1: Failed to obtain header", t)
    }

    if err := header.StartIOController(); err != nil {
        drive_fail("TEST1.1: Failed to start IOController", t)
    }
    out("[+] Test 1 PASS (Loaded FS stream)")
}

func gen_raw_filename(suffix string) string {
    if runtime.GOOS == "windows" {
        return os.Getenv("TEMP") + "\\" + suffix + ".db"
    }

    if runtime.GOOS == "linux" {
        return suffix + ".db"
    }

    return suffix + ".db"
}

func drive_fail(output string, t *testing.T) {
    t.Errorf(output)
    t.FailNow()
}
<|endoftext|>


<commit_before>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package constants

import (
	"testing"
)

func TestGetHRP(t *testing.T) {
	tests := []struct {
		id  uint32
		hrp string
	}{
		{
			id:  MainnetID,
			hrp: MainnetHRP,
		},
		{
			id:  TestnetID,
			hrp: FujiHRP,
		},
		{
			id:  FujiID,
			hrp: FujiHRP,
		},
		{
			id:  LocalID,
			hrp: LocalHRP,
		},
		{
			id:  4294967295,
			hrp: FallbackHRP,
		},
	}
	for _, test := range tests {
		t.Run(test.hrp, func(t *testing.T) {
			if hrp := GetHRP(test.id); hrp != test.hrp {
				t.Fatalf("GetHRP(%d) returned %q but expected %q",
					test.id, hrp, test.hrp)
			}
		})
	}
}

func TestNetworkName(t *testing.T) {
	tests := []struct {
		id   uint32
		name string
	}{
		{
			id:   MainnetID,
			name: MainnetName,
		},
		{
			id:   TestnetID,
			name: FujiName,
		},
		{
			id:   FujiID,
			name: FujiName,
		},
		{
			id:   LocalID,
			name: LocalName,
		},
		{
			id:   4294967295,
			name: "network-4294967295",
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			if name := NetworkName(test.id); name != test.name {
				t.Fatalf("NetworkName(%d) returned %q but expected %q",
					test.id, name, test.name)
			}
		})
	}
}

func TestNetworkID(t *testing.T) {
	tests := []struct {
		name      string
		id        uint32
		shouldErr bool
	}{
		{
			name: MainnetName,
			id:   MainnetID,
		},
		{
			name: "MaInNeT",
			id:   MainnetID,
		},
		{
			name: TestnetName,
			id:   TestnetID,
		},
		{
			name: FujiName,
			id:   FujiID,
		},
		{
			name: LocalName,
			id:   LocalID,
		},
		{
			name: "network-4294967295",
			id:   4294967295,
		},
		{
			name: "4294967295",
			id:   4294967295,
		},
		{
			name:      "networ-4294967295",
			shouldErr: true,
		},
		{
			name:      "network-4294967295123123",
			shouldErr: true,
		},
		{
			name:      "4294967295123123",
			shouldErr: true,
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			id, err := NetworkID(test.name)
			if err == nil && test.shouldErr {
				t.Fatalf("NetworkID(%q) returned %d but should have errored", test.name, test.id)
			}
			if err != nil && !test.shouldErr {
				t.Fatalf("NetworkID(%q) unexpectedly errored with: %s", test.name, err)
			}
			if id != test.id {
				t.Fatalf("NetworkID(%q) returned %d but expected %d", test.name, id, test.id)
			}
		})
	}
}
<commit_msg>fixed manhattan test<commit_after>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package constants

import (
	"testing"
)

func TestGetHRP(t *testing.T) {
	tests := []struct {
		id  uint32
		hrp string
	}{
		{
			id:  MainnetID,
			hrp: MainnetHRP,
		},
		{
			id:  TestnetID,
			hrp: FallbackHRP,
		},
		{
			id:  FujiID,
			hrp: FujiHRP,
		},
		{
			id:  LocalID,
			hrp: LocalHRP,
		},
		{
			id:  4294967295,
			hrp: FallbackHRP,
		},
	}
	for _, test := range tests {
		t.Run(test.hrp, func(t *testing.T) {
			if hrp := GetHRP(test.id); hrp != test.hrp {
				t.Fatalf("GetHRP(%d) returned %q but expected %q",
					test.id, hrp, test.hrp)
			}
		})
	}
}

func TestNetworkName(t *testing.T) {
	tests := []struct {
		id   uint32
		name string
	}{
		{
			id:   MainnetID,
			name: MainnetName,
		},
		{
			id:   TestnetID,
			name: ManhattanName,
		},
		{
			id:   FujiID,
			name: FujiName,
		},
		{
			id:   LocalID,
			name: LocalName,
		},
		{
			id:   4294967295,
			name: "network-4294967295",
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			if name := NetworkName(test.id); name != test.name {
				t.Fatalf("NetworkName(%d) returned %q but expected %q",
					test.id, name, test.name)
			}
		})
	}
}

func TestNetworkID(t *testing.T) {
	tests := []struct {
		name      string
		id        uint32
		shouldErr bool
	}{
		{
			name: MainnetName,
			id:   MainnetID,
		},
		{
			name: "MaInNeT",
			id:   MainnetID,
		},
		{
			name: TestnetName,
			id:   TestnetID,
		},
		{
			name: FujiName,
			id:   FujiID,
		},
		{
			name: LocalName,
			id:   LocalID,
		},
		{
			name: "network-4294967295",
			id:   4294967295,
		},
		{
			name: "4294967295",
			id:   4294967295,
		},
		{
			name:      "networ-4294967295",
			shouldErr: true,
		},
		{
			name:      "network-4294967295123123",
			shouldErr: true,
		},
		{
			name:      "4294967295123123",
			shouldErr: true,
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			id, err := NetworkID(test.name)
			if err == nil && test.shouldErr {
				t.Fatalf("NetworkID(%q) returned %d but should have errored", test.name, test.id)
			}
			if err != nil && !test.shouldErr {
				t.Fatalf("NetworkID(%q) unexpectedly errored with: %s", test.name, err)
			}
			if id != test.id {
				t.Fatalf("NetworkID(%q) returned %d but expected %d", test.name, id, test.id)
			}
		})
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2017, Janoš Guljaš <janos@resenje.org>
// All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package httpServer

import (
	"crypto/tls"
	"net"
	"net/http"
	"time"

	"resenje.org/web/servers"
)

var (
	_ servers.Server    = new(Server)
	_ servers.TCPServer = new(Server)
)

// Options struct holds parameters that can be configure using
// functions with prefix With.
type Options struct {
	tlsConfig *tls.Config
}

// Option is a function that sets optional parameters for
// the Server.
type Option func(*Options)

// WithTLSConfig sets a TLS configuration for the HTTP server
// and creates a TLS listener.
func WithTLSConfig(tlsConfig *tls.Config) Option { return func(o *Options) { o.tlsConfig = tlsConfig } }

// Server wraps http.Server to provide methods for
// resenje.org/web/servers.Server interface.
type Server struct {
	http.Server
}

// New creates a new instance of Server.
func New(handler http.Handler, opts ...Option) (s *Server) {
	o := &Options{}
	for _, opt := range opts {
		opt(o)
	}
	s = &Server{
		Server: http.Server{
			Handler:   handler,
			TLSConfig: o.tlsConfig,
		},
	}
	return
}

// ServeTCP executes http.Server.Serve method.
// If the provided listener is net.TCPListener, keep alive
// will be enabled. If server is configured with TLS,
// a tls.Listener will be created with provided listener.
func (s *Server) ServeTCP(ln net.Listener) (err error) {
	if l, ok := ln.(*net.TCPListener); ok {
		ln = tcpKeepAliveListener{TCPListener: l}
	}
	if s.TLSConfig != nil {
		ln = tls.NewListener(ln, s.TLSConfig)
	}

	err = s.Server.Serve(ln)
	if err == http.ErrServerClosed {
		return nil
	}
	return
}

// TCPKeepAliveListener sets TCP keep alive period.
type tcpKeepAliveListener struct {
	*net.TCPListener
}

// Accept accepts TCP connection and sets TCP keep alive period
func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
	tc, err := ln.AcceptTCP()
	if err != nil {
		return
	}
	tc.SetKeepAlive(true)
	tc.SetKeepAlivePeriod(3 * time.Minute)
	return tc, nil
}
<commit_msg>Check for errors from SetKeepAlive and SetKeepAlivePeriod in HTTP server Accept<commit_after>// Copyright (c) 2017, Janoš Guljaš <janos@resenje.org>
// All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package httpServer

import (
	"crypto/tls"
	"net"
	"net/http"
	"time"

	"resenje.org/web/servers"
)

var (
	_ servers.Server    = new(Server)
	_ servers.TCPServer = new(Server)
)

// Options struct holds parameters that can be configure using
// functions with prefix With.
type Options struct {
	tlsConfig *tls.Config
}

// Option is a function that sets optional parameters for
// the Server.
type Option func(*Options)

// WithTLSConfig sets a TLS configuration for the HTTP server
// and creates a TLS listener.
func WithTLSConfig(tlsConfig *tls.Config) Option { return func(o *Options) { o.tlsConfig = tlsConfig } }

// Server wraps http.Server to provide methods for
// resenje.org/web/servers.Server interface.
type Server struct {
	http.Server
}

// New creates a new instance of Server.
func New(handler http.Handler, opts ...Option) (s *Server) {
	o := &Options{}
	for _, opt := range opts {
		opt(o)
	}
	s = &Server{
		Server: http.Server{
			Handler:   handler,
			TLSConfig: o.tlsConfig,
		},
	}
	return
}

// ServeTCP executes http.Server.Serve method.
// If the provided listener is net.TCPListener, keep alive
// will be enabled. If server is configured with TLS,
// a tls.Listener will be created with provided listener.
func (s *Server) ServeTCP(ln net.Listener) (err error) {
	if l, ok := ln.(*net.TCPListener); ok {
		ln = tcpKeepAliveListener{TCPListener: l}
	}
	if s.TLSConfig != nil {
		ln = tls.NewListener(ln, s.TLSConfig)
	}

	err = s.Server.Serve(ln)
	if err == http.ErrServerClosed {
		return nil
	}
	return
}

// TCPKeepAliveListener sets TCP keep alive period.
type tcpKeepAliveListener struct {
	*net.TCPListener
}

// Accept accepts TCP connection and sets TCP keep alive period
func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
	tc, err := ln.AcceptTCP()
	if err != nil {
		return
	}
	if err := tc.SetKeepAlive(true); err != nil {
		return nil, err
	}
	if err := tc.SetKeepAlivePeriod(3 * time.Minute); err != nil {
		return nil, err
	}
	return tc, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/md5"
	"encoding/hex"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"strings"
	"text/template"
	"time"

	"github.com/robfig/cron"
	"github.com/samuel/go-zookeeper/zk"
)

//go:generate go run ./scripts/package-templates.go

type defaultLogger struct{}

func (defaultLogger) Printf(format string, a ...interface{}) {
	log.Printf(format, a...)
}

var (
	templateFile     string
	nginxRoot        string
	zookeeperNodes   string
	serviceRoot      string
	t                *template.Template
	renderedTemplate bytes.Buffer
	sitesAvailable   string
	sitesEnabled     string
	hashes           = make(map[string]string)
	logger           defaultLogger
)

// check is a simple wrapper to avoid the verbosity of
// `if err != nil` checks.
func check(err error) {
	if err != nil {
		panic(err)
	}
}

// Config is a simple mapping of service name and upstream endpoints
// so that we can generate nginx service configuration
type Config struct {
	Service           string
	UpstreamEndpoints []string
}

// updateService will iterate through the services available in zookeeper
// and generate a new template for them.
func updateService(zookeeper *zk.Conn, serviceRoot string) {
	children, _, _, err := zookeeper.ChildrenW(serviceRoot)
	check(err)
	reload := false

	for _, child := range children {
		serviceInstance := strings.Join([]string{serviceRoot, child, "instances"}, "/")
		info, _, _, err := zookeeper.ChildrenW(serviceInstance)
		if err != nil {
			panic(err)
		}

		var upstreamEndpoints []string

		for _, instanceInfo := range info {
			i := strings.Join(strings.Split(instanceInfo, "_"), ":")
			upstreamEndpoints = append(upstreamEndpoints, i)
		}

		data := Config{
			Service:           child,
			UpstreamEndpoints: upstreamEndpoints,
		}

		t.Execute(&renderedTemplate, data)
		r := rewriteConfig(child)
		if r == true {
			writeOutput(child)
			// reload = true
		}

		renderedTemplate.Reset()
	}
	if reload == true {
		reloadNginx()
	}
}

// writeOutput will check if the service exists, remove and recreate it
func writeOutput(service string) {
	fname := fmt.Sprintf("%s/%s.service", sitesAvailable, service)
	err := os.Remove(fname)
	check(err)
	f, err := os.OpenFile(fname, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0444)
	check(err)
	_, err = f.WriteString(renderedTemplate.String())
	check(err)
	f.Close()
}

// rewriteConfig will check if the configuration file needs to be overwritten
// and if it's overwritten it needs to signal that nginx must be reloaded
func rewriteConfig(service string) bool {
	hasher := md5.New()
	hasher.Write([]byte(renderedTemplate.String()))
	renderedHash := hex.EncodeToString(hasher.Sum(nil))
	if val, ok := hashes[service]; ok {
		if val != renderedHash {
			hashes[service] = renderedHash
		} else {
			logger.Printf("%+v :: %+v unchanged. Not updating.", service, renderedHash)
			return false
		}
	} else {
		hashes[service] = renderedHash
	}
	logger.Printf("%+v :: %+v changed. Updating.", service, renderedHash)
	return true
}

// symlink is a wrapper on os.Symlink
func symlink(service string) {
	err := os.Symlink(fmt.Sprintf("%s/%s.service", sitesAvailable, service),
		fmt.Sprintf("%s/%s.service", sitesEnabled, service))
	check(err)
}

// reloadNginx is a wrapper to shell out to reload the configuration
func reloadNginx() {
	reloadCommand := exec.Command("service", "nginx reload")
	err := reloadCommand.Run()
	check(err)
}

func main() {
	flag.StringVar(&templateFile, "template", "", "nginx template to use")
	flag.StringVar(&nginxRoot, "nginx-root", "/etc/nginx/", "The root of the nginx installation")
	flag.StringVar(&zookeeperNodes, "zookeeper-nodes", "127.0.0.1:2181", "The zookeeper instance to connect to")
	flag.StringVar(&serviceRoot, "service-root", "/", "The root path with your service metadata")
	flag.Parse()

	sitesAvailable = fmt.Sprintf("%s/sites-available/", nginxRoot)
	sitesEnabled = fmt.Sprintf("%s/sites-enabled/", nginxRoot)

	var err error
	if len(templateFile) == 0 {
		t, err = template.New("service-template").Parse(defaultService)
		check(err)
	} else {
		t, err = template.New("service-template").ParseFiles(templateFile)
		check(err)
	}

	sigc := make(chan os.Signal, 1)
	signal.Notify(sigc, os.Interrupt, os.Kill)

	zookeeper, _, err := zk.Connect([]string{zookeeperNodes}, time.Second)
	check(err)

	c := cron.New()
	c.AddFunc("*/10 * * * *", func() {
		updateService(zookeeper, serviceRoot)
	})
	c.Start()

	defer c.Stop()
	<-sigc
}
<commit_msg>Added back reloading.<commit_after>package main

import (
	"bytes"
	"crypto/md5"
	"encoding/hex"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"strings"
	"text/template"
	"time"

	"github.com/robfig/cron"
	"github.com/samuel/go-zookeeper/zk"
)

//go:generate go run ./scripts/package-templates.go

type defaultLogger struct{}

func (defaultLogger) Printf(format string, a ...interface{}) {
	log.Printf(format, a...)
}

var (
	templateFile     string
	nginxRoot        string
	zookeeperNodes   string
	serviceRoot      string
	t                *template.Template
	renderedTemplate bytes.Buffer
	sitesAvailable   string
	sitesEnabled     string
	hashes           = make(map[string]string)
	logger           defaultLogger
)

// check is a simple wrapper to avoid the verbosity of
// `if err != nil` checks.
func check(err error) {
	if err != nil {
		panic(err)
	}
}

// Config is a simple mapping of service name and upstream endpoints
// so that we can generate nginx service configuration
type Config struct {
	Service           string
	UpstreamEndpoints []string
}

// updateService will iterate through the services available in zookeeper
// and generate a new template for them.
func updateService(zookeeper *zk.Conn, serviceRoot string) {
	children, _, _, err := zookeeper.ChildrenW(serviceRoot)
	check(err)
	reload := false

	for _, child := range children {
		serviceInstance := strings.Join([]string{serviceRoot, child, "instances"}, "/")
		info, _, _, err := zookeeper.ChildrenW(serviceInstance)
		if err != nil {
			panic(err)
		}

		var upstreamEndpoints []string

		for _, instanceInfo := range info {
			i := strings.Join(strings.Split(instanceInfo, "_"), ":")
			upstreamEndpoints = append(upstreamEndpoints, i)
		}

		data := Config{
			Service:           child,
			UpstreamEndpoints: upstreamEndpoints,
		}

		t.Execute(&renderedTemplate, data)
		r := rewriteConfig(child)
		if r == true {
			writeOutput(child)
			reload = true
		}

		renderedTemplate.Reset()
	}
	if reload == true {
		reloadNginx()
	}
}

// writeOutput will check if the service exists, remove and recreate it
func writeOutput(service string) {
	fname := fmt.Sprintf("%s/%s.service", sitesAvailable, service)
	err := os.Remove(fname)
	check(err)
	f, err := os.OpenFile(fname, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0444)
	check(err)
	_, err = f.WriteString(renderedTemplate.String())
	check(err)
	f.Close()
}

// rewriteConfig will check if the configuration file needs to be overwritten
// and if it's overwritten it needs to signal that nginx must be reloaded
func rewriteConfig(service string) bool {
	hasher := md5.New()
	hasher.Write([]byte(renderedTemplate.String()))
	renderedHash := hex.EncodeToString(hasher.Sum(nil))
	if val, ok := hashes[service]; ok {
		if val != renderedHash {
			hashes[service] = renderedHash
		} else {
			logger.Printf("%+v :: %+v unchanged. Not updating.", service, renderedHash)
			return false
		}
	} else {
		hashes[service] = renderedHash
	}
	logger.Printf("%+v :: %+v changed. Updating.", service, renderedHash)
	return true
}

// symlink is a wrapper on os.Symlink
func symlink(service string) {
	err := os.Symlink(fmt.Sprintf("%s/%s.service", sitesAvailable, service),
		fmt.Sprintf("%s/%s.service", sitesEnabled, service))
	check(err)
}

// reloadNginx is a wrapper to shell out to reload the configuration
func reloadNginx() {
	reloadCommand := exec.Command("service", "nginx reload")
	err := reloadCommand.Run()
	check(err)
}

func main() {
	flag.StringVar(&templateFile, "template", "", "nginx template to use")
	flag.StringVar(&nginxRoot, "nginx-root", "/etc/nginx/", "The root of the nginx installation")
	flag.StringVar(&zookeeperNodes, "zookeeper-nodes", "127.0.0.1:2181", "The zookeeper instance to connect to")
	flag.StringVar(&serviceRoot, "service-root", "/", "The root path with your service metadata")
	flag.Parse()

	sitesAvailable = fmt.Sprintf("%s/sites-available/", nginxRoot)
	sitesEnabled = fmt.Sprintf("%s/sites-enabled/", nginxRoot)

	var err error
	if len(templateFile) == 0 {
		t, err = template.New("service-template").Parse(defaultService)
		check(err)
	} else {
		t, err = template.New("service-template").ParseFiles(templateFile)
		check(err)
	}

	sigc := make(chan os.Signal, 1)
	signal.Notify(sigc, os.Interrupt, os.Kill)

	zookeeper, _, err := zk.Connect([]string{zookeeperNodes}, time.Second)
	check(err)

	c := cron.New()
	c.AddFunc("*/10 * * * *", func() {
		updateService(zookeeper, serviceRoot)
	})
	c.Start()

	defer c.Stop()
	<-sigc
}
<|endoftext|>


<commit_before>package buildah_test

import (
	"context"
	"io"
	"io/ioutil"
	"os"
	"testing"

	"github.com/werf/werf/pkg/util"

	"github.com/werf/werf/pkg/docker"

	"github.com/werf/werf/pkg/werf"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"github.com/werf/werf/pkg/buildah"
)

func TestBuildah(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Buildah suite")
}

var _ = BeforeSuite(func() {
	Expect(werf.Init("", "")).To(Succeed())
	Expect(docker.Init(context.Background(), "", false, false, "")).To(Succeed())
})

var _ = Describe("Buildah client", func() {
	Skip("not working inside go test yet")

	var b buildah.Buildah

	BeforeEach(func() {
		var err error
		b, err = buildah.NewBuildah(buildah.ModeDockerWithFuse, buildah.BuildahOpts{})
		Expect(err).To(Succeed())
	})

	It("Builds projects using Dockerfile", func() {
		for _, desc := range []struct {
			DockerfilePath string
			ContextPath    string
		}{
			{"./buildah_test/Dockerfile.ghost", ""},
			{"./buildah_test/Dockerfile.neovim", ""},
			{"./buildah_test/app1/Dockerfile", "./buildah_test/app1"},
			{"./buildah_test/app2/Dockerfile", "./buildah_test/app2"},
			{"./buildah_test/app3/Dockerfile", "./buildah_test/app3"},
		} {
			d, c := loadDockerfileAndContext(desc.DockerfilePath, desc.ContextPath)

			_, err := b.BuildFromDockerfile(context.Background(), d, buildah.BuildFromDockerfileOpts{
				CommonOpts: buildah.CommonOpts{LogWriter: os.Stdout},
				ContextTar: c,
			})

			Expect(err).To(Succeed())
		}
	})
})

func loadDockerfileAndContext(dockerfilePath string, contextPath string) ([]byte, io.Reader) {
	data, err := ioutil.ReadFile(dockerfilePath)
	Expect(err).To(Succeed())

	if contextPath == "" {
		return data, nil
	}

	reader := util.ReadDirAsTar(contextPath)

	return data, reader
}
<commit_msg>tests: fix test skipping<commit_after>package buildah_test

import (
	"context"
	"io"
	"io/ioutil"
	"os"
	"testing"

	"github.com/werf/werf/pkg/util"

	"github.com/werf/werf/pkg/docker"

	"github.com/werf/werf/pkg/werf"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"github.com/werf/werf/pkg/buildah"
)

func TestBuildah(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Buildah suite")
}

var _ = BeforeSuite(func() {
	Expect(werf.Init("", "")).To(Succeed())
	Expect(docker.Init(context.Background(), "", false, false, "")).To(Succeed())
})

var _ = Describe("Buildah client", func() {
	var b buildah.Buildah

	BeforeEach(func() {
		Skip("not working inside go test yet")

		var err error
		b, err = buildah.NewBuildah(buildah.ModeDockerWithFuse, buildah.BuildahOpts{})
		Expect(err).To(Succeed())
	})

	It("Builds projects using Dockerfile", func() {
		for _, desc := range []struct {
			DockerfilePath string
			ContextPath    string
		}{
			{"./buildah_test/Dockerfile.ghost", ""},
			{"./buildah_test/Dockerfile.neovim", ""},
			{"./buildah_test/app1/Dockerfile", "./buildah_test/app1"},
			{"./buildah_test/app2/Dockerfile", "./buildah_test/app2"},
			{"./buildah_test/app3/Dockerfile", "./buildah_test/app3"},
		} {
			d, c := loadDockerfileAndContext(desc.DockerfilePath, desc.ContextPath)

			_, err := b.BuildFromDockerfile(context.Background(), d, buildah.BuildFromDockerfileOpts{
				CommonOpts: buildah.CommonOpts{LogWriter: os.Stdout},
				ContextTar: c,
			})

			Expect(err).To(Succeed())
		}
	})
})

func loadDockerfileAndContext(dockerfilePath string, contextPath string) ([]byte, io.Reader) {
	data, err := ioutil.ReadFile(dockerfilePath)
	Expect(err).To(Succeed())

	if contextPath == "" {
		return data, nil
	}

	reader := util.ReadDirAsTar(contextPath)

	return data, reader
}
<|endoftext|>


<commit_before>package writer

import (
	"fmt"
	"io"
	"math/rand"
	"strconv"
	"strings"
	"time"

	"github.com/go-kit/log"
	"github.com/go-kit/log/level"
)

const (
	LogEntry = "%s %s\n"
)

type Writer struct {
	w                    io.Writer
	sent                 chan time.Time
	interval             time.Duration
	outOfOrderPercentage int
	outOfOrderMin        time.Duration
	outOfOrderMax        time.Duration
	size                 int
	prevTsLen            int
	pad                  string
	quit                 chan struct{}
	done                 chan struct{}

	logger log.Logger
}

func NewWriter(
	writer io.Writer,
	sentChan chan time.Time,
	entryInterval, outOfOrderMin, outOfOrderMax time.Duration,
	outOfOrderPercentage, entrySize int,
	logger log.Logger,
) *Writer {

	w := &Writer{
		w:                    writer,
		sent:                 sentChan,
		interval:             entryInterval,
		outOfOrderPercentage: outOfOrderPercentage,
		outOfOrderMin:        outOfOrderMin,
		outOfOrderMax:        outOfOrderMax,
		size:                 entrySize,
		prevTsLen:            0,
		quit:                 make(chan struct{}),
		done:                 make(chan struct{}),
		logger:               logger,
	}

	go w.run()

	return w
}

func (w *Writer) Stop() {
	if w.quit != nil {
		close(w.quit)
		<-w.done
		w.quit = nil
	}
}

func (w *Writer) run() {
	t := time.NewTicker(w.interval)
	defer func() {
		t.Stop()
		close(w.done)
	}()
	for {
		select {
		case <-t.C:
			t := time.Now()
			if i := rand.Intn(100); i < w.outOfOrderPercentage {
				n := rand.Intn(int(w.outOfOrderMax.Seconds()-w.outOfOrderMin.Seconds())) + int(w.outOfOrderMin.Seconds())
				t = t.Add(-time.Duration(n) * time.Second)
			}
			ts := strconv.FormatInt(t.UnixNano(), 10)
			tsLen := len(ts)

			// I guess some day this could happen????
			if w.prevTsLen != tsLen {
				var str strings.Builder
				// Total line length includes timestamp, white space separator, new line char.  Subtract those out
				for str.Len() < w.size-tsLen-2 {
					str.WriteString("p")
				}
				w.pad = str.String()
				w.prevTsLen = tsLen
			}

			_, err := fmt.Fprintf(w.w, LogEntry, ts, w.pad)
			if err != nil {
				level.Error(w.logger).Log("msg", "failed to write log entry", "error", err)
			}
			w.sent <- t
		case <-w.quit:
			return
		}
	}

}
<commit_msg>fix(loki-canary): Send to Loki after updating `totalEntries`. (#7211)<commit_after>package writer

import (
	"fmt"
	"io"
	"math/rand"
	"strconv"
	"strings"
	"time"

	"github.com/go-kit/log"
	"github.com/go-kit/log/level"
)

const (
	LogEntry = "%s %s\n"
)

type Writer struct {
	w                    io.Writer
	sent                 chan time.Time
	interval             time.Duration
	outOfOrderPercentage int
	outOfOrderMin        time.Duration
	outOfOrderMax        time.Duration
	size                 int
	prevTsLen            int
	pad                  string
	quit                 chan struct{}
	done                 chan struct{}

	logger log.Logger
}

func NewWriter(
	writer io.Writer,
	sentChan chan time.Time,
	entryInterval, outOfOrderMin, outOfOrderMax time.Duration,
	outOfOrderPercentage, entrySize int,
	logger log.Logger,
) *Writer {

	w := &Writer{
		w:                    writer,
		sent:                 sentChan,
		interval:             entryInterval,
		outOfOrderPercentage: outOfOrderPercentage,
		outOfOrderMin:        outOfOrderMin,
		outOfOrderMax:        outOfOrderMax,
		size:                 entrySize,
		prevTsLen:            0,
		quit:                 make(chan struct{}),
		done:                 make(chan struct{}),
		logger:               logger,
	}

	go w.run()

	return w
}

func (w *Writer) Stop() {
	if w.quit != nil {
		close(w.quit)
		<-w.done
		w.quit = nil
	}
}

func (w *Writer) run() {
	t := time.NewTicker(w.interval)
	defer func() {
		t.Stop()
		close(w.done)
	}()
	for {
		select {
		case <-t.C:
			t := time.Now()
			if i := rand.Intn(100); i < w.outOfOrderPercentage {
				n := rand.Intn(int(w.outOfOrderMax.Seconds()-w.outOfOrderMin.Seconds())) + int(w.outOfOrderMin.Seconds())
				t = t.Add(-time.Duration(n) * time.Second)
			}
			ts := strconv.FormatInt(t.UnixNano(), 10)
			tsLen := len(ts)

			// I guess some day this could happen????
			if w.prevTsLen != tsLen {
				var str strings.Builder
				// Total line length includes timestamp, white space separator, new line char.  Subtract those out
				for str.Len() < w.size-tsLen-2 {
					str.WriteString("p")
				}
				w.pad = str.String()
				w.prevTsLen = tsLen
			}
			w.sent <- t
			_, err := fmt.Fprintf(w.w, LogEntry, ts, w.pad)
			if err != nil {
				level.Error(w.logger).Log("msg", "failed to write log entry", "error", err)
			}
		case <-w.quit:
			return
		}
	}

}
<|endoftext|>