<commit_before>// since.go

package main

import (
	"flag"
	"fmt"
	"github.com/MichaelTJones/walk"
	"log"
	"os"
	"runtime"
	"sort"
	"strings"
	"sync"
	"time"
)

/* REVISION HISTORY
   21 Oct 2018 -- First started playing w/ MichaelTJones' code.  I added a help flag
   21 Oct 2022 -- In the code again, after running golangci-lint.  Changed how help flag contents is output.  If an absolute time is given, use that, else use duration.
   26 Oct 2022 -- Added '~' processing.  And output timing info.
*/

var LastAlteredDate = "Oct 26, 2022"

//var duration = flag.String("d", "", "find files modified within DURATION")
var duration = flag.Duration("dur", 5*time.Minute, "find files modified within this duration")
var format = flag.String("f", "2006-01-02 03:04:05", "time format")
var instant = flag.String("t", "", "find files modified since TIME")
var quiet = flag.Bool("q", false, "do not print filenames")
var verbose = flag.Bool("v", false, "print summary statistics")
var days = flag.Int("d", 0, "days duration")
var weeks = flag.Int("w", 0, "weeks duration")

//var help = flag.Bool("h", false, "print help message")

func main() {

	execName, _ := os.Executable()
	ExecFI, _ := os.Stat(execName)
	ExecTimeStamp := ExecFI.ModTime().Format("Mon Jan-2-2006_15:04:05 MST")

	flag.Usage = func() {
		fmt.Fprintf(flag.CommandLine.Output(), " %s last modified %s, compiled with %s, last linked %s.\n", os.Args[0], LastAlteredDate, runtime.Version(), ExecTimeStamp)
		fmt.Fprintf(flag.CommandLine.Output(), " Usage: since <options> <start-dir-list> \n")
		fmt.Fprintf(flag.CommandLine.Output(), " Valid time units for duration are ns, us, ms, s, m, h. \n")
		fmt.Fprintf(flag.CommandLine.Output(), " since -d 5m -- show all files changed within last 5 minutes starting at current directory \n")
		fmt.Fprintf(flag.CommandLine.Output(), " since -d 5m $HOME or %%userprofile -- show all files changed within last 5 minutes starting at home directory \n")
		flag.PrintDefaults()
	}
	flag.Parse()

	fmt.Printf(" since written in Go.  LastAltered %s, compiled with %s, last linked %s.\n", LastAlteredDate, runtime.Version(), ExecTimeStamp)

	now := time.Now()
	when := now
	switch {
	case *instant != "":
		t, err := time.Parse(*format, *instant)
		if err != nil {
			fmt.Printf("error parsing time %q, %s\n", *instant, err)
			os.Exit(1)
		}
		when = t
	default:
		//d, err := time.ParseDuration(*duration)
		//if err != nil {
		//	fmt.Printf("error parsing duration %q, %s\n", *duration, err)
		//	os.Exit(2)
		//}
		*duration = *duration + time.Duration(*weeks)*7*24*time.Hour + time.Duration(*days)*24*time.Hour
		when = now.Add(-*duration) // subtract duration from now.
	}

	home, err := os.UserHomeDir()
	if err != nil {
		fmt.Fprintf(os.Stderr, " Error from UserHomeDir is %v.\n", err)
	}

	if *verbose {
		fmt.Printf(" weeks = %d, days = %d, duration = %s\n", *weeks, *days, *duration)
		fmt.Printf(" when = %s, home directory is %s\n", when, home)
	}

	// goroutine to collect names of recently-modified files
	var result []string
	done := make(chan bool)
	results := make(chan string, 1024)
	go func() {
		for r := range results {
			result = append(result, r)
		}
		sort.Strings(result) // simulate ordered traversal
		done <- true
	}()

	// parallel walker and walk to find recently-modified files
	var lock sync.Mutex
	var tFiles, tBytes int // total files and bytes
	var rFiles, rBytes int // recent files and bytes
	sizeVisitor := func(path string, info os.FileInfo, err error) error {
		if err == nil {
			lock.Lock()
			tFiles += 1
			tBytes += int(info.Size())
			lock.Unlock()

			if info.ModTime().After(when) {
				lock.Lock()
				rFiles += 1
				rBytes += int(info.Size())
				lock.Unlock()

				if !*quiet {
					// fmt.Printf("%s %s\n", info.ModTime(), path) // simple
					results <- path // allows sorting into "normal" order
				}
			}
		}
		return nil
	}
	if len(flag.Args()) < 1 {
		dir, err := os.Getwd()
		if err != nil {
			log.Fatalln(" error from Getwd is", err)
		}
		err = walk.Walk(dir, sizeVisitor)
		if err != nil {
			log.Fatalln(" error from walk.Walk is", err)
		}
	} else {
		for _, root := range flag.Args() {
			dir := strings.Replace(root, "~", home, 1) // I decided to not test for windows or presence of ~.  This is pretty fast as it is.
			err := walk.Walk(dir, sizeVisitor)
			if err != nil {
				log.Fatalln(" error from walk.Walk is", err)
			}
		}
	}

	// wait for traversal results and print
	close(results) // no more results
	<-done         // wait for final results and sorting
	𝛥t := float64(time.Since(now)) / 1e9

	for _, r := range result {
		fmt.Printf("%s\n", r)
	}

	fmt.Printf(" since ran for %s\n", time.Since(now))

	// print optional verbose summary report
	if *verbose {
		log.Printf("     total: %8d files (%7.2f%%), %13d bytes (%7.2f%%)\n",
			tFiles, 100.0, tBytes, 100.0)

		rfp := 100 * float64(rFiles) / float64(tFiles)
		rbp := 100 * float64(rBytes) / float64(tBytes)
		log.Printf("    recent: %8d files (%7.2f%%), %13d bytes (%7.2f%%) in %.4f seconds\n",
			rFiles, rfp, rBytes, rbp, 𝛥t)
	}
}
<commit_msg>10/28/2022 10:30:36 PM since/since.go -- added deviceID stuff<commit_after>// since.go

package main

import (
	"flag"
	"fmt"
	jwalk "github.com/MichaelTJones/walk"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"sort"
	"strings"
	"sync"
	"syscall"
	"time"
)

/*
   REVISION HISTORY
   -------- -------
   21 Oct 2018 -- First started playing w/ MichaelTJones' code.  I added a help flag
   21 Oct 2022 -- In the code again, after running golangci-lint.  Changed how help flag contents is output.  If an absolute time is given, use that, else use duration.
   26 Oct 2022 -- Added '~' processing.  And output timing info.
   28 Oct 2022 -- On linux this takes an hour to run when I invoke it using my home directory.  I'm looking into why.  I think because it's following a symlink to bigbkupG.
                  Naw, it's also following symlinks to DSM.
                  I posted on golang-nuts for help.  I'm adding the DevID that was recommended.
*/

var LastAlteredDate = "Oct 28, 2022"

//var duration = flag.String("d", "", "find files modified within DURATION")
var duration = flag.Duration("dur", 10*time.Minute, "find files modified within this duration")
var format = flag.String("f", "2006-01-02 03:04:05", "time format")
var instant = flag.String("t", "", "find files modified since TIME")
var quiet = flag.Bool("q", false, "do not print filenames")
var verbose = flag.Bool("v", false, "print summary statistics")
var days = flag.Int("d", 0, "days duration")
var weeks = flag.Int("w", 0, "weeks duration")

type devID uint64

func main() {

	runtime.GOMAXPROCS(runtime.NumCPU())

	execName, _ := os.Executable()
	ExecFI, _ := os.Stat(execName)
	ExecTimeStamp := ExecFI.ModTime().Format("Mon Jan-2-2006_15:04:05 MST")

	flag.Usage = func() {
		fmt.Fprintf(flag.CommandLine.Output(), " %s last modified %s, compiled with %s, last linked %s.\n", os.Args[0], LastAlteredDate, runtime.Version(), ExecTimeStamp)
		fmt.Fprintf(flag.CommandLine.Output(), " Usage: since <options> <start-dir-list> \n")
		fmt.Fprintf(flag.CommandLine.Output(), " Valid time units for duration are ns, us, ms, s, m, h. \n")
		fmt.Fprintf(flag.CommandLine.Output(), " since -d 5m -- show all files changed within last 5 minutes starting at current directory \n")
		fmt.Fprintf(flag.CommandLine.Output(), " since -d 5m $HOME or %%userprofile -- show all files changed within last 5 minutes starting at home directory \n")
		flag.PrintDefaults()
	}
	flag.Parse()

	fmt.Printf(" since written in Go.  LastAltered %s, compiled with %s, last linked %s.\n", LastAlteredDate, runtime.Version(), ExecTimeStamp)

	now := time.Now()
	when := now
	switch {
	case *instant != "":
		t, err := time.Parse(*format, *instant)
		if err != nil {
			fmt.Printf("error parsing time %q, %s\n", *instant, err)
			os.Exit(1)
		}
		when = t
	default:
		//d, err := time.ParseDuration(*duration)
		//if err != nil {
		//	fmt.Printf("error parsing duration %q, %s\n", *duration, err)
		//	os.Exit(2)
		//}
		*duration = *duration + time.Duration(*weeks)*7*24*time.Hour + time.Duration(*days)*24*time.Hour
		when = now.Add(-*duration) // subtract duration from now.
	}

	home, err := os.UserHomeDir()
	if err != nil {
		fmt.Fprintf(os.Stderr, " Error from UserHomeDir is %v.\n", err)
	}

	if *verbose {
		fmt.Printf(" weeks = %d, days = %d, duration = %s\n", *weeks, *days, *duration)
		fmt.Printf(" when = %s, home directory is %s\n", when, home)
	}

	// goroutine to collect names of recently-modified files
	var result []string
	done := make(chan bool)
	results := make(chan string, 1024)
	go func() {
		for r := range results {
			result = append(result, r)
		}
		sort.Strings(result) // simulate ordered traversal
		done <- true
	}()

	// parallel walker and walk to find recently-modified files
	var lock sync.Mutex
	var tFiles, tBytes int // total files and bytes
	var rFiles, rBytes int // recent files and bytes
	var rootDeviceID devID
	var dir string

	if len(flag.Args()) < 1 {
		dir, err = os.Getwd()
		if err != nil {
			log.Fatalln(" error from Getwd is", err)
		}
	} else {
		dir = flag.Arg(0) // will only use the first argument, which is all I use anyway.
		dir = strings.Replace(dir, "~", home, 1)
	}
	fi, er := os.Stat(dir)
	if er != nil {
		log.Fatalf(" error from os.Stat(%s) is %v\n", dir, er)
	}
	rootDeviceID = GetDeviceID(dir, fi)

	sizeVisitor := func(path string, info os.FileInfo, err error) error {
		if err == nil {
			lock.Lock()
			tFiles += 1
			tBytes += int(info.Size())
			lock.Unlock()

			if info.IsDir() {
				if filepath.Ext(path) == ".git" {
					if *verbose {
						fmt.Printf(" skipping .git\n")
					}
					return filepath.SkipDir
					//} else if strings.Contains(path, ".cache") {
					//	if *verbose {
					//		fmt.Printf(" skipping .cache\n")
					//	}
					//	return filepath.SkipDir
				} else if isSymlink(info.Mode()) { // skip all symlinked directories.  I intend this to catch bigbkupG and DSM.
					if *verbose {
						fmt.Printf(" skipping symlink %s\n", path)
					}
					return filepath.SkipDir
				} else {
					id := GetDeviceID(path, info)
					if rootDeviceID != id {
						if *verbose {
							fmt.Printf(" root device id is %d for %q, path device id is %d for %q.  Skipping.\n", rootDeviceID, dir, id, path)
						}
						return filepath.SkipDir
					}
				}
			}

			if info.ModTime().After(when) {
				lock.Lock()
				rFiles += 1
				rBytes += int(info.Size())
				lock.Unlock()

				if !*quiet {
					// fmt.Printf("%s %s\n", info.ModTime(), path) // simple
					results <- path // allows sorting into "normal" order
				}
			}
		}
		return nil
	}

	if *quiet { // just so compiler sees this can potentially still be executed.
		err = jwalk.Walk(dir, sizeVisitor)
	} else {
		err = filepath.Walk(dir, sizeVisitor)
	}

	if err != nil {
		log.Printf(" error from walk.Walk is %v\n", err)
	}

	// wait for traversal results and print
	time.Sleep(3 * time.Second) // kludge to see if I really do need a waitgroup.  I think I do after all.
	close(results)              // no more results
	<-done                      // wait for final results and sorting
	𝛥t := float64(time.Since(now)) / 1e9

	for _, r := range result {
		fmt.Printf("%s\n", r)
	}

	fmt.Printf(" since ran for %s\n", time.Since(now))

	// print optional verbose summary report
	if *verbose {
		log.Printf("     total: %8d files (%7.2f%%), %13d bytes (%7.2f%%)\n",
			tFiles, 100.0, tBytes, 100.0)

		rfp := 100 * float64(rFiles) / float64(tFiles)
		rbp := 100 * float64(rBytes) / float64(tBytes)
		log.Printf("    recent: %8d files (%7.2f%%), %13d bytes (%7.2f%%) in %.4f seconds\n",
			rFiles, rfp, rBytes, rbp, 𝛥t)
	}
}

func isSymlink(fm os.FileMode) bool {
	intermed := fm & os.ModeSymlink
	return intermed != 0
}

func GetDeviceID(path string, fi os.FileInfo) devID {
	var stat = fi.Sys().(*syscall.Stat_t)
	return devID(stat.Dev)
}
<|endoftext|>


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

package runtime

import "unsafe"

// Keep a cached value to make gotraceback fast,
// since we call it on every call to gentraceback.
// The cached value is a uint32 in which the low bit
// is the "crash" setting and the top 31 bits are the
// gotraceback value.
var traceback_cache uint32 = 2 << 1

// The GOTRACEBACK environment variable controls the
// behavior of a Go program that is crashing and exiting.
//	GOTRACEBACK=0   suppress all tracebacks
//	GOTRACEBACK=1   default behavior - show tracebacks but exclude runtime frames
//	GOTRACEBACK=2   show tracebacks including runtime frames
//	GOTRACEBACK=crash   show tracebacks including runtime frames, then crash (core dump etc)
//go:nosplit
func gotraceback(crash *bool) int32 {
	_g_ := getg()
	if crash != nil {
		*crash = false
	}
	if _g_.m.traceback != 0 {
		return int32(_g_.m.traceback)
	}
	if crash != nil {
		*crash = traceback_cache&1 != 0
	}
	return int32(traceback_cache >> 1)
}

var (
	argc int32
	argv **byte
)

// nosplit for use in linux/386 startup linux_setup_vdso
//go:nosplit
func argv_index(argv **byte, i int32) *byte {
	return *(**byte)(add(unsafe.Pointer(argv), uintptr(i)*ptrSize))
}

func args(c int32, v **byte) {
	argc = c
	argv = v
	sysargs(c, v)
}

var (
	// TODO: Retire in favor of GOOS== checks.
	isplan9   int32
	issolaris int32
	iswindows int32
)

func goargs() {
	if GOOS == "windows" {
		return
	}

	argslice = make([]string, argc)
	for i := int32(0); i < argc; i++ {
		argslice[i] = gostringnocopy(argv_index(argv, i))
	}
}

func goenvs_unix() {
	// TODO(austin): ppc64 in dynamic linking mode doesn't
	// guarantee env[] will immediately follow argv.  Might cause
	// problems.
	n := int32(0)
	for argv_index(argv, argc+1+n) != nil {
		n++
	}

	envs = make([]string, n)
	for i := int32(0); i < n; i++ {
		envs[i] = gostring(argv_index(argv, argc+1+i))
	}
}

func environ() []string {
	return envs
}

// TODO: These should be locals in testAtomic64, but we don't 8-byte
// align stack variables on 386.
var test_z64, test_x64 uint64

func testAtomic64() {
	test_z64 = 42
	test_x64 = 0
	prefetcht0(uintptr(unsafe.Pointer(&test_z64)))
	prefetcht1(uintptr(unsafe.Pointer(&test_z64)))
	prefetcht2(uintptr(unsafe.Pointer(&test_z64)))
	prefetchnta(uintptr(unsafe.Pointer(&test_z64)))
	if cas64(&test_z64, test_x64, 1) {
		throw("cas64 failed")
	}
	if test_x64 != 0 {
		throw("cas64 failed")
	}
	test_x64 = 42
	if !cas64(&test_z64, test_x64, 1) {
		throw("cas64 failed")
	}
	if test_x64 != 42 || test_z64 != 1 {
		throw("cas64 failed")
	}
	if atomicload64(&test_z64) != 1 {
		throw("load64 failed")
	}
	atomicstore64(&test_z64, (1<<40)+1)
	if atomicload64(&test_z64) != (1<<40)+1 {
		throw("store64 failed")
	}
	if xadd64(&test_z64, (1<<40)+1) != (2<<40)+2 {
		throw("xadd64 failed")
	}
	if atomicload64(&test_z64) != (2<<40)+2 {
		throw("xadd64 failed")
	}
	if xchg64(&test_z64, (3<<40)+3) != (2<<40)+2 {
		throw("xchg64 failed")
	}
	if atomicload64(&test_z64) != (3<<40)+3 {
		throw("xchg64 failed")
	}
}

func check() {
	var (
		a     int8
		b     uint8
		c     int16
		d     uint16
		e     int32
		f     uint32
		g     int64
		h     uint64
		i, i1 float32
		j, j1 float64
		k, k1 unsafe.Pointer
		l     *uint16
		m     [4]byte
	)
	type x1t struct {
		x uint8
	}
	type y1t struct {
		x1 x1t
		y  uint8
	}
	var x1 x1t
	var y1 y1t

	if unsafe.Sizeof(a) != 1 {
		throw("bad a")
	}
	if unsafe.Sizeof(b) != 1 {
		throw("bad b")
	}
	if unsafe.Sizeof(c) != 2 {
		throw("bad c")
	}
	if unsafe.Sizeof(d) != 2 {
		throw("bad d")
	}
	if unsafe.Sizeof(e) != 4 {
		throw("bad e")
	}
	if unsafe.Sizeof(f) != 4 {
		throw("bad f")
	}
	if unsafe.Sizeof(g) != 8 {
		throw("bad g")
	}
	if unsafe.Sizeof(h) != 8 {
		throw("bad h")
	}
	if unsafe.Sizeof(i) != 4 {
		throw("bad i")
	}
	if unsafe.Sizeof(j) != 8 {
		throw("bad j")
	}
	if unsafe.Sizeof(k) != ptrSize {
		throw("bad k")
	}
	if unsafe.Sizeof(l) != ptrSize {
		throw("bad l")
	}
	if unsafe.Sizeof(x1) != 1 {
		throw("bad unsafe.Sizeof x1")
	}
	if unsafe.Offsetof(y1.y) != 1 {
		throw("bad offsetof y1.y")
	}
	if unsafe.Sizeof(y1) != 2 {
		throw("bad unsafe.Sizeof y1")
	}

	if timediv(12345*1000000000+54321, 1000000000, &e) != 12345 || e != 54321 {
		throw("bad timediv")
	}

	var z uint32
	z = 1
	if !cas(&z, 1, 2) {
		throw("cas1")
	}
	if z != 2 {
		throw("cas2")
	}

	z = 4
	if cas(&z, 5, 6) {
		throw("cas3")
	}
	if z != 4 {
		throw("cas4")
	}

	z = 0xffffffff
	if !cas(&z, 0xffffffff, 0xfffffffe) {
		throw("cas5")
	}
	if z != 0xfffffffe {
		throw("cas6")
	}

	k = unsafe.Pointer(uintptr(0xfedcb123))
	if ptrSize == 8 {
		k = unsafe.Pointer(uintptr(unsafe.Pointer(k)) << 10)
	}
	if casp(&k, nil, nil) {
		throw("casp1")
	}
	k1 = add(k, 1)
	if !casp(&k, k, k1) {
		throw("casp2")
	}
	if k != k1 {
		throw("casp3")
	}

	m = [4]byte{1, 1, 1, 1}
	atomicor8(&m[1], 0xf0)
	if m[0] != 1 || m[1] != 0xf1 || m[2] != 1 || m[3] != 1 {
		throw("atomicor8")
	}

	*(*uint64)(unsafe.Pointer(&j)) = ^uint64(0)
	if j == j {
		throw("float64nan")
	}
	if !(j != j) {
		throw("float64nan1")
	}

	*(*uint64)(unsafe.Pointer(&j1)) = ^uint64(1)
	if j == j1 {
		throw("float64nan2")
	}
	if !(j != j1) {
		throw("float64nan3")
	}

	*(*uint32)(unsafe.Pointer(&i)) = ^uint32(0)
	if i == i {
		throw("float32nan")
	}
	if i == i {
		throw("float32nan1")
	}

	*(*uint32)(unsafe.Pointer(&i1)) = ^uint32(1)
	if i == i1 {
		throw("float32nan2")
	}
	if i == i1 {
		throw("float32nan3")
	}

	testAtomic64()

	if _FixedStack != round2(_FixedStack) {
		throw("FixedStack is not power-of-2")
	}
}

type dbgVar struct {
	name  string
	value *int32
}

// TODO(rsc): Make GC respect debug.invalidptr.

// Holds variables parsed from GODEBUG env var,
// except for "memprofilerate" since there is an
// existing int var for that value, which may
// already have an initial value.
var debug struct {
	allocfreetrace    int32
	efence            int32
	gccheckmark       int32
	gcpacertrace      int32
	gcshrinkstackoff  int32
	gcstackbarrieroff int32
	gcstoptheworld    int32
	gctrace           int32
	invalidptr        int32
	sbrk              int32
	scavenge          int32
	scheddetail       int32
	schedtrace        int32
	wbshadow          int32
}

var dbgvars = []dbgVar{
	{"allocfreetrace", &debug.allocfreetrace},
	{"efence", &debug.efence},
	{"gccheckmark", &debug.gccheckmark},
	{"gcpacertrace", &debug.gcpacertrace},
	{"gcshrinkstackoff", &debug.gcshrinkstackoff},
	{"gcstackbarrieroff", &debug.gcstackbarrieroff},
	{"gcstoptheworld", &debug.gcstoptheworld},
	{"gctrace", &debug.gctrace},
	{"invalidptr", &debug.invalidptr},
	{"sbrk", &debug.sbrk},
	{"scavenge", &debug.scavenge},
	{"scheddetail", &debug.scheddetail},
	{"schedtrace", &debug.schedtrace},
	{"wbshadow", &debug.wbshadow},
}

func parsedebugvars() {
	for p := gogetenv("GODEBUG"); p != ""; {
		field := ""
		i := index(p, ",")
		if i < 0 {
			field, p = p, ""
		} else {
			field, p = p[:i], p[i+1:]
		}
		i = index(field, "=")
		if i < 0 {
			continue
		}
		key, value := field[:i], field[i+1:]

		// Update MemProfileRate directly here since it
		// is int, not int32, and should only be updated
		// if specified in GODEBUG.
		if key == "memprofilerate" {
			MemProfileRate = atoi(value)
		} else {
			for _, v := range dbgvars {
				if v.name == key {
					*v.value = int32(atoi(value))
				}
			}
		}
	}

	switch p := gogetenv("GOTRACEBACK"); p {
	case "":
		traceback_cache = 1 << 1
	case "crash":
		traceback_cache = 2<<1 | 1
	default:
		traceback_cache = uint32(atoi(p)) << 1
	}
}

// Poor mans 64-bit division.
// This is a very special function, do not use it if you are not sure what you are doing.
// int64 division is lowered into _divv() call on 386, which does not fit into nosplit functions.
// Handles overflow in a time-specific manner.
//go:nosplit
func timediv(v int64, div int32, rem *int32) int32 {
	res := int32(0)
	for bit := 30; bit >= 0; bit-- {
		if v >= int64(div)<<uint(bit) {
			v = v - (int64(div) << uint(bit))
			res += 1 << uint(bit)
		}
	}
	if v >= int64(div) {
		if rem != nil {
			*rem = 0
		}
		return 0x7fffffff
	}
	if rem != nil {
		*rem = int32(v)
	}
	return res
}

// Helpers for Go. Must be NOSPLIT, must only call NOSPLIT functions, and must not block.

//go:nosplit
func acquirem() *m {
	_g_ := getg()
	_g_.m.locks++
	return _g_.m
}

//go:nosplit
func releasem(mp *m) {
	_g_ := getg()
	mp.locks--
	if mp.locks == 0 && _g_.preempt {
		// restore the preemption request in case we've cleared it in newstack
		_g_.stackguard0 = stackPreempt
	}
}

//go:nosplit
func gomcache() *mcache {
	return getg().m.mcache
}

//go:linkname reflect_typelinks reflect.typelinks
//go:nosplit
func reflect_typelinks() [][]*_type {
	ret := [][]*_type{firstmoduledata.typelinks}
	for datap := firstmoduledata.next; datap != nil; datap = datap.next {
		ret = append(ret, datap.typelinks)
	}
	return ret
}
<commit_msg>runtime: abort on fatal errors and panics in c-shared and c-archive modes<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package runtime

import "unsafe"

// Keep a cached value to make gotraceback fast,
// since we call it on every call to gentraceback.
// The cached value is a uint32 in which the low bit
// is the "crash" setting and the top 31 bits are the
// gotraceback value.
var traceback_cache uint32 = 2 << 1

// The GOTRACEBACK environment variable controls the
// behavior of a Go program that is crashing and exiting.
//	GOTRACEBACK=0   suppress all tracebacks
//	GOTRACEBACK=1   default behavior - show tracebacks but exclude runtime frames
//	GOTRACEBACK=2   show tracebacks including runtime frames
//	GOTRACEBACK=crash   show tracebacks including runtime frames, then crash (core dump etc)
//go:nosplit
func gotraceback(crash *bool) int32 {
	_g_ := getg()
	if crash != nil {
		*crash = false
	}
	if _g_.m.traceback != 0 {
		return int32(_g_.m.traceback)
	}
	if crash != nil {
		*crash = traceback_cache&1 != 0
	}
	return int32(traceback_cache >> 1)
}

var (
	argc int32
	argv **byte
)

// nosplit for use in linux/386 startup linux_setup_vdso
//go:nosplit
func argv_index(argv **byte, i int32) *byte {
	return *(**byte)(add(unsafe.Pointer(argv), uintptr(i)*ptrSize))
}

func args(c int32, v **byte) {
	argc = c
	argv = v
	sysargs(c, v)
}

var (
	// TODO: Retire in favor of GOOS== checks.
	isplan9   int32
	issolaris int32
	iswindows int32
)

func goargs() {
	if GOOS == "windows" {
		return
	}

	argslice = make([]string, argc)
	for i := int32(0); i < argc; i++ {
		argslice[i] = gostringnocopy(argv_index(argv, i))
	}
}

func goenvs_unix() {
	// TODO(austin): ppc64 in dynamic linking mode doesn't
	// guarantee env[] will immediately follow argv.  Might cause
	// problems.
	n := int32(0)
	for argv_index(argv, argc+1+n) != nil {
		n++
	}

	envs = make([]string, n)
	for i := int32(0); i < n; i++ {
		envs[i] = gostring(argv_index(argv, argc+1+i))
	}
}

func environ() []string {
	return envs
}

// TODO: These should be locals in testAtomic64, but we don't 8-byte
// align stack variables on 386.
var test_z64, test_x64 uint64

func testAtomic64() {
	test_z64 = 42
	test_x64 = 0
	prefetcht0(uintptr(unsafe.Pointer(&test_z64)))
	prefetcht1(uintptr(unsafe.Pointer(&test_z64)))
	prefetcht2(uintptr(unsafe.Pointer(&test_z64)))
	prefetchnta(uintptr(unsafe.Pointer(&test_z64)))
	if cas64(&test_z64, test_x64, 1) {
		throw("cas64 failed")
	}
	if test_x64 != 0 {
		throw("cas64 failed")
	}
	test_x64 = 42
	if !cas64(&test_z64, test_x64, 1) {
		throw("cas64 failed")
	}
	if test_x64 != 42 || test_z64 != 1 {
		throw("cas64 failed")
	}
	if atomicload64(&test_z64) != 1 {
		throw("load64 failed")
	}
	atomicstore64(&test_z64, (1<<40)+1)
	if atomicload64(&test_z64) != (1<<40)+1 {
		throw("store64 failed")
	}
	if xadd64(&test_z64, (1<<40)+1) != (2<<40)+2 {
		throw("xadd64 failed")
	}
	if atomicload64(&test_z64) != (2<<40)+2 {
		throw("xadd64 failed")
	}
	if xchg64(&test_z64, (3<<40)+3) != (2<<40)+2 {
		throw("xchg64 failed")
	}
	if atomicload64(&test_z64) != (3<<40)+3 {
		throw("xchg64 failed")
	}
}

func check() {
	var (
		a     int8
		b     uint8
		c     int16
		d     uint16
		e     int32
		f     uint32
		g     int64
		h     uint64
		i, i1 float32
		j, j1 float64
		k, k1 unsafe.Pointer
		l     *uint16
		m     [4]byte
	)
	type x1t struct {
		x uint8
	}
	type y1t struct {
		x1 x1t
		y  uint8
	}
	var x1 x1t
	var y1 y1t

	if unsafe.Sizeof(a) != 1 {
		throw("bad a")
	}
	if unsafe.Sizeof(b) != 1 {
		throw("bad b")
	}
	if unsafe.Sizeof(c) != 2 {
		throw("bad c")
	}
	if unsafe.Sizeof(d) != 2 {
		throw("bad d")
	}
	if unsafe.Sizeof(e) != 4 {
		throw("bad e")
	}
	if unsafe.Sizeof(f) != 4 {
		throw("bad f")
	}
	if unsafe.Sizeof(g) != 8 {
		throw("bad g")
	}
	if unsafe.Sizeof(h) != 8 {
		throw("bad h")
	}
	if unsafe.Sizeof(i) != 4 {
		throw("bad i")
	}
	if unsafe.Sizeof(j) != 8 {
		throw("bad j")
	}
	if unsafe.Sizeof(k) != ptrSize {
		throw("bad k")
	}
	if unsafe.Sizeof(l) != ptrSize {
		throw("bad l")
	}
	if unsafe.Sizeof(x1) != 1 {
		throw("bad unsafe.Sizeof x1")
	}
	if unsafe.Offsetof(y1.y) != 1 {
		throw("bad offsetof y1.y")
	}
	if unsafe.Sizeof(y1) != 2 {
		throw("bad unsafe.Sizeof y1")
	}

	if timediv(12345*1000000000+54321, 1000000000, &e) != 12345 || e != 54321 {
		throw("bad timediv")
	}

	var z uint32
	z = 1
	if !cas(&z, 1, 2) {
		throw("cas1")
	}
	if z != 2 {
		throw("cas2")
	}

	z = 4
	if cas(&z, 5, 6) {
		throw("cas3")
	}
	if z != 4 {
		throw("cas4")
	}

	z = 0xffffffff
	if !cas(&z, 0xffffffff, 0xfffffffe) {
		throw("cas5")
	}
	if z != 0xfffffffe {
		throw("cas6")
	}

	k = unsafe.Pointer(uintptr(0xfedcb123))
	if ptrSize == 8 {
		k = unsafe.Pointer(uintptr(unsafe.Pointer(k)) << 10)
	}
	if casp(&k, nil, nil) {
		throw("casp1")
	}
	k1 = add(k, 1)
	if !casp(&k, k, k1) {
		throw("casp2")
	}
	if k != k1 {
		throw("casp3")
	}

	m = [4]byte{1, 1, 1, 1}
	atomicor8(&m[1], 0xf0)
	if m[0] != 1 || m[1] != 0xf1 || m[2] != 1 || m[3] != 1 {
		throw("atomicor8")
	}

	*(*uint64)(unsafe.Pointer(&j)) = ^uint64(0)
	if j == j {
		throw("float64nan")
	}
	if !(j != j) {
		throw("float64nan1")
	}

	*(*uint64)(unsafe.Pointer(&j1)) = ^uint64(1)
	if j == j1 {
		throw("float64nan2")
	}
	if !(j != j1) {
		throw("float64nan3")
	}

	*(*uint32)(unsafe.Pointer(&i)) = ^uint32(0)
	if i == i {
		throw("float32nan")
	}
	if i == i {
		throw("float32nan1")
	}

	*(*uint32)(unsafe.Pointer(&i1)) = ^uint32(1)
	if i == i1 {
		throw("float32nan2")
	}
	if i == i1 {
		throw("float32nan3")
	}

	testAtomic64()

	if _FixedStack != round2(_FixedStack) {
		throw("FixedStack is not power-of-2")
	}
}

type dbgVar struct {
	name  string
	value *int32
}

// TODO(rsc): Make GC respect debug.invalidptr.

// Holds variables parsed from GODEBUG env var,
// except for "memprofilerate" since there is an
// existing int var for that value, which may
// already have an initial value.
var debug struct {
	allocfreetrace    int32
	efence            int32
	gccheckmark       int32
	gcpacertrace      int32
	gcshrinkstackoff  int32
	gcstackbarrieroff int32
	gcstoptheworld    int32
	gctrace           int32
	invalidptr        int32
	sbrk              int32
	scavenge          int32
	scheddetail       int32
	schedtrace        int32
	wbshadow          int32
}

var dbgvars = []dbgVar{
	{"allocfreetrace", &debug.allocfreetrace},
	{"efence", &debug.efence},
	{"gccheckmark", &debug.gccheckmark},
	{"gcpacertrace", &debug.gcpacertrace},
	{"gcshrinkstackoff", &debug.gcshrinkstackoff},
	{"gcstackbarrieroff", &debug.gcstackbarrieroff},
	{"gcstoptheworld", &debug.gcstoptheworld},
	{"gctrace", &debug.gctrace},
	{"invalidptr", &debug.invalidptr},
	{"sbrk", &debug.sbrk},
	{"scavenge", &debug.scavenge},
	{"scheddetail", &debug.scheddetail},
	{"schedtrace", &debug.schedtrace},
	{"wbshadow", &debug.wbshadow},
}

func parsedebugvars() {
	for p := gogetenv("GODEBUG"); p != ""; {
		field := ""
		i := index(p, ",")
		if i < 0 {
			field, p = p, ""
		} else {
			field, p = p[:i], p[i+1:]
		}
		i = index(field, "=")
		if i < 0 {
			continue
		}
		key, value := field[:i], field[i+1:]

		// Update MemProfileRate directly here since it
		// is int, not int32, and should only be updated
		// if specified in GODEBUG.
		if key == "memprofilerate" {
			MemProfileRate = atoi(value)
		} else {
			for _, v := range dbgvars {
				if v.name == key {
					*v.value = int32(atoi(value))
				}
			}
		}
	}

	switch p := gogetenv("GOTRACEBACK"); p {
	case "":
		traceback_cache = 1 << 1
	case "crash":
		traceback_cache = 2<<1 | 1
	default:
		traceback_cache = uint32(atoi(p)) << 1
	}
	// when C owns the process, simply exit'ing the process on fatal errors
	// and panics is surprising. Be louder and abort instead.
	if islibrary || isarchive {
		traceback_cache |= 1
	}
}

// Poor mans 64-bit division.
// This is a very special function, do not use it if you are not sure what you are doing.
// int64 division is lowered into _divv() call on 386, which does not fit into nosplit functions.
// Handles overflow in a time-specific manner.
//go:nosplit
func timediv(v int64, div int32, rem *int32) int32 {
	res := int32(0)
	for bit := 30; bit >= 0; bit-- {
		if v >= int64(div)<<uint(bit) {
			v = v - (int64(div) << uint(bit))
			res += 1 << uint(bit)
		}
	}
	if v >= int64(div) {
		if rem != nil {
			*rem = 0
		}
		return 0x7fffffff
	}
	if rem != nil {
		*rem = int32(v)
	}
	return res
}

// Helpers for Go. Must be NOSPLIT, must only call NOSPLIT functions, and must not block.

//go:nosplit
func acquirem() *m {
	_g_ := getg()
	_g_.m.locks++
	return _g_.m
}

//go:nosplit
func releasem(mp *m) {
	_g_ := getg()
	mp.locks--
	if mp.locks == 0 && _g_.preempt {
		// restore the preemption request in case we've cleared it in newstack
		_g_.stackguard0 = stackPreempt
	}
}

//go:nosplit
func gomcache() *mcache {
	return getg().m.mcache
}

//go:linkname reflect_typelinks reflect.typelinks
//go:nosplit
func reflect_typelinks() [][]*_type {
	ret := [][]*_type{firstmoduledata.typelinks}
	for datap := firstmoduledata.next; datap != nil; datap = datap.next {
		ret = append(ret, datap.typelinks)
	}
	return ret
}
<|endoftext|>


<commit_before>package ast

//go:generate sh -c "./md2go es5.md > astnodes.go && go fmt"

import (
	"encoding/json"
	"fmt"
	"reflect"
)

// typeOnly is used to determine node types in first pass of two-pass
// JSON unmarhsalling routines.
type typeOnly struct {
	Type string `json:"type"`
}

type node interface {
	_is_node()
}

func (nodeStuff) _is_node() {}

type statement interface {
	_is_statement()
}

func (statementStuff) _is_statement() {}

type Statement struct{ S statement }
type Statements []statement

func (this *Statement) UnmarshalJSON(b []byte) error {
	var tmp typeOnly
	if err := json.Unmarshal(b, &tmp); err != nil {
		return err
	}
	stype, ok := statementTypes[tmp.Type]
	if !ok {
		return fmt.Errorf("ast: json.Unmarshal: unknown type %s", tmp.Type)
	}
	var s statement = reflect.New(reflect.TypeOf(stype).Elem()).
		Interface().(statement)
	if err := json.Unmarshal(b, &s); err != nil {
		return err
	}
	this.S = s
	return nil
}

func (this *Statements) UnmarshalJSON(b []byte) error {
	var tmp []typeOnly
	if err := json.Unmarshal(b, &tmp); err != nil {
		return err
	}
	s := make([]statement, len(tmp))
	for i, t := range tmp {
		stype, ok := statementTypes[t.Type]
		if !ok {
			return fmt.Errorf("ast: json.Unmarshal: unknown type %s", t.Type)
		}
		s[i] = reflect.New(reflect.TypeOf(stype).Elem()).Interface().(statement)
	}
	if err := json.Unmarshal(b, &s); err != nil {
		return err
	}
	*this = s
	return nil
}

type Expression struct{ E expression }
type Expressions []expression
type expression interface {
	_is_expression()
}

func (expressionStuff) _is_expression() {}

func (this *Expression) UnmarshalJSON(b []byte) error {
	var tmp typeOnly
	if err := json.Unmarshal(b, &tmp); err != nil {
		return err
	}
	etype, ok := expressionTypes[tmp.Type]
	if !ok {
		return fmt.Errorf("ast: json.Unmarshal: unknown type %s", tmp.Type)
	}
	var e expression = reflect.New(reflect.TypeOf(etype).Elem()).
		Interface().(expression)
	if err := json.Unmarshal(b, &e); err != nil {
		return err
	}
	this.E = e
	return nil
}

func (this *Expressions) UnmarshalJSON(b []byte) error {
	var tmp []typeOnly
	if err := json.Unmarshal(b, &tmp); err != nil {
		return err
	}
	e := make([]expression, len(tmp))
	for i, t := range tmp {
		etype, ok := expressionTypes[t.Type]
		if !ok {
			return fmt.Errorf("ast: json.Unmarshal: unknown type %s", t.Type)
		}
		e[i] = reflect.New(reflect.TypeOf(etype).Elem()).
			Interface().(expression)
	}
	if err := json.Unmarshal(b, &e); err != nil {
		return err
	}
	*this = e
	return nil
}

type DeclOrID struct{ N declOrID }
type declOrID interface {
	_is_declOrID()
}

func (VariableDeclaration) _is_declOrID() {}
func (Identifier) _is_declOrID()          {}

func (this *DeclOrID) UnmarshalJSON(b []byte) error {
	var tmp typeOnly
	if err := json.Unmarshal(b, &tmp); err != nil {
		return err
	}
	var n declOrID
	switch tmp.Type {
	case "VariableDeclaration":
		n = new(VariableDeclaration)
	case "Identifier":
		n = new(Identifier)
	default:
		return fmt.Errorf("Unrecognized type %s", tmp.Type)
	}
	if err := json.Unmarshal(b, &n); err != nil {
		return err
	}
	this.N = n
	return nil
}

type LitOrID struct{ N litOrID }
type litOrID interface {
	_is_litOrID()
}

func (Literal) _is_litOrID()    {}
func (Identifier) _is_litOrID() {}

func (this *LitOrID) UnmarshalJSON(b []byte) error {
	var tmp typeOnly
	if err := json.Unmarshal(b, &tmp); err != nil {
		return err
	}
	var n litOrID
	switch tmp.Type {
	case "Literal":
		n = new(Literal)
	case "Identifier":
		n = new(Identifier)
	default:
		return fmt.Errorf("Unrecognized type %s", tmp.Type)
	}
	if err := json.Unmarshal(b, &n); err != nil {
		return err
	}
	this.N = n
	return nil
}
<commit_msg>Documentation for package ast<commit_after>// The ast package defines types to store an abstract syntax tree, in
// ESTree EcmaScript 5 format, as defined at
// https://github.com/estree/estree/blob/master/es5.md, as tree of Go
// structs, interfaces, and slices.
//
// Most of the ES5 nodes are represented by a Go struct of the same
// name, with fields with capitalised versions of the same names (so
// they are visible outside the ast package).
//
// There are some execptions - notably for statements and expressions -
// where multiple different ES5 node types can appear in the same
// position in the parse tree.
//
// Most of the type declarations are in astnodes.go which is
// auto-generated from the ES5 ESTree spec document by the md2go
// script; run `go generate` to update it.  The rest of the code, and
// in particular interface types and associated methods, is in ast.go.
package ast

//go:generate sh -c "./md2go es5.md > astnodes.go && go fmt"

import (
	"encoding/json"
	"fmt"
	"reflect"
)

// typeOnly is used to determine node types in first pass of two-pass
// JSON unmarhsalling routines.
type typeOnly struct {
	Type string `json:"type"`
}

type node interface {
	_is_node()
}

func (nodeStuff) _is_node() {}

type statement interface {
	_is_statement()
}

func (statementStuff) _is_statement() {}

type Statement struct{ S statement }
type Statements []statement

func (this *Statement) UnmarshalJSON(b []byte) error {
	var tmp typeOnly
	if err := json.Unmarshal(b, &tmp); err != nil {
		return err
	}
	stype, ok := statementTypes[tmp.Type]
	if !ok {
		return fmt.Errorf("ast: json.Unmarshal: unknown type %s", tmp.Type)
	}
	var s statement = reflect.New(reflect.TypeOf(stype).Elem()).
		Interface().(statement)
	if err := json.Unmarshal(b, &s); err != nil {
		return err
	}
	this.S = s
	return nil
}

func (this *Statements) UnmarshalJSON(b []byte) error {
	var tmp []typeOnly
	if err := json.Unmarshal(b, &tmp); err != nil {
		return err
	}
	s := make([]statement, len(tmp))
	for i, t := range tmp {
		stype, ok := statementTypes[t.Type]
		if !ok {
			return fmt.Errorf("ast: json.Unmarshal: unknown type %s", t.Type)
		}
		s[i] = reflect.New(reflect.TypeOf(stype).Elem()).Interface().(statement)
	}
	if err := json.Unmarshal(b, &s); err != nil {
		return err
	}
	*this = s
	return nil
}

type Expression struct{ E expression }
type Expressions []expression
type expression interface {
	_is_expression()
}

func (expressionStuff) _is_expression() {}

func (this *Expression) UnmarshalJSON(b []byte) error {
	var tmp typeOnly
	if err := json.Unmarshal(b, &tmp); err != nil {
		return err
	}
	etype, ok := expressionTypes[tmp.Type]
	if !ok {
		return fmt.Errorf("ast: json.Unmarshal: unknown type %s", tmp.Type)
	}
	var e expression = reflect.New(reflect.TypeOf(etype).Elem()).
		Interface().(expression)
	if err := json.Unmarshal(b, &e); err != nil {
		return err
	}
	this.E = e
	return nil
}

func (this *Expressions) UnmarshalJSON(b []byte) error {
	var tmp []typeOnly
	if err := json.Unmarshal(b, &tmp); err != nil {
		return err
	}
	e := make([]expression, len(tmp))
	for i, t := range tmp {
		etype, ok := expressionTypes[t.Type]
		if !ok {
			return fmt.Errorf("ast: json.Unmarshal: unknown type %s", t.Type)
		}
		e[i] = reflect.New(reflect.TypeOf(etype).Elem()).
			Interface().(expression)
	}
	if err := json.Unmarshal(b, &e); err != nil {
		return err
	}
	*this = e
	return nil
}

type DeclOrID struct{ N declOrID }
type declOrID interface {
	_is_declOrID()
}

func (VariableDeclaration) _is_declOrID() {}
func (Identifier) _is_declOrID()          {}

func (this *DeclOrID) UnmarshalJSON(b []byte) error {
	var tmp typeOnly
	if err := json.Unmarshal(b, &tmp); err != nil {
		return err
	}
	var n declOrID
	switch tmp.Type {
	case "VariableDeclaration":
		n = new(VariableDeclaration)
	case "Identifier":
		n = new(Identifier)
	default:
		return fmt.Errorf("Unrecognized type %s", tmp.Type)
	}
	if err := json.Unmarshal(b, &n); err != nil {
		return err
	}
	this.N = n
	return nil
}

type LitOrID struct{ N litOrID }
type litOrID interface {
	_is_litOrID()
}

func (Literal) _is_litOrID()    {}
func (Identifier) _is_litOrID() {}

func (this *LitOrID) UnmarshalJSON(b []byte) error {
	var tmp typeOnly
	if err := json.Unmarshal(b, &tmp); err != nil {
		return err
	}
	var n litOrID
	switch tmp.Type {
	case "Literal":
		n = new(Literal)
	case "Identifier":
		n = new(Identifier)
	default:
		return fmt.Errorf("Unrecognized type %s", tmp.Type)
	}
	if err := json.Unmarshal(b, &n); err != nil {
		return err
	}
	this.N = n
	return nil
}
<|endoftext|>


<commit_before>/**
Message-oriented socket.

Provides a TCP connection for transferring messages.
Each message has its 32bit length.

Sending of messages is synchronous (see Send() method).
Reading of incoming messages is implemented as background
thread. 'handler' callback is called for each incoming
message.
*/

package tcpcall

import (
	"bufio"
	"encoding/binary"
	"errors"
	"io"
	"net"
	"sync"
	"tcpcall/pools"
	"time"
)

// Packet header Len
const HEADER_LEN = 4

// Errors
var (
	MsgConnNotConnectedError = errors.New("msg conn: not connected")
	MsgTooLongError          = errors.New("incoming message is too long")
)

// Message oriented connection
type MsgConn struct {
	socket    net.Conn
	buffer    *bufio.Writer
	lastFlush time.Time
	// socket write mutex
	socketMu sync.Mutex
	// maximum allowed length for incoming packets
	maxPacketLen int
	// Minimum time between write buffer flushes
	minFlushPeriod time.Duration
	// incoming package handler
	handler func([]byte)
	// callback for disconnect event
	onDisconnect func()
}

// Create new message oriented connection.
func NewMsgConn(
	socket net.Conn,
	minFlushPeriod time.Duration,
	writeBufferSize int,
	maxPacketLen int,
	handler func([]byte),
	onClose func(),
) (*MsgConn, error) {
	if err := socket.SetReadDeadline(time.Time{}); err != nil {
		return nil, err
	}
	conn := &MsgConn{
		socket:         socket,
		buffer:         bufio.NewWriterSize(socket, writeBufferSize),
		handler:        handler,
		onDisconnect:   onClose,
		maxPacketLen:   maxPacketLen,
		minFlushPeriod: minFlushPeriod,
	}
	go conn.readLoop()
	return conn, nil
}

// SetWriteDeadline sets the deadline for future Write calls
// and any currently-blocked Write call.
// A zero value for t means Write will not time out.
func (c *MsgConn) SetWriteDeadline(t time.Time) error {
	return c.socket.SetWriteDeadline(t)
}

// Send message to the other side.
func (c *MsgConn) Send(msg [][]byte) error {
	if c == nil {
		return MsgConnNotConnectedError
	}
	msgLen := 0
	for _, e := range msg {
		msgLen += len(e)
	}
	c.socketMu.Lock()
	if err := binary.Write(c.buffer, binary.BigEndian, uint32(msgLen)); err != nil {
		c.closeUnsafe()
		c.socketMu.Unlock()
		return err
	}
	// write chunks one by one
	for _, e := range msg {
		if _, err := c.buffer.Write(e); err != nil {
			c.closeUnsafe()
			c.socketMu.Unlock()
			return err
		}
	}
	// flush the buffer
	if c.minFlushPeriod <= 0 ||
		time.Now().After(c.lastFlush.Add(c.minFlushPeriod)) {
		if err := c.buffer.Flush(); err != nil {
			c.closeUnsafe()
			c.socketMu.Unlock()
			return err
		}
		c.lastFlush = time.Now()
	}
	c.socketMu.Unlock()
	return nil
}

// Close connection.
func (c *MsgConn) Close() {
	c.socketMu.Lock()
	c.closeUnsafe()
	c.socketMu.Unlock()
}

func (c *MsgConn) closeUnsafe() {
	if c.socket == nil {
		return
	}
	c.socket.Close()
	c.socket = nil
	if c.onDisconnect != nil {
		c.onDisconnect()
	}
}

// Return truth if connection is already closed.
func (c *MsgConn) Closed() bool {
	if c == nil {
		return true
	}
	c.socketMu.Lock()
	res := c.socket == nil
	c.socketMu.Unlock()
	return res
}

// Goroutine.
// Receive incoming messages from the other side
// and call callback function for each.
func (c *MsgConn) readLoop() {
	for {
		packet, err := c.readPacket()
		if err != nil {
			c.Close()
			return
		}
		c.handler(packet)
	}
}

// Receive next message from the other side.
func (c *MsgConn) readPacket() ([]byte, error) {
	header := pools.GetFreeBuffer(HEADER_LEN)
	if _, err := io.ReadAtLeast(c.socket, header, len(header)); err != nil {
		return nil, err
	}
	len := int(binary.BigEndian.Uint32(header))
	pools.ReleaseBuffer(header)
	if 0 < c.maxPacketLen && c.maxPacketLen < len {
		return nil, MsgTooLongError
	}
	buffer := make([]byte, len)
	if _, err := io.ReadAtLeast(c.socket, buffer, len); err != nil {
		return nil, err
	}
	return buffer[:len], nil
}
<commit_msg>Avoid nil pointer dereference on packet read<commit_after>/**
Message-oriented socket.

Provides a TCP connection for transferring messages.
Each message has its 32bit length.

Sending of messages is synchronous (see Send() method).
Reading of incoming messages is implemented as background
thread. 'handler' callback is called for each incoming
message.
*/

package tcpcall

import (
	"bufio"
	"encoding/binary"
	"errors"
	"io"
	"net"
	"sync"
	"tcpcall/pools"
	"time"
)

// Packet header Len
const HEADER_LEN = 4

// Errors
var (
	MsgConnNotConnectedError = errors.New("msg conn: not connected")
	MsgTooLongError          = errors.New("incoming message is too long")
)

// Message oriented connection
type MsgConn struct {
	socket    net.Conn
	buffer    *bufio.Writer
	lastFlush time.Time
	// socket write mutex
	socketMu sync.Mutex
	// maximum allowed length for incoming packets
	maxPacketLen int
	// Minimum time between write buffer flushes
	minFlushPeriod time.Duration
	// incoming package handler
	handler func([]byte)
	// callback for disconnect event
	onDisconnect func()
}

// Create new message oriented connection.
func NewMsgConn(
	socket net.Conn,
	minFlushPeriod time.Duration,
	writeBufferSize int,
	maxPacketLen int,
	handler func([]byte),
	onClose func(),
) (*MsgConn, error) {
	if err := socket.SetReadDeadline(time.Time{}); err != nil {
		return nil, err
	}
	conn := &MsgConn{
		socket:         socket,
		buffer:         bufio.NewWriterSize(socket, writeBufferSize),
		handler:        handler,
		onDisconnect:   onClose,
		maxPacketLen:   maxPacketLen,
		minFlushPeriod: minFlushPeriod,
	}
	go conn.readLoop()
	return conn, nil
}

// SetWriteDeadline sets the deadline for future Write calls
// and any currently-blocked Write call.
// A zero value for t means Write will not time out.
func (c *MsgConn) SetWriteDeadline(t time.Time) error {
	return c.socket.SetWriteDeadline(t)
}

// Send message to the other side.
func (c *MsgConn) Send(msg [][]byte) error {
	if c == nil {
		return MsgConnNotConnectedError
	}
	msgLen := 0
	for _, e := range msg {
		msgLen += len(e)
	}
	c.socketMu.Lock()
	if err := binary.Write(c.buffer, binary.BigEndian, uint32(msgLen)); err != nil {
		c.closeUnsafe()
		c.socketMu.Unlock()
		return err
	}
	// write chunks one by one
	for _, e := range msg {
		if _, err := c.buffer.Write(e); err != nil {
			c.closeUnsafe()
			c.socketMu.Unlock()
			return err
		}
	}
	// flush the buffer
	if c.minFlushPeriod <= 0 ||
		time.Now().After(c.lastFlush.Add(c.minFlushPeriod)) {
		if err := c.buffer.Flush(); err != nil {
			c.closeUnsafe()
			c.socketMu.Unlock()
			return err
		}
		c.lastFlush = time.Now()
	}
	c.socketMu.Unlock()
	return nil
}

// Close connection.
func (c *MsgConn) Close() {
	c.socketMu.Lock()
	c.closeUnsafe()
	c.socketMu.Unlock()
}

func (c *MsgConn) closeUnsafe() {
	if c.socket == nil {
		return
	}
	c.socket.Close()
	c.socket = nil
	if c.onDisconnect != nil {
		c.onDisconnect()
	}
}

// Return truth if connection is already closed.
func (c *MsgConn) Closed() bool {
	if c == nil {
		return true
	}
	c.socketMu.Lock()
	res := c.socket == nil
	c.socketMu.Unlock()
	return res
}

// Goroutine.
// Receive incoming messages from the other side
// and call callback function for each.
func (c *MsgConn) readLoop() {
	for {
		packet, err := c.readPacket()
		if err != nil {
			c.Close()
			return
		}
		c.handler(packet)
	}
}

// Receive next message from the other side.
func (c *MsgConn) readPacket() ([]byte, error) {
	socket := c.socket
	if socket == nil {
		return nil, MsgConnNotConnectedError
	}
	header := pools.GetFreeBuffer(HEADER_LEN)
	if _, err := io.ReadAtLeast(socket, header, len(header)); err != nil {
		return nil, err
	}
	len := int(binary.BigEndian.Uint32(header))
	pools.ReleaseBuffer(header)
	if 0 < c.maxPacketLen && c.maxPacketLen < len {
		return nil, MsgTooLongError
	}
	buffer := make([]byte, len)
	if _, err := io.ReadAtLeast(socket, buffer, len); err != nil {
		return nil, err
	}
	return buffer[:len], nil
}
<|endoftext|>


<commit_before>package google

import (
	"fmt"
	"log"
	"time"

	"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
	cloudresourcemanager "google.golang.org/api/cloudresourcemanager/v1"
	"google.golang.org/api/googleapi"
)

type Waiter interface {
	// State returns the current status of the operation.
	State() string

	// Error returns an error embedded in the operation we're waiting on, or nil
	// if the operation has no current error.
	Error() error

	// IsRetryable returns whether a given error should be retried.
	IsRetryable(error) bool

	// SetOp sets the operation we're waiting on in a Waiter struct so that it
	// can be used in other methods.
	SetOp(interface{}) error

	// QueryOp sends a request to the server to get the current status of the
	// operation. It's expected that QueryOp will return exactly one of an
	// operation or an error as non-nil, and that requests will be retried by
	// specific implementations of the method.
	QueryOp() (interface{}, error)

	// OpName is the name of the operation and is used to log its status.
	OpName() string

	// PendingStates contains the values of State() that cause us to continue
	// refreshing the operation.
	PendingStates() []string

	// TargetStates contain the values of State() that cause us to finish
	// refreshing the operation.
	TargetStates() []string
}

type CommonOperationWaiter struct {
	Op CommonOperation
}

func (w *CommonOperationWaiter) State() string {
	if w == nil {
		return fmt.Sprintf("Operation is nil!")
	}

	return fmt.Sprintf("done: %v", w.Op.Done)
}

func (w *CommonOperationWaiter) Error() error {
	if w != nil && w.Op.Error != nil {
		return fmt.Errorf("Error code %v, message: %s", w.Op.Error.Code, w.Op.Error.Message)
	}
	return nil
}

func (w *CommonOperationWaiter) IsRetryable(error) bool {
	return false
}

func (w *CommonOperationWaiter) SetOp(op interface{}) error {
	if err := Convert(op, &w.Op); err != nil {
		return err
	}
	return nil
}

func (w *CommonOperationWaiter) OpName() string {
	if w == nil {
		return "<nil>"
	}

	return w.Op.Name
}

func (w *CommonOperationWaiter) PendingStates() []string {
	return []string{"done: false"}
}

func (w *CommonOperationWaiter) TargetStates() []string {
	return []string{"done: true"}
}

func OperationDone(w Waiter) bool {
	for _, s := range w.TargetStates() {
		if s == w.State() {
			return true
		}
	}
	return false
}

func CommonRefreshFunc(w Waiter) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		op, err := w.QueryOp()
		if err != nil {
			// Importantly, this error is in the GET to the operation, and isn't an error
			// with the resource CRUD request itself.
			if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
				log.Printf("[DEBUG] Dismissed an operation GET as retryable based on error code being 404: %s", err)
				return op, "done: false", nil
			}

			return nil, "", fmt.Errorf("error while retrieving operation: %s", err)
		}

		if err = w.SetOp(op); err != nil {
			return nil, "", fmt.Errorf("Cannot continue, unable to use operation: %s", err)
		}

		if err = w.Error(); err != nil {
			if w.IsRetryable(err) {
				log.Printf("[DEBUG] Retrying operation GET based on retryable err: %s", err)
				return op, w.State(), nil
			}
			return nil, "", err
		}

		log.Printf("[DEBUG] Got %v while polling for operation %s's status", w.State(), w.OpName())
		return op, w.State(), nil
	}
}

func OperationWait(w Waiter, activity string, timeoutMinutes int) error {
	if OperationDone(w) {
		if w.Error() != nil {
			return w.Error()
		}
		return nil
	}

	c := &resource.StateChangeConf{
		Pending:    w.PendingStates(),
		Target:     w.TargetStates(),
		Refresh:    CommonRefreshFunc(w),
		Timeout:    time.Duration(timeoutMinutes) * time.Minute,
		MinTimeout: 2 * time.Second,
	}
	opRaw, err := c.WaitForState()
	if err != nil {
		return fmt.Errorf("Error waiting for %s: %s", activity, err)
	}

	err = w.SetOp(opRaw)
	if err != nil {
		return err
	}
	if w.Error() != nil {
		return w.Error()
	}

	return nil
}

// The cloud resource manager API operation is an example of one of many
// interchangeable API operations. Choose it somewhat arbitrarily to represent
// the "common" operation.
type CommonOperation cloudresourcemanager.Operation
<commit_msg>Enable general retries for QueryOp(...) calls (#257)<commit_after>package google

import (
	"fmt"
	"log"
	"net/url"
	"time"

	"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
	cloudresourcemanager "google.golang.org/api/cloudresourcemanager/v1"
	"google.golang.org/api/googleapi"
)

type Waiter interface {
	// State returns the current status of the operation.
	State() string

	// Error returns an error embedded in the operation we're waiting on, or nil
	// if the operation has no current error.
	Error() error

	// IsRetryable returns whether a given error should be retried.
	IsRetryable(error) bool

	// SetOp sets the operation we're waiting on in a Waiter struct so that it
	// can be used in other methods.
	SetOp(interface{}) error

	// QueryOp sends a request to the server to get the current status of the
	// operation. It's expected that QueryOp will return exactly one of an
	// operation or an error as non-nil, and that requests will be retried by
	// specific implementations of the method.
	QueryOp() (interface{}, error)

	// OpName is the name of the operation and is used to log its status.
	OpName() string

	// PendingStates contains the values of State() that cause us to continue
	// refreshing the operation.
	PendingStates() []string

	// TargetStates contain the values of State() that cause us to finish
	// refreshing the operation.
	TargetStates() []string
}

type CommonOperationWaiter struct {
	Op CommonOperation
}

func (w *CommonOperationWaiter) State() string {
	if w == nil {
		return fmt.Sprintf("Operation is nil!")
	}

	return fmt.Sprintf("done: %v", w.Op.Done)
}

func (w *CommonOperationWaiter) Error() error {
	if w != nil && w.Op.Error != nil {
		return fmt.Errorf("Error code %v, message: %s", w.Op.Error.Code, w.Op.Error.Message)
	}
	return nil
}

func (w *CommonOperationWaiter) IsRetryable(error) bool {
	return false
}

func (w *CommonOperationWaiter) SetOp(op interface{}) error {
	if err := Convert(op, &w.Op); err != nil {
		return err
	}
	return nil
}

func (w *CommonOperationWaiter) OpName() string {
	if w == nil {
		return "<nil>"
	}

	return w.Op.Name
}

func (w *CommonOperationWaiter) PendingStates() []string {
	return []string{"done: false"}
}

func (w *CommonOperationWaiter) TargetStates() []string {
	return []string{"done: true"}
}

func OperationDone(w Waiter) bool {
	for _, s := range w.TargetStates() {
		if s == w.State() {
			return true
		}
	}
	return false
}

func CommonRefreshFunc(w Waiter) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		op, err := w.QueryOp()
		if err != nil {
			// Importantly, this error is in the GET to the operation, and isn't an error
			// with the resource CRUD request itself.
			notFoundRetryPredicate := func(e error) (bool, string) {
				if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
					return true, "should retry 404s on a GET of an Operation"
				}
				return false, ""
			}
			predicates := []func(e error) (bool, string){
				notFoundRetryPredicate,
			}
			for _, e := range getAllTypes(err, &googleapi.Error{}, &url.Error{}) {
				if isRetryableError(e, predicates) {
					log.Printf("[DEBUG] Dismissed error on GET of operation '%v' retryable: %s", w.OpName(), err)
					return op, "done: false", nil
				}
			}

			return nil, "", fmt.Errorf("error while retrieving operation: %s", err)
		}

		if err = w.SetOp(op); err != nil {
			return nil, "", fmt.Errorf("Cannot continue, unable to use operation: %s", err)
		}

		if err = w.Error(); err != nil {
			if w.IsRetryable(err) {
				log.Printf("[DEBUG] Retrying operation GET based on retryable err: %s", err)
				return op, w.State(), nil
			}
			return nil, "", err
		}

		log.Printf("[DEBUG] Got %v while polling for operation %s's status", w.State(), w.OpName())
		return op, w.State(), nil
	}
}

func OperationWait(w Waiter, activity string, timeoutMinutes int) error {
	if OperationDone(w) {
		if w.Error() != nil {
			return w.Error()
		}
		return nil
	}

	c := &resource.StateChangeConf{
		Pending:    w.PendingStates(),
		Target:     w.TargetStates(),
		Refresh:    CommonRefreshFunc(w),
		Timeout:    time.Duration(timeoutMinutes) * time.Minute,
		MinTimeout: 2 * time.Second,
	}
	opRaw, err := c.WaitForState()
	if err != nil {
		return fmt.Errorf("Error waiting for %s: %s", activity, err)
	}

	err = w.SetOp(opRaw)
	if err != nil {
		return err
	}
	if w.Error() != nil {
		return w.Error()
	}

	return nil
}

// The cloud resource manager API operation is an example of one of many
// interchangeable API operations. Choose it somewhat arbitrarily to represent
// the "common" operation.
type CommonOperation cloudresourcemanager.Operation
<|endoftext|>


<commit_before>// ----------------------------------------------------------------------------
//
//     ***     AUTO GENERATED CODE    ***    Type: MMv1     ***
//
// ----------------------------------------------------------------------------
//
//     This file is automatically generated by Magic Modules and manual
//     changes will be clobbered when the file is regenerated.
//
//     Please read more about how to change this file in
//     .github/CONTRIBUTING.md.
//
// ----------------------------------------------------------------------------

package google

import (
	"fmt"
	"log"
	"reflect"
	"regexp"

	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func deleteSpannerBackups(d *schema.ResourceData, config *Config, res map[string]interface{}, userAgent string, billingProject string) error {
	var v interface{}
	var ok bool

	v, ok = res["backups"]
	if !ok || v == nil {
		return nil
	}

	// Iterate over the list and delete each backup.
	for _, itemRaw := range v.([]interface{}) {
		if itemRaw == nil {
			continue
		}
		item := itemRaw.(map[string]interface{})

		backupName := item["name"].(string)

		log.Printf("[DEBUG] Found backups for resource %q: %#v)", d.Id(), item)

		path := "{{SpannerBasePath}}" + backupName

		url, err := replaceVars(d, config, path)
		if err != nil {
			return err
		}

		_, err = sendRequest(config, "DELETE", billingProject, url, userAgent, nil)
		if err != nil {
			return err
		}
	}
	return nil
}

func GetSpannerInstanceCaiObject(d TerraformResourceData, config *Config) ([]Asset, error) {
	name, err := assetName(d, config, "//spanner.googleapis.com/projects/{{project}}/instances/{{name}}")
	if err != nil {
		return []Asset{}, err
	}
	if obj, err := GetSpannerInstanceApiObject(d, config); err == nil {
		return []Asset{{
			Name: name,
			Type: "spanner.googleapis.com/Instance",
			Resource: &AssetResource{
				Version:              "v1",
				DiscoveryDocumentURI: "https://www.googleapis.com/discovery/v1/apis/spanner/v1/rest",
				DiscoveryName:        "Instance",
				Data:                 obj,
			},
		}}, nil
	} else {
		return []Asset{}, err
	}
}

func GetSpannerInstanceApiObject(d TerraformResourceData, config *Config) (map[string]interface{}, error) {
	obj := make(map[string]interface{})
	nameProp, err := expandSpannerInstanceName(d.Get("name"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(nameProp)) && (ok || !reflect.DeepEqual(v, nameProp)) {
		obj["name"] = nameProp
	}
	configProp, err := expandSpannerInstanceConfig(d.Get("config"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("config"); !isEmptyValue(reflect.ValueOf(configProp)) && (ok || !reflect.DeepEqual(v, configProp)) {
		obj["config"] = configProp
	}
	displayNameProp, err := expandSpannerInstanceDisplayName(d.Get("display_name"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("display_name"); !isEmptyValue(reflect.ValueOf(displayNameProp)) && (ok || !reflect.DeepEqual(v, displayNameProp)) {
		obj["displayName"] = displayNameProp
	}
	nodeCountProp, err := expandSpannerInstanceNumNodes(d.Get("num_nodes"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("num_nodes"); !isEmptyValue(reflect.ValueOf(nodeCountProp)) && (ok || !reflect.DeepEqual(v, nodeCountProp)) {
		obj["nodeCount"] = nodeCountProp
	}
	processingUnitsProp, err := expandSpannerInstanceProcessingUnits(d.Get("processing_units"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("processing_units"); !isEmptyValue(reflect.ValueOf(processingUnitsProp)) && (ok || !reflect.DeepEqual(v, processingUnitsProp)) {
		obj["processingUnits"] = processingUnitsProp
	}
	labelsProp, err := expandSpannerInstanceLabels(d.Get("labels"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("labels"); !isEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) {
		obj["labels"] = labelsProp
	}

	return resourceSpannerInstanceEncoder(d, config, obj)
}

func resourceSpannerInstanceEncoder(d TerraformResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) {
	// Temp Logic to accomodate processing_units and num_nodes
	if obj["processingUnits"] == nil && obj["nodeCount"] == nil {
		obj["nodeCount"] = 1
	}
	newObj := make(map[string]interface{})
	newObj["instance"] = obj
	if obj["name"] == nil {
		if err := d.Set("name", resource.PrefixedUniqueId("tfgen-spanid-")[:30]); err != nil {
			return nil, fmt.Errorf("Error setting name: %s", err)
		}
		newObj["instanceId"] = d.Get("name").(string)
	} else {
		newObj["instanceId"] = obj["name"]
	}
	delete(obj, "name")
	return newObj, nil
}

func expandSpannerInstanceName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandSpannerInstanceConfig(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	r := regexp.MustCompile("projects/(.+)/instanceConfigs/(.+)")
	if r.MatchString(v.(string)) {
		return v.(string), nil
	}

	project, err := getProject(d, config)
	if err != nil {
		return nil, err
	}

	return fmt.Sprintf("projects/%s/instanceConfigs/%s", project, v.(string)), nil
}

func expandSpannerInstanceDisplayName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandSpannerInstanceNumNodes(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandSpannerInstanceProcessingUnits(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandSpannerInstanceLabels(v interface{}, d TerraformResourceData, config *Config) (map[string]string, error) {
	if v == nil {
		return map[string]string{}, nil
	}
	m := make(map[string]string)
	for k, val := range v.(map[string]interface{}) {
		m[k] = val.(string)
	}
	return m, nil
}
<commit_msg>Fix typo in spanner code (#5041) (#758)<commit_after>// ----------------------------------------------------------------------------
//
//     ***     AUTO GENERATED CODE    ***    Type: MMv1     ***
//
// ----------------------------------------------------------------------------
//
//     This file is automatically generated by Magic Modules and manual
//     changes will be clobbered when the file is regenerated.
//
//     Please read more about how to change this file in
//     .github/CONTRIBUTING.md.
//
// ----------------------------------------------------------------------------

package google

import (
	"fmt"
	"log"
	"reflect"
	"regexp"

	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func deleteSpannerBackups(d *schema.ResourceData, config *Config, res map[string]interface{}, userAgent string, billingProject string) error {
	var v interface{}
	var ok bool

	v, ok = res["backups"]
	if !ok || v == nil {
		return nil
	}

	// Iterate over the list and delete each backup.
	for _, itemRaw := range v.([]interface{}) {
		if itemRaw == nil {
			continue
		}
		item := itemRaw.(map[string]interface{})

		backupName := item["name"].(string)

		log.Printf("[DEBUG] Found backups for resource %q: %#v)", d.Id(), item)

		path := "{{SpannerBasePath}}" + backupName

		url, err := replaceVars(d, config, path)
		if err != nil {
			return err
		}

		_, err = sendRequest(config, "DELETE", billingProject, url, userAgent, nil)
		if err != nil {
			return err
		}
	}
	return nil
}

func GetSpannerInstanceCaiObject(d TerraformResourceData, config *Config) ([]Asset, error) {
	name, err := assetName(d, config, "//spanner.googleapis.com/projects/{{project}}/instances/{{name}}")
	if err != nil {
		return []Asset{}, err
	}
	if obj, err := GetSpannerInstanceApiObject(d, config); err == nil {
		return []Asset{{
			Name: name,
			Type: "spanner.googleapis.com/Instance",
			Resource: &AssetResource{
				Version:              "v1",
				DiscoveryDocumentURI: "https://www.googleapis.com/discovery/v1/apis/spanner/v1/rest",
				DiscoveryName:        "Instance",
				Data:                 obj,
			},
		}}, nil
	} else {
		return []Asset{}, err
	}
}

func GetSpannerInstanceApiObject(d TerraformResourceData, config *Config) (map[string]interface{}, error) {
	obj := make(map[string]interface{})
	nameProp, err := expandSpannerInstanceName(d.Get("name"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(nameProp)) && (ok || !reflect.DeepEqual(v, nameProp)) {
		obj["name"] = nameProp
	}
	configProp, err := expandSpannerInstanceConfig(d.Get("config"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("config"); !isEmptyValue(reflect.ValueOf(configProp)) && (ok || !reflect.DeepEqual(v, configProp)) {
		obj["config"] = configProp
	}
	displayNameProp, err := expandSpannerInstanceDisplayName(d.Get("display_name"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("display_name"); !isEmptyValue(reflect.ValueOf(displayNameProp)) && (ok || !reflect.DeepEqual(v, displayNameProp)) {
		obj["displayName"] = displayNameProp
	}
	nodeCountProp, err := expandSpannerInstanceNumNodes(d.Get("num_nodes"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("num_nodes"); !isEmptyValue(reflect.ValueOf(nodeCountProp)) && (ok || !reflect.DeepEqual(v, nodeCountProp)) {
		obj["nodeCount"] = nodeCountProp
	}
	processingUnitsProp, err := expandSpannerInstanceProcessingUnits(d.Get("processing_units"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("processing_units"); !isEmptyValue(reflect.ValueOf(processingUnitsProp)) && (ok || !reflect.DeepEqual(v, processingUnitsProp)) {
		obj["processingUnits"] = processingUnitsProp
	}
	labelsProp, err := expandSpannerInstanceLabels(d.Get("labels"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("labels"); !isEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) {
		obj["labels"] = labelsProp
	}

	return resourceSpannerInstanceEncoder(d, config, obj)
}

func resourceSpannerInstanceEncoder(d TerraformResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) {
	// Temp Logic to accommodate processing_units and num_nodes
	if obj["processingUnits"] == nil && obj["nodeCount"] == nil {
		obj["nodeCount"] = 1
	}
	newObj := make(map[string]interface{})
	newObj["instance"] = obj
	if obj["name"] == nil {
		if err := d.Set("name", resource.PrefixedUniqueId("tfgen-spanid-")[:30]); err != nil {
			return nil, fmt.Errorf("Error setting name: %s", err)
		}
		newObj["instanceId"] = d.Get("name").(string)
	} else {
		newObj["instanceId"] = obj["name"]
	}
	delete(obj, "name")
	return newObj, nil
}

func expandSpannerInstanceName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandSpannerInstanceConfig(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	r := regexp.MustCompile("projects/(.+)/instanceConfigs/(.+)")
	if r.MatchString(v.(string)) {
		return v.(string), nil
	}

	project, err := getProject(d, config)
	if err != nil {
		return nil, err
	}

	return fmt.Sprintf("projects/%s/instanceConfigs/%s", project, v.(string)), nil
}

func expandSpannerInstanceDisplayName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandSpannerInstanceNumNodes(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandSpannerInstanceProcessingUnits(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandSpannerInstanceLabels(v interface{}, d TerraformResourceData, config *Config) (map[string]string, error) {
	if v == nil {
		return map[string]string{}, nil
	}
	m := make(map[string]string)
	for k, val := range v.(map[string]interface{}) {
		m[k] = val.(string)
	}
	return m, nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/base64"
	"crypto/rand"
	"errors"
	"path"
	"net/http"
	"net/url"
	"log"
	"strings"
	"fmt"
	"image"
	"image/jpeg"
	"os"
)

// some constants
const ItemLength = 18
const CreateAttempts = 10
const FanOut = 3
const SourceFileName = "source.jpeg"

type Handler struct {
	rootDir string
}

func (s Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		s.Get(w, r)
	case "POST":
		s.Post(w, r)
	case "PUT":
		s.Put(w, r)
	case "DELETE":
		s.Delete(w, r)
	default:
		http.Error(w, "Method Not Allowed", 405)
	}
}

func randomString() string {
	slice := make([]byte, ItemLength)
	rand.Read(slice)
	return base64.URLEncoding.EncodeToString(slice)
}

func dirName(token string) string {
	// really happy this works, by the way
	parts := strings.SplitN(token, "", FanOut+1)
	// now here i was, almost making an argument how golang isn't elegant
	return path.Join(parts...)
}

func (s Handler) filePath(u *url.URL) string {
	return path.Join(s.rootDir, u.Path)
}

func (s Handler) urlPath(fullPath string) string {
	return strings.Replace(fullPath, s.rootDir, "", 1)
}

func (s Handler) createFile() (*os.File, string, error) {
	flags := os.O_RDWR|os.O_CREATE|os.O_EXCL
	for i := 0; i < CreateAttempts; i++ {
		dir := path.Join(s.rootDir, dirName(randomString()))
		if err := os.MkdirAll(dir, 0755); err != nil {
			return nil, "", err
		}
		filename := path.Join(dir, SourceFileName)
		file, err := os.OpenFile(filename, flags, 0644)
		if err != nil {
			if os.IsExist(err) {
				continue
			}
			return nil, "", err
		}
		// return with a file and its name
		return file, filename, nil
	}
	return nil, "", errors.New("Exceeded attempts to create file")
}

// Handle an upload request
func (s Handler) Put(w http.ResponseWriter, r *http.Request) {
	if r.Body == nil {
		http.Error(w, "No data sent", 400)
		return
	}
	img, _, err := image.Decode(r.Body)
	if err != nil {
		http.Error(w, "Could not decode image", 400)
		return
	}
	file, filename, err := s.createFile()
	if err != nil {
		http.Error(w, "Could not create file", 500)
		log.Print(err)
		return
	}
	defer file.Close()
	if err = jpeg.Encode(file, img, nil); err != nil {
		http.Error(w, "Could not save image", 500)
		log.Print(err)
	} else {
		// great success!
		http.Redirect(w, r, s.urlPath(filename), 301)
	}
}

// Handle a GET request
func (s Handler) Get(w http.ResponseWriter, r *http.Request) {
	fullPath := s.filePath(r.URL)
	file, err := os.OpenFile(fullPath, os.O_RDWR, 0600)
	if err != nil {
		if os.IsNotExist(err) {
			http.NotFound(w, r)
		} else {
			http.Error(w, "Internal Server Error", 500)
			log.Print(err)
		}
		return
	}
	defer file.Close()
	info, err := file.Stat()
	if err != nil {
		http.Error(w, "Internal Server Error", 500)
		log.Print(err)
		return
	} else if info.IsDir() {
		http.Error(w, "Forbidden", 403)
	} else if info.Size() == 0 {

	} else {
		http.ServeContent(w, r, info.Name(), info.ModTime(), file)
	}
}

func (s Handler) Post(w http.ResponseWriter, r *http.Request) {

}

func (s Handler) Delete(w http.ResponseWriter, r *http.Request) {
	fullPath := s.filePath(r.URL)
	info, err := os.Stat(fullPath)
	if err != nil {
		if os.IsNotExist(err) {
			http.NotFound(w, r)
		} else {
			http.Error(w, "Internal Server Error", 500)
		}
		return
	}
	if info.IsDir() {
		http.Error(w, "Forbidden", 403)
	} else if info.Name() == SourceFileName {
		if err = os.RemoveAll(path.Dir(fullPath)); err != nil {
			http.Error(w, "Internal Server Error", 500)
		} else {
			fmt.Fprintln(w, "OK")
		}
	} else {
		os.Remove(fullPath)
	}
}

func main() {
	fmt.Println("OH HAI")
}
<commit_msg>reformatted, added makeImage function, nyi<commit_after>package main

import (
	"crypto/rand"
	"encoding/base64"
	"errors"
	"fmt"
	"image"
	"image/jpeg"
	"log"
	"net/http"
	"net/url"
	"os"
	"path"
	"strings"
	"time"
)

// some constants
const ItemLength = 18
const CreateAttempts = 10
const FanOut = 3
const SourceFileName = "source.jpeg"

type Handler struct {
	rootDir string
}

func (s Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		s.Get(w, r)
	case "POST":
		s.Post(w, r)
	case "PUT":
		s.Put(w, r)
	case "DELETE":
		s.Delete(w, r)
	default:
		http.Error(w, "Method Not Allowed", 405)
	}
}

func randomString() string {
	slice := make([]byte, ItemLength)
	rand.Read(slice)
	return base64.URLEncoding.EncodeToString(slice)
}

func dirName(token string) string {
	// really happy this works, by the way
	parts := strings.SplitN(token, "", FanOut+1)
	// now here i was, almost making an argument how golang isn't elegant
	return path.Join(parts...)
}

func (s Handler) filePath(u *url.URL) string {
	return path.Join(s.rootDir, u.Path)
}

func (s Handler) urlPath(fullPath string) string {
	return strings.Replace(fullPath, s.rootDir, "", 1)
}

func (s Handler) createFile() (*os.File, string, error) {
	flags := os.O_RDWR | os.O_CREATE | os.O_EXCL
	for i := 0; i < CreateAttempts; i++ {
		dir := path.Join(s.rootDir, dirName(randomString()))
		if err := os.MkdirAll(dir, 0755); err != nil {
			return nil, "", err
		}
		filename := path.Join(dir, SourceFileName)
		file, err := os.OpenFile(filename, flags, 0644)
		if err != nil {
			if os.IsExist(err) {
				continue
			}
			return nil, "", err
		}
		// return with a file and its name
		return file, filename, nil
	}
	return nil, "", errors.New("Exceeded attempts to create file")
}

func makeImage(filename string, file *os.File) error {
	return nil
}

// Handle an upload request
func (s Handler) Put(w http.ResponseWriter, r *http.Request) {
	if r.Body == nil {
		http.Error(w, "No data sent", 400)
		return
	}
	img, _, err := image.Decode(r.Body)
	if err != nil {
		http.Error(w, "Could not decode image", 400)
		return
	}
	file, filename, err := s.createFile()
	if err != nil {
		http.Error(w, "Could not create file", 500)
		log.Print(err)
		return
	}
	defer file.Close()
	if err = jpeg.Encode(file, img, nil); err != nil {
		http.Error(w, "Could not save image", 500)
		log.Print(err)
	} else {
		// great success!
		http.Redirect(w, r, s.urlPath(filename), 301)
	}
}

// Handle a GET request
func (s Handler) Get(w http.ResponseWriter, r *http.Request) {
	fullPath := s.filePath(r.URL)
	file, err := os.OpenFile(fullPath, os.O_RDWR, 0600)
	if err != nil {
		if os.IsNotExist(err) {
			http.NotFound(w, r)
		} else {
			http.Error(w, "Internal Server Error", 500)
			log.Print(err)
		}
		return
	}
	defer file.Close()
	info, err := file.Stat()
	if err != nil {
		http.Error(w, "Internal Server Error", 500)
		log.Print(err)
		return
	} else if info.IsDir() {
		http.Error(w, "Forbidden", 403)
	} else if info.Size() == 0 {
		if err = makeImage(fullPath, file); err != nil {
			os.Remove(fullPath) // don't try again
			http.NotFound(w, r) // bluff
		} else {
			http.ServeContent(w, r, info.Name(), time.Now(), file)
		}
	} else {
		http.ServeContent(w, r, info.Name(), info.ModTime(), file)
	}
}

func (s Handler) Post(w http.ResponseWriter, r *http.Request) {

}

func (s Handler) Delete(w http.ResponseWriter, r *http.Request) {
	fullPath := s.filePath(r.URL)
	info, err := os.Stat(fullPath)
	if err != nil {
		if os.IsNotExist(err) {
			http.NotFound(w, r)
		} else {
			http.Error(w, "Internal Server Error", 500)
		}
		return
	}
	if info.IsDir() {
		http.Error(w, "Forbidden", 403)
	} else if info.Name() == SourceFileName {
		if err = os.RemoveAll(path.Dir(fullPath)); err != nil {
			http.Error(w, "Internal Server Error", 500)
		} else {
			fmt.Fprintln(w, "OK")
		}
	} else {
		os.Remove(fullPath)
	}
}

func main() {
	fmt.Println("OH HAI")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/trasa/watchmud/direction"
	"github.com/trasa/watchmud/message"
)

func (c *Client) printPrompt() {
	// TODO need to figure out when the right time to print the prompt is ...
	fmt.Print("> ")
}

// for a response with IsSuccess == false,
// print a generic error message.
func (c *Client) printError(resp message.Response) {
	fmt.Println("Error:", resp.GetMessageType(), resp.GetResultCode())
}

// print this room description to the player
func (c *Client) printRoom(room message.RoomDescription) {
	fmt.Println(room.Name)
	fmt.Println()
	fmt.Println(room.Description)
	// obvious exits
	if exits, err := direction.ExitsToFormattedString(room.Exits); err == nil {
		fmt.Println("Obvious Exits:", exits)
	} else {
		fmt.Println("Error Getting exits:", err)
	}
	if len(room.Players) > 0 || len(room.Objects) > 0 {
		fmt.Println()
	}
	// objects
	for _, o := range room.Objects {
		fmt.Println(o)
	}
	// other players, mobs
	for _, p := range room.Players {
		fmt.Printf("%s stands here.\n", p)
	}
}
<commit_msg>room description includes mobs<commit_after>package main

import (
	"fmt"
	"github.com/trasa/watchmud/direction"
	"github.com/trasa/watchmud/message"
)

func (c *Client) printPrompt() {
	// TODO need to figure out when the right time to print the prompt is ...
	fmt.Print("> ")
}

// for a response with IsSuccess == false,
// print a generic error message.
func (c *Client) printError(resp message.Response) {
	fmt.Println("Error:", resp.GetMessageType(), resp.GetResultCode())
}

// print this room description to the player
func (c *Client) printRoom(room message.RoomDescription) {
	fmt.Println(room.Name)
	fmt.Println()
	fmt.Println(room.Description)
	// obvious exits
	if exits, err := direction.ExitsToFormattedString(room.Exits); err == nil {
		fmt.Println("Obvious Exits:", exits)
	} else {
		fmt.Println("Error Getting exits:", err)
	}
	if len(room.Players) > 0 || len(room.Objects) > 0 {
		fmt.Println()
	}
	// objects
	for _, o := range room.Objects {
		fmt.Println(o)
	}
	// other players
	for _, m := range room.Mobs {
		fmt.Println(m)
	}
	for _, p := range room.Players {
		fmt.Printf("%s stands here.\n", p)
	}
}
<|endoftext|>


<commit_before>package jobber

/*
	Copyright 2017 Daniel Carbone

	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.
*/

import (
	"fmt"
	"sync"
)

// Boss controls the life of the workers
type Boss struct {
	*sync.RWMutex

	workers map[string]*worker
	hr      chan *worker
}

// New creates a Boss
func NewBoss() *Boss {
	// initialize boss
	b := &Boss{
		RWMutex: &sync.RWMutex{},

		workers: make(map[string]*worker),
		hr:      make(chan *worker, 100),
	}

	// start up that hr team...
	go b.exitInterview()

	return b
}

// HasWorker lets you know if a worker already exists for a job
func (b *Boss) HasWorker(name string) bool {
	b.RLock()
	defer b.RUnlock()

	// do we have this person?
	if _, ok := b.workers[name]; ok {
		return true
	}

	return false
}

// NewWorker will attempt to create a new worker for a job. Returns error if you've already hired somebody.
func (b *Boss) NewWorker(name string, queueLength int) error {
	// see if we're already got somebody doin' it
	if b.HasWorker(name) {
		if debug {
			logger.Printf("Jobber: A worker for job \"%s\" already exists.\n", name)
		}
		return fmt.Errorf("A worker for job \"%s\" already exists.", name)
	}

	// 'lil input sanitizing
	if 0 > queueLength {
		// shout
		if debug {
			logger.Printf(
				"Jobber: Incoming new worker request for job \"%s\" request specified invalid queue"+
					" length of \"%d\", will set length to \"0\"\n",
				name,
				queueLength)
		}
		// make unbuffered
		queueLength = 0
	}

	// tell the world
	logger.Printf(
		"Jobber: Creating new worker for job with name \"%s\" and queue length of \"%d\"\n",
		name,
		queueLength)

	// lock boss down
	b.Lock()
	defer b.Unlock()

	// add worker
	b.workers[name] = newWorker(name, queueLength)

	// start up work routine
	go b.workers[name].doWork()

	// maybe say so?
	if debug {
		logger.Printf("Jobber: Go routine started for job \"%s\"\n", name)
	}

	return nil
}

// AddWork will push a new job to the end of a worker's queue
func (b *Boss) AddJob(workerName string, j Job) error {
	// see if we've already hired this worker
	if false == b.HasWorker(workerName) {
		if debug {
			logger.Printf("Jobber: No worker with \"%s\" found.\n", workerName)
		}
		return fmt.Errorf("No worker with name \"%s\" found", workerName)
	}

	// lock boss down
	b.RLock()
	defer b.RUnlock()

	// add to worker queue
	return b.workers[workerName].addJob(j)
}

// NewUnbufferedWorker will attempt to create a new worker with a queue length of 0
func (b *Boss) NewUnbufferedWorker(name string) error {
	return b.NewWorker(name, 0)
}

// StopWorker will tell a worker to finish up their queue then remove them
func (b *Boss) StopWorker(workerName string) error {
	if false == b.HasWorker(workerName) {
		if debug {
			logger.Printf("Jobber: No worker named \"%s\" found, cannot tell them to stop.", workerName)
		}
		return fmt.Errorf("No worker named \"%s\" found, cannot tell them to stop.", workerName)
	}

	b.RLock()
	defer b.RUnlock()

	err := b.workers[workerName].stop(b.hr)
	if nil != err {
		return err
	}

	return nil
}

// exitInterview processes workers coming in to hr
func (b *Boss) exitInterview() {
	for {
		select {
		case w := <-b.hr:
			logger.Printf("Jobber: Worker \"%s\" has completed all queued tasks.  They completed"+
				"\"%d\" jobs all told. Goodbye, \"%s\"...\n",
				w.name,
				w.completed,
				w.name)
			b.Lock()
			delete(b.workers, w.name)
			b.Unlock()
		}
	}
}
<commit_msg>some mo lil stuff<commit_after>package jobber

/*
	Copyright 2017 Daniel Carbone

	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.
*/

import (
	"fmt"
	"sync"
)

// Boss controls the life of the workers
type Boss struct {
	*sync.RWMutex

	workers map[string]*worker
	hr      chan *worker
}

// New creates a Boss
func NewBoss() *Boss {
	// initialize boss
	b := &Boss{
		RWMutex: &sync.RWMutex{},

		workers: make(map[string]*worker),
		hr:      make(chan *worker, 100),
	}

	// start up that hr team...
	go b.exitInterview()

	return b
}

// HasWorker lets you know if a worker already exists for a job
func (b *Boss) HasWorker(name string) bool {
	b.RLock()
	defer b.RUnlock()

	// do we have this person?
	if _, ok := b.workers[name]; ok {
		return true
	}

	return false
}

// NewWorker will attempt to create a new worker for a job. Returns error if you've already hired somebody.
func (b *Boss) NewWorker(name string, queueLength int) error {
	// see if we're already got somebody doin' it
	if b.HasWorker(name) {
		if debug {
			logger.Printf("Jobber: A worker for job \"%s\" already exists.\n", name)
		}
		return fmt.Errorf("A worker for job \"%s\" already exists.", name)
	}

	// 'lil input sanitizing
	if 0 > queueLength {
		// shout
		if debug {
			logger.Printf(
				"Jobber: Incoming new worker \"%s\" request specified invalid queue length of \"%d\","+
					" will set length to \"0\"\n",
				name,
				queueLength)
		}
		// make unbuffered
		queueLength = 0
	}

	// tell the world
	logger.Printf(
		"Jobber: Creating new worker for job with name \"%s\" and queue length of \"%d\"\n",
		name,
		queueLength)

	// lock boss down
	b.Lock()
	defer b.Unlock()

	// add worker
	b.workers[name] = newWorker(name, queueLength)

	// start up work routine
	go b.workers[name].doWork()

	// maybe say so?
	if debug {
		logger.Printf("Jobber: Go routine started for job \"%s\"\n", name)
	}

	return nil
}

// AddWork will push a new job to the end of a worker's queue
func (b *Boss) AddJob(workerName string, j Job) error {
	// see if we've already hired this worker
	if false == b.HasWorker(workerName) {
		if debug {
			logger.Printf("Jobber: No worker with \"%s\" found.\n", workerName)
		}
		return fmt.Errorf("No worker with name \"%s\" found", workerName)
	}

	// lock boss down
	b.RLock()
	defer b.RUnlock()

	// add to worker queue
	return b.workers[workerName].addJob(j)
}

// NewUnbufferedWorker will attempt to create a new worker with a queue length of 0
func (b *Boss) NewUnbufferedWorker(name string) error {
	return b.NewWorker(name, 0)
}

// StopWorker will tell a worker to finish up their queue then remove them
func (b *Boss) StopWorker(workerName string) error {
	if false == b.HasWorker(workerName) {
		if debug {
			logger.Printf("Jobber: No worker named \"%s\" found, cannot tell them to stop.", workerName)
		}
		return fmt.Errorf("No worker named \"%s\" found, cannot tell them to stop.", workerName)
	}

	b.RLock()
	defer b.RUnlock()

	err := b.workers[workerName].stop(b.hr)
	if nil != err {
		return err
	}

	return nil
}

// exitInterview processes workers coming in to hr
func (b *Boss) exitInterview() {
	for {
		select {
		case w := <-b.hr:
			logger.Printf("Jobber: Worker \"%s\" has completed all queued tasks.  They completed"+
				"\"%d\" jobs all told. Goodbye, \"%s\"...\n",
				w.name,
				w.completed,
				w.name)
			b.Lock()
			delete(b.workers, w.name)
			b.Unlock()
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"github.com/google/go-github/github"
)

// MirroredPR contains the upstream and downstream PR ids
type MirroredPR struct {
	DownstreamID int
	UpstreamID   int
}

// PRMirror contains various different variables
type PRMirror struct {
	GitHubClient  *github.Client
	Context       *context.Context
	Configuration *Config
	Database      *Database
	GitLock       *SpinLock
}

// GitHubEventMonitor passes in an instance of the PRMirror struct to all HTTP calls to the webhook listener
type GitHubEventMonitor struct {
	Mirrorer PRMirror
}

// HandleEvent handles github events and acts like an event handler
func (p PRMirror) HandleEvent(event *github.Event) {
	seenEvent, _ := p.Database.SeenEvent(event.GetID())
	if seenEvent {
		return
	}

	eventType := event.GetType()
	if eventType != "PullRequestEvent" {
		return
	}

	prEvent := github.PullRequestEvent{}
	err := json.Unmarshal(event.GetRawPayload(), &prEvent)
	if err != nil {
		panic(err)
	}

	p.HandlePREvent(&prEvent)
	p.Database.AddEvent(event.GetID())
}

func (p PRMirror) HandlePREvent(prEvent *github.PullRequestEvent) {
	repoName := prEvent.Repo.GetName()
	//repoOwner := prEvent.Repo.Owner.GetName()
	prEventURL := prEvent.PullRequest.GetURL()

	if repoName != p.Configuration.DownstreamRepo {
		log.Warningf("Ignoring PR Event: %s because %s != %s\n", prEventURL, repoName, p.Configuration.UpstreamRepo)
		return
	} //else if repoOwner != p.Configuration.DownstreamOwner {
	//log.Warningf("Ignoring PR Event: %s because %s != %s\n", prEventURL, repoOwner, p.Configuration.UpstreamOwner)
	//return
	//}

	log.Debugf("Handling PR Event: %s\n", prEventURL)

	prAction := prEvent.GetAction()
	if prAction == "closed" && prEvent.PullRequest.GetMerged() == true {
		prID, err := p.MirrorPR(prEvent.PullRequest)
		if err != nil {
			log.Errorf("Error while creating a new PR: %s\n", err.Error())
		} else {
			p.AddLabels(prID, []string{"Upstream PR Merged"})
			p.Database.StoreMirror(prID, prEvent.PullRequest.GetNumber())
		}
	}
}

// RunEventScraper runs the GitHub repo event API scraper
func (p PRMirror) RunEventScraper() {
	for {
		events, pollInterval, err := p.GetRepoEvents()
		if err == nil {
			for _, event := range events {
				p.HandleEvent(event)
			}
		}

		log.Debugf("Sleeping for %d as specified by GitHub\n", pollInterval)
		time.Sleep(time.Duration(pollInterval) * time.Second)
	}
}

// ServeHTTP handles HTTP requests to the webhook endpoint
func (s GitHubEventMonitor) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	payload, err := github.ValidatePayload(r, []byte(s.Mirrorer.Configuration.WebhookSecret))
	if err != nil {
		log.Errorf("Error validating the payload\n")
		return
	}
	event, err := github.ParseWebHook(github.WebHookType(r), payload)
	if err != nil {
		log.Errorf("Error parsing the payload\n")
	}

	switch event := event.(type) {
	case *github.PullRequestEvent:
		s.Mirrorer.HandlePREvent(event)
	}
}

// RunWebhookListener acts a webhook listener which GitHub will call with events
func (p PRMirror) RunWebhookListener() {
	server := GitHubEventMonitor{Mirrorer: p}
	err := http.ListenAndServe(fmt.Sprintf(":%d", p.Configuration.WebhookPort), server)
	log.Fatal(err)
}

// MirrorPR will mirror a PR from an upstream to the downstream
func (p PRMirror) MirrorPR(pr *github.PullRequest) (int, error) {
	p.GitLock.Lock()
	defer p.GitLock.Unlock()

	log.Infof("Mirroring PR [%d]: %s from %s\n", pr.GetNumber(), pr.GetTitle(), pr.User.GetLogin())

	cmd := exec.Command(fmt.Sprintf("%s%s", p.Configuration.RepoPath, p.Configuration.ToolPath), strconv.Itoa(pr.GetNumber()), pr.GetTitle())
	cmd.Dir = p.Configuration.RepoPath
	cmdoutput, err := cmd.CombinedOutput()
	if err != nil {
		panic(err)
	}

	logpath := fmt.Sprintf("./logs/upstream-merge-%d.log", pr.GetNumber())
	ioutil.WriteFile(logpath, cmdoutput, 0600)
	log.Debugf("Wrote log to %s\n", logpath)

	base := "master"
	head := fmt.Sprintf("upstream-merge-%d", pr.GetNumber())
	maintainerCanModify := true // We are the owner of the PR so we can specify this as true
	title := fmt.Sprintf("[MIRROR] %s", pr.GetTitle())
	body := fmt.Sprintf("Original PR: %s\n--------------------\n%s", pr.GetHTMLURL(), strings.Replace(pr.GetBody(), "@", "@ ", -1))

	newPR := github.NewPullRequest{}
	newPR.Title = &title
	newPR.Body = &body
	newPR.Base = &base
	newPR.Head = &head
	newPR.MaintainerCanModify = &maintainerCanModify

	pr, _, err = p.GitHubClient.PullRequests.Create(*p.Context, p.Configuration.DownstreamOwner, p.Configuration.DownstreamRepo, &newPR)
	if err != nil {
		return 0, err
	}

	if strings.Contains(string(cmdoutput), "Rejected hunk") {
		p.AddLabels(pr.GetNumber(), []string{"Auto Merge Rejections"})
	}

	return pr.GetNumber(), nil
}
<commit_msg>fuck right off<commit_after>package main

import (
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"github.com/google/go-github/github"
)

// MirroredPR contains the upstream and downstream PR ids
type MirroredPR struct {
	DownstreamID int
	UpstreamID   int
}

// PRMirror contains various different variables
type PRMirror struct {
	GitHubClient  *github.Client
	Context       *context.Context
	Configuration *Config
	Database      *Database
	GitLock       *SpinLock
}

// GitHubEventMonitor passes in an instance of the PRMirror struct to all HTTP calls to the webhook listener
type GitHubEventMonitor struct {
	Mirrorer PRMirror
}

// HandleEvent handles github events and acts like an event handler
func (p PRMirror) HandleEvent(event *github.Event) {
	seenEvent, _ := p.Database.SeenEvent(event.GetID())
	if seenEvent {
		return
	}

	eventType := event.GetType()
	if eventType != "PullRequestEvent" {
		return
	}

	prEvent := github.PullRequestEvent{}
	err := json.Unmarshal(event.GetRawPayload(), &prEvent)
	if err != nil {
		panic(err)
	}

	p.HandlePREvent(&prEvent)
	p.Database.AddEvent(event.GetID())
}

func (p PRMirror) HandlePREvent(prEvent *github.PullRequestEvent) {
	//repoName := prEvent.Repo.GetName()
	//repoOwner := prEvent.Repo.Owner.GetName()
	prEventURL := prEvent.PullRequest.GetURL()

	//if p.Configuration.UseWebhook repoName != p.Configuration.DownstreamRepo {
	//	log.Warningf("Ignoring PR Event: %s because %s != %s\n", prEventURL, repoName, p.Configuration.UpstreamRepo)
	//	return
	//} //else if repoOwner != p.Configuration.DownstreamOwner {
	//log.Warningf("Ignoring PR Event: %s because %s != %s\n", prEventURL, repoOwner, p.Configuration.UpstreamOwner)
	//return
	//}

	log.Debugf("Handling PR Event: %s\n", prEventURL)

	prAction := prEvent.GetAction()
	if prAction == "closed" && prEvent.PullRequest.GetMerged() == true {
		prID, err := p.MirrorPR(prEvent.PullRequest)
		if err != nil {
			log.Errorf("Error while creating a new PR: %s\n", err.Error())
		} else {
			p.AddLabels(prID, []string{"Upstream PR Merged"})
			p.Database.StoreMirror(prID, prEvent.PullRequest.GetNumber())
		}
	}
}

// RunEventScraper runs the GitHub repo event API scraper
func (p PRMirror) RunEventScraper() {
	for {
		events, pollInterval, err := p.GetRepoEvents()
		if err == nil {
			for _, event := range events {
				p.HandleEvent(event)
			}
		}

		log.Debugf("Sleeping for %d as specified by GitHub\n", pollInterval)
		time.Sleep(time.Duration(pollInterval) * time.Second)
	}
}

// ServeHTTP handles HTTP requests to the webhook endpoint
func (s GitHubEventMonitor) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	payload, err := github.ValidatePayload(r, []byte(s.Mirrorer.Configuration.WebhookSecret))
	if err != nil {
		log.Errorf("Error validating the payload\n")
		return
	}
	event, err := github.ParseWebHook(github.WebHookType(r), payload)
	if err != nil {
		log.Errorf("Error parsing the payload\n")
	}

	switch event := event.(type) {
	case *github.PullRequestEvent:
		s.Mirrorer.HandlePREvent(event)
	}
}

// RunWebhookListener acts a webhook listener which GitHub will call with events
func (p PRMirror) RunWebhookListener() {
	server := GitHubEventMonitor{Mirrorer: p}
	err := http.ListenAndServe(fmt.Sprintf(":%d", p.Configuration.WebhookPort), server)
	log.Fatal(err)
}

// MirrorPR will mirror a PR from an upstream to the downstream
func (p PRMirror) MirrorPR(pr *github.PullRequest) (int, error) {
	p.GitLock.Lock()
	defer p.GitLock.Unlock()

	log.Infof("Mirroring PR [%d]: %s from %s\n", pr.GetNumber(), pr.GetTitle(), pr.User.GetLogin())

	cmd := exec.Command(fmt.Sprintf("%s%s", p.Configuration.RepoPath, p.Configuration.ToolPath), strconv.Itoa(pr.GetNumber()), pr.GetTitle())
	cmd.Dir = p.Configuration.RepoPath
	cmdoutput, err := cmd.CombinedOutput()
	if err != nil {
		panic(err)
	}

	logpath := fmt.Sprintf("./logs/upstream-merge-%d.log", pr.GetNumber())
	ioutil.WriteFile(logpath, cmdoutput, 0600)
	log.Debugf("Wrote log to %s\n", logpath)

	base := "master"
	head := fmt.Sprintf("upstream-merge-%d", pr.GetNumber())
	maintainerCanModify := true // We are the owner of the PR so we can specify this as true
	title := fmt.Sprintf("[MIRROR] %s", pr.GetTitle())
	body := fmt.Sprintf("Original PR: %s\n--------------------\n%s", pr.GetHTMLURL(), strings.Replace(pr.GetBody(), "@", "@ ", -1))

	newPR := github.NewPullRequest{}
	newPR.Title = &title
	newPR.Body = &body
	newPR.Base = &base
	newPR.Head = &head
	newPR.MaintainerCanModify = &maintainerCanModify

	pr, _, err = p.GitHubClient.PullRequests.Create(*p.Context, p.Configuration.DownstreamOwner, p.Configuration.DownstreamRepo, &newPR)
	if err != nil {
		return 0, err
	}

	if strings.Contains(string(cmdoutput), "Rejected hunk") {
		p.AddLabels(pr.GetNumber(), []string{"Auto Merge Rejections"})
	}

	return pr.GetNumber(), nil
}
<|endoftext|>