<commit_before>package weed_server

import (
	"bytes"
	"crypto/md5"
	"hash"
	"io"
	"io/ioutil"
	"net/http"
	"sort"
	"strings"
	"sync"
	"time"

	"github.com/chrislusf/seaweedfs/weed/filer"
	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/operation"
	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
	"github.com/chrislusf/seaweedfs/weed/security"
	"github.com/chrislusf/seaweedfs/weed/stats"
	"github.com/chrislusf/seaweedfs/weed/util"
)

var bufPool = sync.Pool{
	New: func() interface{} {
		return new(bytes.Buffer)
	},
}

func (fs *FilerServer) uploadReaderToChunks(w http.ResponseWriter, r *http.Request, reader io.Reader, chunkSize int32, fileName, contentType string, contentLength int64, so *operation.StorageOption) ([]*filer_pb.FileChunk, hash.Hash, int64, error, []byte) {
	var fileChunks []*filer_pb.FileChunk

	md5Hash := md5.New()
	var partReader = ioutil.NopCloser(io.TeeReader(reader, md5Hash))

	chunkOffset := int64(0)
	var smallContent []byte
	var uploadErr error

	var wg sync.WaitGroup
	for {

		// need to throttle this for large files
		bytesBuffer := bufPool.Get().(*bytes.Buffer)
		defer bufPool.Put(bytesBuffer)

		limitedReader := io.LimitReader(partReader, int64(chunkSize))

		bytesBuffer.Reset()

		dataSize, err := bytesBuffer.ReadFrom(limitedReader)

		// data, err := ioutil.ReadAll(limitedReader)
		if err != nil || dataSize == 0 {
			return nil, md5Hash, 0, err, nil
		}
		if chunkOffset == 0 && !isAppend(r) {
			if dataSize < fs.option.SaveToFilerLimit || strings.HasPrefix(r.URL.Path, filer.DirectoryEtcRoot) && dataSize < 4*1024 {
				chunkOffset += dataSize
				smallContent = make([]byte, dataSize)
				bytesBuffer.Read(smallContent)
				break
			}
		}

		wg.Add(1)
		go func(offset int64) {
			defer wg.Done()

			chunk, toChunkErr := fs.dataToChunk(fileName, contentType, bytesBuffer.Bytes(), offset, so)
			if toChunkErr != nil {
				uploadErr = toChunkErr
			}
			if chunk != nil {
				fileChunks = append(fileChunks, chunk)
				glog.V(4).Infof("uploaded %s chunk %d to %s [%d,%d)", fileName, len(fileChunks), chunk.FileId, offset, offset+int64(chunk.Size))
			}
		}(chunkOffset)

		// reset variables for the next chunk
		chunkOffset = chunkOffset + dataSize

		// if last chunk was not at full chunk size, but already exhausted the reader
		if dataSize < int64(chunkSize) {
			break
		}
	}

	wg.Wait()

	if uploadErr != nil {
		return nil, md5Hash, 0, uploadErr, nil
	}

	sort.Slice(fileChunks, func(i, j int) bool {
		return fileChunks[i].Offset < fileChunks[j].Offset
	})

	return fileChunks, md5Hash, chunkOffset, nil, smallContent
}

func (fs *FilerServer) doUpload(urlLocation string, limitedReader io.Reader, fileName string, contentType string, pairMap map[string]string, auth security.EncodedJwt) (*operation.UploadResult, error, []byte) {

	stats.FilerRequestCounter.WithLabelValues("chunkUpload").Inc()
	start := time.Now()
	defer func() {
		stats.FilerRequestHistogram.WithLabelValues("chunkUpload").Observe(time.Since(start).Seconds())
	}()

	uploadResult, err, data := operation.Upload(urlLocation, fileName, fs.option.Cipher, limitedReader, false, contentType, pairMap, auth)
	if uploadResult != nil && uploadResult.RetryCount > 0 {
		stats.FilerRequestCounter.WithLabelValues("chunkUploadRetry").Add(float64(uploadResult.RetryCount))
	}
	return uploadResult, err, data
}

func (fs *FilerServer) dataToChunk(fileName, contentType string, data []byte, chunkOffset int64, so *operation.StorageOption) (*filer_pb.FileChunk, error) {
	dataReader := util.NewBytesReader(data)

	// retry to assign a different file id
	var fileId, urlLocation string
	var auth security.EncodedJwt
	var uploadErr error
	var uploadResult *operation.UploadResult
	for i := 0; i < 3; i++ {
		// assign one file id for one chunk
		fileId, urlLocation, auth, uploadErr = fs.assignNewFileInfo(so)
		if uploadErr != nil {
			glog.V(4).Infof("retry later due to assign error: %v", uploadErr)
			time.Sleep(time.Duration(i+1) * 251 * time.Millisecond)
			continue
		}

		// upload the chunk to the volume server
		uploadResult, uploadErr, _ = fs.doUpload(urlLocation, dataReader, fileName, contentType, nil, auth)
		if uploadErr != nil {
			glog.V(4).Infof("retry later due to upload error: %v", uploadErr)
			time.Sleep(time.Duration(i+1) * 251 * time.Millisecond)
			continue
		}
		break
	}
	if uploadErr != nil {
		glog.Errorf("upload error: %v", uploadErr)
		return nil, uploadErr
	}

	// if last chunk exhausted the reader exactly at the border
	if uploadResult.Size == 0 {
		return nil, nil
	}

	return uploadResult.ToPbFileChunk(fileId, chunkOffset), nil
}
<commit_msg>limits concurrent uploads for one file<commit_after>package weed_server

import (
	"bytes"
	"crypto/md5"
	"hash"
	"io"
	"io/ioutil"
	"net/http"
	"sort"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"github.com/chrislusf/seaweedfs/weed/filer"
	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/operation"
	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
	"github.com/chrislusf/seaweedfs/weed/security"
	"github.com/chrislusf/seaweedfs/weed/stats"
	"github.com/chrislusf/seaweedfs/weed/util"
)

var bufPool = sync.Pool{
	New: func() interface{} {
		return new(bytes.Buffer)
	},
}

func (fs *FilerServer) uploadReaderToChunks(w http.ResponseWriter, r *http.Request, reader io.Reader, chunkSize int32, fileName, contentType string, contentLength int64, so *operation.StorageOption) ([]*filer_pb.FileChunk, hash.Hash, int64, error, []byte) {
	var fileChunks []*filer_pb.FileChunk

	md5Hash := md5.New()
	var partReader = ioutil.NopCloser(io.TeeReader(reader, md5Hash))

	chunkOffset := int64(0)
	var smallContent []byte
	var uploadErr error

	var wg sync.WaitGroup
	var bytesBufferCounter int64
	bytesBufferLimitCond := sync.NewCond(new(sync.Mutex))
	for {

		// need to throttle used byte buffer
		bytesBufferLimitCond.L.Lock()
		for atomic.LoadInt64(&bytesBufferCounter) >= 4 {
			glog.V(4).Infof("waiting for byte buffer %d", bytesBufferCounter)
			bytesBufferLimitCond.Wait()
		}
		atomic.AddInt64(&bytesBufferCounter, 1)
		bytesBufferLimitCond.L.Unlock()

		bytesBuffer := bufPool.Get().(*bytes.Buffer)
		glog.V(4).Infof("received byte buffer %d", bytesBufferCounter)

		limitedReader := io.LimitReader(partReader, int64(chunkSize))

		bytesBuffer.Reset()

		dataSize, err := bytesBuffer.ReadFrom(limitedReader)

		// data, err := ioutil.ReadAll(limitedReader)
		if err != nil || dataSize == 0 {
			bufPool.Put(bytesBuffer)
			atomic.AddInt64(&bytesBufferCounter, -1)
			bytesBufferLimitCond.Signal()
			return nil, md5Hash, 0, err, nil
		}
		if chunkOffset == 0 && !isAppend(r) {
			if dataSize < fs.option.SaveToFilerLimit || strings.HasPrefix(r.URL.Path, filer.DirectoryEtcRoot) && dataSize < 4*1024 {
				chunkOffset += dataSize
				smallContent = make([]byte, dataSize)
				bytesBuffer.Read(smallContent)
				bufPool.Put(bytesBuffer)
				atomic.AddInt64(&bytesBufferCounter, -1)
				bytesBufferLimitCond.Signal()
				break
			}
		}

		wg.Add(1)
		go func(offset int64) {
			defer func() {
				bufPool.Put(bytesBuffer)
				atomic.AddInt64(&bytesBufferCounter, -1)
				bytesBufferLimitCond.Signal()
				wg.Done()
			}()

			chunk, toChunkErr := fs.dataToChunk(fileName, contentType, bytesBuffer.Bytes(), offset, so)
			if toChunkErr != nil {
				uploadErr = toChunkErr
			}
			if chunk != nil {
				fileChunks = append(fileChunks, chunk)
				glog.V(4).Infof("uploaded %s chunk %d to %s [%d,%d)", fileName, len(fileChunks), chunk.FileId, offset, offset+int64(chunk.Size))
			}
		}(chunkOffset)

		// reset variables for the next chunk
		chunkOffset = chunkOffset + dataSize

		// if last chunk was not at full chunk size, but already exhausted the reader
		if dataSize < int64(chunkSize) {
			break
		}
	}

	wg.Wait()

	if uploadErr != nil {
		return nil, md5Hash, 0, uploadErr, nil
	}

	sort.Slice(fileChunks, func(i, j int) bool {
		return fileChunks[i].Offset < fileChunks[j].Offset
	})

	return fileChunks, md5Hash, chunkOffset, nil, smallContent
}

func (fs *FilerServer) doUpload(urlLocation string, limitedReader io.Reader, fileName string, contentType string, pairMap map[string]string, auth security.EncodedJwt) (*operation.UploadResult, error, []byte) {

	stats.FilerRequestCounter.WithLabelValues("chunkUpload").Inc()
	start := time.Now()
	defer func() {
		stats.FilerRequestHistogram.WithLabelValues("chunkUpload").Observe(time.Since(start).Seconds())
	}()

	uploadResult, err, data := operation.Upload(urlLocation, fileName, fs.option.Cipher, limitedReader, false, contentType, pairMap, auth)
	if uploadResult != nil && uploadResult.RetryCount > 0 {
		stats.FilerRequestCounter.WithLabelValues("chunkUploadRetry").Add(float64(uploadResult.RetryCount))
	}
	return uploadResult, err, data
}

func (fs *FilerServer) dataToChunk(fileName, contentType string, data []byte, chunkOffset int64, so *operation.StorageOption) (*filer_pb.FileChunk, error) {
	dataReader := util.NewBytesReader(data)

	// retry to assign a different file id
	var fileId, urlLocation string
	var auth security.EncodedJwt
	var uploadErr error
	var uploadResult *operation.UploadResult
	for i := 0; i < 3; i++ {
		// assign one file id for one chunk
		fileId, urlLocation, auth, uploadErr = fs.assignNewFileInfo(so)
		if uploadErr != nil {
			glog.V(4).Infof("retry later due to assign error: %v", uploadErr)
			time.Sleep(time.Duration(i+1) * 251 * time.Millisecond)
			continue
		}

		// upload the chunk to the volume server
		uploadResult, uploadErr, _ = fs.doUpload(urlLocation, dataReader, fileName, contentType, nil, auth)
		if uploadErr != nil {
			glog.V(4).Infof("retry later due to upload error: %v", uploadErr)
			time.Sleep(time.Duration(i+1) * 251 * time.Millisecond)
			continue
		}
		break
	}
	if uploadErr != nil {
		glog.Errorf("upload error: %v", uploadErr)
		return nil, uploadErr
	}

	// if last chunk exhausted the reader exactly at the border
	if uploadResult.Size == 0 {
		return nil, nil
	}

	return uploadResult.ToPbFileChunk(fileId, chunkOffset), nil
}
<|endoftext|>


<commit_before>package s3iface

import (
	"fmt"
	"testing"

	goamzs3 "launchpad.net/goamz/s3"
)

func testBucket(b Bucket, errs chan<- error) {
	var err error
	var testname string
	defer func() {
		if err != nil {
			errs <- fmt.Errorf("Failed bucket test %q: %v", testname, err)
		}
	}()
	testname = "Put test.txt"
	err = b.Put("test.txt", []byte("Hello!"), "text/plain", goamzs3.Private)
	if err != nil {
		return
	}
	testname = "Get test.txt"
	data, err := b.Get("test.txt")
	if err != nil {
		return
	}
	if string(data) != "Hello!" {
		err = fmt.Errorf("Got wrong test data back: %q", data)
		return
	}
	testname = "Del test.txt"
	err = b.Del("test.txt")
	return
}

// Delete the bucket completely (think rm -rf ...)
func purgeBucket(b Bucket, errs chan<- error) {
	defer func() {
		errs <- b.DelBucket()
	}()
	ls, err := b.List("", "", "", 0)
	if err != nil {
		errs <- fmt.Errorf("Failed to list bucket for cleanup: %v", err)
		return
	}
	for _, key := range ls.Contents {
		errs <- b.Del(key.Key)
	}
	return
}

func runS3tests(s3 S3, errs chan<- error) {
	b := s3.Bucket("test")
	err := b.PutBucket(goamzs3.Private)
	if err != nil {
		errs <- fmt.Errorf("Failed to create test bucket: %v", err)
	}
	// Try to clean up, do not care if it fails
	defer purgeBucket(b, errs)
	testBucket(b, errs)
	return
}

func testS3backend(backend S3, t *testing.T) {
	errs := make(chan error)
	go func() {
		runS3tests(backend, errs)
		close(errs)
	}()
	for err := range errs {
		if err != nil {
			t.Error("S3 backend:", err)
		}
	}
}
<commit_msg>Test backends for keynames with / in them<commit_after>package s3iface

import (
	"fmt"
	"testing"

	goamzs3 "launchpad.net/goamz/s3"
)

func testBucketSimple(b Bucket, errs chan<- error) {
	var err error
	var testname string
	defer func() {
		if err != nil {
			errs <- fmt.Errorf("Failed bucket test (simple) %q: %v", testname, err)
		}
	}()
	testname = "Put test.txt"
	err = b.Put("test.txt", []byte("Hello!"), "text/plain", goamzs3.Private)
	if err != nil {
		return
	}
	testname = "Get test.txt"
	data, err := b.Get("test.txt")
	if err != nil {
		return
	}
	if string(data) != "Hello!" {
		err = fmt.Errorf("Got wrong test data back: %q", data)
		return
	}
	testname = "Del test.txt"
	err = b.Del("test.txt")
	return
}

func testBucketNested(b Bucket, errs chan<- error) {
	var err error
	var testname string
	defer func() {
		if err != nil {
			errs <- fmt.Errorf("Failed bucket test (nested) %q: %v", testname, err)
		}
	}()
	testname = "Put a/b/test.txt"
	err = b.Put("a/b/test.txt", []byte("Hello!"), "text/plain", goamzs3.Private)
	if err != nil {
		return
	}
	testname = "Get a/b/test.txt"
	data, err := b.Get("a/b/test.txt")
	if err != nil {
		return
	}
	if string(data) != "Hello!" {
		err = fmt.Errorf("Got wrong test data back: %q", data)
		return
	}
	testname = "Del a/b/test.txt"
	err = b.Del("a/b/test.txt")
	return
}

// Delete the bucket completely (think rm -rf ...)
func purgeBucket(b Bucket, errs chan<- error) {
	defer func() {
		errs <- b.DelBucket()
	}()
	ls, err := b.List("", "", "", 0)
	if err != nil {
		errs <- fmt.Errorf("Failed to list bucket for cleanup: %v", err)
		return
	}
	for _, key := range ls.Contents {
		errs <- b.Del(key.Key)
	}
	return
}

func runS3tests(s3 S3, errs chan<- error) {
	b := s3.Bucket("test")
	err := b.PutBucket(goamzs3.Private)
	if err != nil {
		errs <- fmt.Errorf("Failed to create test bucket: %v", err)
	}
	// Try to clean up, do not care if it fails
	defer purgeBucket(b, errs)
	testBucketSimple(b, errs)
	testBucketNested(b, errs)
	return
}

func testS3backend(backend S3, t *testing.T) {
	errs := make(chan error)
	go func() {
		runS3tests(backend, errs)
		close(errs)
	}()
	for err := range errs {
		if err != nil {
			t.Error("S3 backend:", err)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 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 main

import (
	"bytes"
	cmddwarf "cmd/internal/dwarf"
	"cmd/internal/objfile"
	"debug/dwarf"
	"internal/testenv"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"runtime"
	"strings"
	"testing"
)

func testDWARF(t *testing.T, buildmode string, expectDWARF bool, env ...string) {
	testenv.MustHaveCGO(t)
	testenv.MustHaveGoBuild(t)

	if runtime.GOOS == "plan9" {
		t.Skip("skipping on plan9; no DWARF symbol table in executables")
	}

	out, err := exec.Command(testenv.GoToolPath(t), "list", "-f", "{{.Stale}}", "cmd/link").CombinedOutput()
	if err != nil {
		t.Fatalf("go list: %v\n%s", err, out)
	}
	if string(out) != "false\n" {
		if os.Getenv("GOROOT_FINAL_OLD") != "" {
			t.Skip("cmd/link is stale, but $GOROOT_FINAL_OLD is set")
		}
		t.Fatalf("cmd/link is stale - run go install cmd/link")
	}

	for _, prog := range []string{"testprog", "testprogcgo"} {
		prog := prog
		expectDWARF := expectDWARF
		if runtime.GOOS == "aix" && prog == "testprogcgo" {
			extld := os.Getenv("CC")
			if extld == "" {
				extld = "gcc"
			}
			expectDWARF, err = cmddwarf.IsDWARFEnabledOnAIXLd(extld)
			if err != nil {
				t.Fatal(err)
			}

		}

		t.Run(prog, func(t *testing.T) {
			t.Parallel()

			tmpDir, err := ioutil.TempDir("", "go-link-TestDWARF")
			if err != nil {
				t.Fatal(err)
			}
			defer os.RemoveAll(tmpDir)

			exe := filepath.Join(tmpDir, prog+".exe")
			dir := "../../runtime/testdata/" + prog
			cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", exe)
			if buildmode != "" {
				cmd.Args = append(cmd.Args, "-buildmode", buildmode)
			}
			cmd.Args = append(cmd.Args, dir)
			if env != nil {
				cmd.Env = append(os.Environ(), env...)
			}
			out, err := cmd.CombinedOutput()
			if err != nil {
				t.Fatalf("go build -o %v %v: %v\n%s", exe, dir, err, out)
			}

			if buildmode == "c-archive" {
				// Extract the archive and use the go.o object within.
				cmd := exec.Command("ar", "-x", exe)
				cmd.Dir = tmpDir
				if out, err := cmd.CombinedOutput(); err != nil {
					t.Fatalf("ar -x %s: %v\n%s", exe, err, out)
				}
				exe = filepath.Join(tmpDir, "go.o")
			}

			if runtime.GOOS == "darwin" {
				if _, err = exec.LookPath("symbols"); err == nil {
					// Ensure Apple's tooling can parse our object for symbols.
					out, err = exec.Command("symbols", exe).CombinedOutput()
					if err != nil {
						t.Fatalf("symbols %v: %v: %s", filepath.Base(exe), err, out)
					} else {
						if bytes.HasPrefix(out, []byte("Unable to find file")) {
							// This failure will cause the App Store to reject our binaries.
							t.Fatalf("symbols %v: failed to parse file", filepath.Base(exe))
						} else if bytes.Contains(out, []byte(", Empty]")) {
							t.Fatalf("symbols %v: parsed as empty", filepath.Base(exe))
						}
					}
				}
			}

			f, err := objfile.Open(exe)
			if err != nil {
				t.Fatal(err)
			}
			defer f.Close()

			syms, err := f.Symbols()
			if err != nil {
				t.Fatal(err)
			}

			var addr uint64
			for _, sym := range syms {
				if sym.Name == "main.main" {
					addr = sym.Addr
					break
				}
			}
			if addr == 0 {
				t.Fatal("cannot find main.main in symbols")
			}

			d, err := f.DWARF()
			if err != nil {
				if expectDWARF {
					t.Fatal(err)
				}
				return
			} else {
				if !expectDWARF {
					t.Fatal("unexpected DWARF section")
				}
			}

			// Until there is a fix for issue 35512, don't try to use
			// SeekPC or look at the line table on Windows under
			// c-archive build mode.
			if buildmode == "c-archive" && runtime.GOOS == "windows" {
				t.Skip("avoiding SeekPC until 35512 fixed")
			}

			// TODO: We'd like to use filepath.Join here.
			// Also related: golang.org/issue/19784.
			wantFile := path.Join(prog, "main.go")
			wantLine := 24
			r := d.Reader()
			entry, err := r.SeekPC(addr)
			if err != nil {
				t.Fatal(err)
			}
			lr, err := d.LineReader(entry)
			if err != nil {
				t.Fatal(err)
			}
			var line dwarf.LineEntry
			if err := lr.SeekPC(addr, &line); err == dwarf.ErrUnknownPC {
				t.Fatalf("did not find file:line for %#x (main.main)", addr)
			} else if err != nil {
				t.Fatal(err)
			}
			if !strings.HasSuffix(line.File.Name, wantFile) || line.Line != wantLine {
				t.Errorf("%#x is %s:%d, want %s:%d", addr, line.File.Name, line.Line, filepath.Join("...", wantFile), wantLine)
			}
		})
	}
}

func TestDWARF(t *testing.T) {
	testDWARF(t, "", true)
	if !testing.Short() {
		t.Run("c-archive", func(t *testing.T) {
			testDWARF(t, "c-archive", true)
		})
	}
}

func TestDWARFiOS(t *testing.T) {
	// Normally we run TestDWARF on native platform. But on iOS we don't have
	// go build, so we do this test with a cross build.
	// Only run this on darwin/amd64, where we can cross build for iOS.
	if testing.Short() {
		t.Skip("skipping in short mode")
	}
	if runtime.GOARCH != "amd64" || runtime.GOOS != "darwin" {
		t.Skip("skipping on non-darwin/amd64 platform")
	}
	if err := exec.Command("xcrun", "--help").Run(); err != nil {
		t.Skipf("error running xcrun, required for iOS cross build: %v", err)
	}
	cc := "CC=" + runtime.GOROOT() + "/misc/ios/clangwrap.sh"
	// iOS doesn't allow unmapped segments, so iOS executables don't have DWARF.
	testDWARF(t, "", false, cc, "CGO_ENABLED=1", "GOOS=darwin", "GOARCH=arm", "GOARM=7")
	testDWARF(t, "", false, cc, "CGO_ENABLED=1", "GOOS=darwin", "GOARCH=arm64")
	// However, c-archive iOS objects have embedded DWARF.
	testDWARF(t, "c-archive", true, cc, "CGO_ENABLED=1", "GOOS=darwin", "GOARCH=arm", "GOARM=7")
	testDWARF(t, "c-archive", true, cc, "CGO_ENABLED=1", "GOOS=darwin", "GOARCH=arm64")
}
<commit_msg>cmd/link: don't run TestDWARF in c-archive mode on Windows<commit_after>// Copyright 2017 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 main

import (
	"bytes"
	cmddwarf "cmd/internal/dwarf"
	"cmd/internal/objfile"
	"debug/dwarf"
	"internal/testenv"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"runtime"
	"strings"
	"testing"
)

func testDWARF(t *testing.T, buildmode string, expectDWARF bool, env ...string) {
	testenv.MustHaveCGO(t)
	testenv.MustHaveGoBuild(t)

	if runtime.GOOS == "plan9" {
		t.Skip("skipping on plan9; no DWARF symbol table in executables")
	}

	out, err := exec.Command(testenv.GoToolPath(t), "list", "-f", "{{.Stale}}", "cmd/link").CombinedOutput()
	if err != nil {
		t.Fatalf("go list: %v\n%s", err, out)
	}
	if string(out) != "false\n" {
		if os.Getenv("GOROOT_FINAL_OLD") != "" {
			t.Skip("cmd/link is stale, but $GOROOT_FINAL_OLD is set")
		}
		t.Fatalf("cmd/link is stale - run go install cmd/link")
	}

	for _, prog := range []string{"testprog", "testprogcgo"} {
		prog := prog
		expectDWARF := expectDWARF
		if runtime.GOOS == "aix" && prog == "testprogcgo" {
			extld := os.Getenv("CC")
			if extld == "" {
				extld = "gcc"
			}
			expectDWARF, err = cmddwarf.IsDWARFEnabledOnAIXLd(extld)
			if err != nil {
				t.Fatal(err)
			}

		}

		t.Run(prog, func(t *testing.T) {
			t.Parallel()

			tmpDir, err := ioutil.TempDir("", "go-link-TestDWARF")
			if err != nil {
				t.Fatal(err)
			}
			defer os.RemoveAll(tmpDir)

			exe := filepath.Join(tmpDir, prog+".exe")
			dir := "../../runtime/testdata/" + prog
			cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", exe)
			if buildmode != "" {
				cmd.Args = append(cmd.Args, "-buildmode", buildmode)
			}
			cmd.Args = append(cmd.Args, dir)
			if env != nil {
				cmd.Env = append(os.Environ(), env...)
			}
			out, err := cmd.CombinedOutput()
			if err != nil {
				t.Fatalf("go build -o %v %v: %v\n%s", exe, dir, err, out)
			}

			if buildmode == "c-archive" {
				// Extract the archive and use the go.o object within.
				cmd := exec.Command("ar", "-x", exe)
				cmd.Dir = tmpDir
				if out, err := cmd.CombinedOutput(); err != nil {
					t.Fatalf("ar -x %s: %v\n%s", exe, err, out)
				}
				exe = filepath.Join(tmpDir, "go.o")
			}

			if runtime.GOOS == "darwin" {
				if _, err = exec.LookPath("symbols"); err == nil {
					// Ensure Apple's tooling can parse our object for symbols.
					out, err = exec.Command("symbols", exe).CombinedOutput()
					if err != nil {
						t.Fatalf("symbols %v: %v: %s", filepath.Base(exe), err, out)
					} else {
						if bytes.HasPrefix(out, []byte("Unable to find file")) {
							// This failure will cause the App Store to reject our binaries.
							t.Fatalf("symbols %v: failed to parse file", filepath.Base(exe))
						} else if bytes.Contains(out, []byte(", Empty]")) {
							t.Fatalf("symbols %v: parsed as empty", filepath.Base(exe))
						}
					}
				}
			}

			f, err := objfile.Open(exe)
			if err != nil {
				t.Fatal(err)
			}
			defer f.Close()

			syms, err := f.Symbols()
			if err != nil {
				t.Fatal(err)
			}

			var addr uint64
			for _, sym := range syms {
				if sym.Name == "main.main" {
					addr = sym.Addr
					break
				}
			}
			if addr == 0 {
				t.Fatal("cannot find main.main in symbols")
			}

			d, err := f.DWARF()
			if err != nil {
				if expectDWARF {
					t.Fatal(err)
				}
				return
			} else {
				if !expectDWARF {
					t.Fatal("unexpected DWARF section")
				}
			}

			// TODO: We'd like to use filepath.Join here.
			// Also related: golang.org/issue/19784.
			wantFile := path.Join(prog, "main.go")
			wantLine := 24
			r := d.Reader()
			entry, err := r.SeekPC(addr)
			if err != nil {
				t.Fatal(err)
			}
			lr, err := d.LineReader(entry)
			if err != nil {
				t.Fatal(err)
			}
			var line dwarf.LineEntry
			if err := lr.SeekPC(addr, &line); err == dwarf.ErrUnknownPC {
				t.Fatalf("did not find file:line for %#x (main.main)", addr)
			} else if err != nil {
				t.Fatal(err)
			}
			if !strings.HasSuffix(line.File.Name, wantFile) || line.Line != wantLine {
				t.Errorf("%#x is %s:%d, want %s:%d", addr, line.File.Name, line.Line, filepath.Join("...", wantFile), wantLine)
			}
		})
	}
}

func TestDWARF(t *testing.T) {
	testDWARF(t, "", true)
	if !testing.Short() {
		if runtime.GOOS == "windows" {
			t.Skip("skipping Windows/c-archive; see Issue 35512 for more.")
		}
		t.Run("c-archive", func(t *testing.T) {
			testDWARF(t, "c-archive", true)
		})
	}
}

func TestDWARFiOS(t *testing.T) {
	// Normally we run TestDWARF on native platform. But on iOS we don't have
	// go build, so we do this test with a cross build.
	// Only run this on darwin/amd64, where we can cross build for iOS.
	if testing.Short() {
		t.Skip("skipping in short mode")
	}
	if runtime.GOARCH != "amd64" || runtime.GOOS != "darwin" {
		t.Skip("skipping on non-darwin/amd64 platform")
	}
	if err := exec.Command("xcrun", "--help").Run(); err != nil {
		t.Skipf("error running xcrun, required for iOS cross build: %v", err)
	}
	cc := "CC=" + runtime.GOROOT() + "/misc/ios/clangwrap.sh"
	// iOS doesn't allow unmapped segments, so iOS executables don't have DWARF.
	testDWARF(t, "", false, cc, "CGO_ENABLED=1", "GOOS=darwin", "GOARCH=arm", "GOARM=7")
	testDWARF(t, "", false, cc, "CGO_ENABLED=1", "GOOS=darwin", "GOARCH=arm64")
	// However, c-archive iOS objects have embedded DWARF.
	testDWARF(t, "c-archive", true, cc, "CGO_ENABLED=1", "GOOS=darwin", "GOARCH=arm", "GOARM=7")
	testDWARF(t, "c-archive", true, cc, "CGO_ENABLED=1", "GOOS=darwin", "GOARCH=arm64")
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"github.com/ops-class/test161"
	"os"
	"sort"
	"strings"
)

// 'test161 run' flags
var runCommandVars struct {
	dryRun     bool
	explain    bool
	sequential bool
	nodeps     bool
	verbose    string
	isTag      bool
	tests      []string
}

func __printRunError(err error) {
	fmt.Fprintf(os.Stderr, "Error: %v\n", err)
}

func printRunError(err error) {
	__printRunError(err)
}

func printRunErrors(errs []error) {
	if len(errs) > 0 {
		for _, e := range errs {
			__printRunError(e)
		}
	}
}

func doRun() int {
	if err := getRunArgs(); err != nil {
		printRunError(err)
		return 1
	}

	exitcode, errs := runTests()
	if len(errs) > 0 {
		printRunErrors(errs)
	}

	return exitcode
}

// Verbose settings
const (
	VERBOSE_LOUD    = "loud"
	VERBOSE_QUIET   = "quiet"
	VERBOSE_WHISPER = "whisper"
)

func getRunArgs() error {

	runFlags := flag.NewFlagSet("test161 run", flag.ExitOnError)
	runFlags.Usage = usage

	runFlags.BoolVar(&runCommandVars.dryRun, "dry-run", false, "")
	runFlags.BoolVar(&runCommandVars.dryRun, "d", false, "")
	runFlags.BoolVar(&runCommandVars.explain, "explain", false, "")
	runFlags.BoolVar(&runCommandVars.explain, "x", false, "")
	runFlags.BoolVar(&runCommandVars.sequential, "sequential", false, "")
	runFlags.BoolVar(&runCommandVars.sequential, "s", false, "")
	runFlags.BoolVar(&runCommandVars.nodeps, "no-dependencies", false, "")
	runFlags.BoolVar(&runCommandVars.nodeps, "n", false, "")
	runFlags.StringVar(&runCommandVars.verbose, "verbose", "loud", "")
	runFlags.StringVar(&runCommandVars.verbose, "v", "loud", "")
	runFlags.BoolVar(&runCommandVars.isTag, "tag", false, "")

	runFlags.Parse(os.Args[2:]) // this may exit

	runCommandVars.tests = runFlags.Args()

	if len(runCommandVars.tests) == 0 {
		return errors.New("At least one test or target must be specified")
	}

	switch runCommandVars.verbose {
	case VERBOSE_LOUD:
	case VERBOSE_QUIET:
	case VERBOSE_WHISPER:
	default:
		return errors.New("verbose flag must be one of 'loud', 'quiet', or 'whisper'")
	}

	return nil
}

func runTestGroup(tg *test161.TestGroup, useDeps bool) int {
	var r test161.TestRunner
	if useDeps {
		r = test161.NewDependencyRunner(tg)
	} else {
		r = test161.NewSimpleRunner(tg)
	}

	if runCommandVars.sequential {
		test161.SetManagerCapacity(1)
	} else {
		test161.SetManagerCapacity(0)
	}

	// Set up a PersistenceManager that just outputs to the console
	if runCommandVars.verbose == VERBOSE_LOUD {
		// Compute the max witdth for pretty-printing lines
		max := 0
		for _, t := range tg.Tests {
			if max < len(t.DependencyID) {
				max = len(t.DependencyID)
			}
		}
		env.Persistence = &ConsolePersistence{max}
	}

	// Run it
	test161.StartManager()
	done := r.Run()

	// For reurn val
	allCorrect := true

	for res := range done {
		if res.Test.Result != test161.TEST_RESULT_CORRECT {
			allCorrect = false
		}
	}

	test161.StopManager()

	printRunSummary(tg, runCommandVars.verbose, useDeps)

	if allCorrect {
		return 0
	} else {
		return 1
	}
}

func printRunSummary(tg *test161.TestGroup, verbosity string, tryDependOrder bool) {
	headers := []*Heading{
		&Heading{
			Text:     "Test",
			MinWidth: 30,
		},
		&Heading{
			Text:     "Result",
			MinWidth: 10,
		},
		&Heading{
			Text:           "Memory Leaks",
			RightJustified: true,
		},
		&Heading{
			Text:           "Score",
			MinWidth:       10,
			RightJustified: true,
		},
	}

	tests := getPrintOrder(tg, tryDependOrder)

	totalPoints, totalAvail := uint(0), uint(0)

	results := make([][]string, 0)

	desc := []string{"Total Correct", "Total Incorrect",
		"Total Skipped", "Total Aborted",
	}

	totals := []int{0, 0, 0, 0}

	for _, test := range tests {
		totalPoints += test.PointsEarned
		totalAvail += test.PointsAvailable

		status := string(test.Result)
		if test.Result == test161.TEST_RESULT_SKIP {
			// Try to find a failed dependency
			for _, dep := range test.ExpandedDeps {
				if dep.Result == test161.TEST_RESULT_INCORRECT ||
					dep.Result == test161.TEST_RESULT_SKIP {

					status += " (" + (dep.DependencyID) + ")"
					break
				}
			}
		}

		leak := "---"
		if test.MemLeakChecked {
			if test.MemLeakBytes == 0 {
				leak = "None"
			} else {
				leak = fmt.Sprintf("%v bytes", test.MemLeakBytes)
			}
		}

		row := []string{
			test.DependencyID,
			status,
			leak,
			fmt.Sprintf("%v/%v", test.PointsEarned, test.PointsAvailable),
		}

		results = append(results, row)

		switch test.Result {
		case test161.TEST_RESULT_CORRECT:
			totals[0] += 1
		case test161.TEST_RESULT_INCORRECT:
			totals[1] += 1
		case test161.TEST_RESULT_SKIP:
			totals[2] += 1
		case test161.TEST_RESULT_ABORT:
			totals[3] += 1
		}
	}

	test161.StopManager()

	if verbosity != VERBOSE_WHISPER {
		// Chop off the score if it's not a graded target
		if totalAvail == 0 {
			headers = headers[0 : len(headers)-1]
			for i, row := range results {
				results[i] = row[0 : len(row)-1]
			}
		}
		fmt.Println()
		printColumns(headers, results, defaultPrintConf)
	}

	// Print totals
	fmt.Println()

	for i := 0; i < len(desc); i++ {
		if i == 0 || totals[i] > 0 {
			fmt.Printf("%-15v: %v/%v\n", desc[i], totals[i], len(tg.Tests))
		}
	}

	if totalAvail > 0 {
		fmt.Printf("\n%-15v: %v/%v\n", "Total Score", totalPoints, totalAvail)
	}

	fmt.Println()
}

func runTests() (int, []error) {

	var target *test161.Target
	var ok bool

	// Try running as a Target first
	if len(runCommandVars.tests) == 1 && !runCommandVars.isTag {
		if target, ok = env.Targets[runCommandVars.tests[0]]; ok {
			tg, errs := target.Instance(env)
			if len(errs) > 0 {
				return 1, errs
			} else {
				if runCommandVars.explain {
					explain(tg)
				} else if runCommandVars.dryRun {
					printDryRun(tg)
				} else {
					runTestGroup(tg, true)
				}
				return 0, nil
			}
		}
	}

	// Not a target, run as a regular (ungraded) TestGroup
	config := &test161.GroupConfig{
		Name:    "test",
		UseDeps: !runCommandVars.nodeps,
		Tests:   runCommandVars.tests,
		Env:     env,
	}

	exitcode := 0

	if tg, errs := test161.GroupFromConfig(config); len(errs) > 0 {
		return 1, errs
	} else {
		if runCommandVars.explain {
			explain(tg)
		} else if runCommandVars.dryRun {
			printDryRun(tg)
		} else {
			exitcode = runTestGroup(tg, config.UseDeps)
		}
		return exitcode, nil
	}
}

type testsByID []*test161.Test

func (t testsByID) Len() int           { return len(t) }
func (t testsByID) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }
func (t testsByID) Less(i, j int) bool { return t[i].DependencyID < t[j].DependencyID }

func printDryRun(tg *test161.TestGroup) {

	headers := []*Heading{
		&Heading{
			Text:     "Test ID",
			MinWidth: 30,
		},
		&Heading{
			Text: "Test Name",
		},
		&Heading{
			Text:           "Points",
			RightJustified: true,
		},
	}

	sorted := getPrintOrder(tg, true)
	rows := make([][]string, 0)

	for _, test := range sorted {
		points := ""
		if test.IsDependency {
			points = "(dependency)"
		} else {
			points = fmt.Sprintf("%v", test.PointsAvailable)
		}
		rows = append(rows, []string{
			test.DependencyID, test.Name, points,
		})
	}

	fmt.Println()
	printColumns(headers, rows, defaultPrintConf)
	fmt.Println()
}

func explain(tg *test161.TestGroup) {

	tests := getPrintOrder(tg, true)

	fmt.Println()

	for _, test := range tests {
		if test.IsDependency {
			fmt.Printf("%-30v (dependency)\n", test.DependencyID)
		}
	}

	for _, test := range tests {
		if test.IsDependency {
			continue
		}

		fmt.Println()

		// Test ID
		fmt.Println(test.DependencyID)
		fmt.Println(strings.Repeat("-", 60))
		fmt.Println("Name        :", test.Name)
		fmt.Println("Description :", strings.TrimSpace(test.Description))

		fmt.Println("\nSys161 Conf:")

		// Merge in test161 defaults for any missing configuration values
		test.SetEnv(env)
		test.MergeAllDefaults()
		conf, _ := test.PrintConf()
		fmt.Println(strings.TrimSpace(conf))
		fmt.Println()

		// Points/scoring
		if test.PointsAvailable > 0 {
			fmt.Println("Points      : ", test.PointsAvailable)
			fmt.Println("Scoring     : ", test.ScoringMethod)
		}

		// Dependencies
		if len(test.ExpandedDeps) > 0 {
			sorted := make([]*test161.Test, 0)
			for _, dep := range test.ExpandedDeps {
				sorted = append(sorted, dep)
			}
			sort.Sort(testsByID(sorted))

			fmt.Println("Dependencies:")
			for _, dep := range sorted {
				fmt.Println("    ", dep.DependencyID)
			}
		}

		// Commands
		fmt.Println("Commands:")

		for _, cmd := range test.Commands {
			// Instantiate the command so we get the expected output
			fmt.Println("    Cmd Line    :", cmd.Input.Line)
			fmt.Println("      Panics    :", cmd.Panic)
			fmt.Println("      Times Out :", cmd.TimesOut)
			fmt.Println("      Timeout   :", cmd.Timeout)
			fmt.Println("      Points    :", cmd.PointsAvailable)
			if len(cmd.ExpectedOutput) > 0 {
				fmt.Println("      Output    :")
				for _, output := range cmd.ExpectedOutput {
					fmt.Println("            Text     :", output.Text)
					fmt.Println("            Trusted  :", output.Trusted)
					fmt.Println("            KeyID    :", output.KeyName)
				}
			}
		}
	}

	fmt.Println()
}

func getPrintOrder(tg *test161.TestGroup, tryDependOrder bool) []*test161.Test {
	tests := make([]*test161.Test, 0, len(tg.Tests))

	if tryDependOrder {
		if graph, err := tg.DependencyGraph(); err == nil {
			if topSort, err := graph.TopSort(); err == nil {

				for i := len(topSort) - 1; i >= 0; i -= 1 {
					if test, ok := tg.Tests[topSort[i]]; !ok {
						break
					} else {
						tests = append(tests, test)
					}
				}
			}

			if len(tests) == len(tg.Tests) {
				return tests
			}
		}
	}

	// Default to alphabetical
	for _, t := range tg.Tests {
		tests = append(tests, t)
	}
	sort.Sort(testsByID(tests))

	return tests
}
<commit_msg>Now printing errors encountered in the test runner.<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"github.com/ops-class/test161"
	"os"
	"sort"
	"strings"
)

// 'test161 run' flags
var runCommandVars struct {
	dryRun     bool
	explain    bool
	sequential bool
	nodeps     bool
	verbose    string
	isTag      bool
	tests      []string
}

func __printRunError(err error) {
	fmt.Fprintf(os.Stderr, "Error: %v\n", err)
}

func printRunError(err error) {
	__printRunError(err)
}

func printRunErrors(errs []error) {
	if len(errs) > 0 {
		for _, e := range errs {
			__printRunError(e)
		}
	}
}

func doRun() int {
	if err := getRunArgs(); err != nil {
		printRunError(err)
		return 1
	}

	exitcode, errs := runTests()
	if len(errs) > 0 {
		printRunErrors(errs)
	}

	return exitcode
}

// Verbose settings
const (
	VERBOSE_LOUD    = "loud"
	VERBOSE_QUIET   = "quiet"
	VERBOSE_WHISPER = "whisper"
)

func getRunArgs() error {

	runFlags := flag.NewFlagSet("test161 run", flag.ExitOnError)
	runFlags.Usage = usage

	runFlags.BoolVar(&runCommandVars.dryRun, "dry-run", false, "")
	runFlags.BoolVar(&runCommandVars.dryRun, "d", false, "")
	runFlags.BoolVar(&runCommandVars.explain, "explain", false, "")
	runFlags.BoolVar(&runCommandVars.explain, "x", false, "")
	runFlags.BoolVar(&runCommandVars.sequential, "sequential", false, "")
	runFlags.BoolVar(&runCommandVars.sequential, "s", false, "")
	runFlags.BoolVar(&runCommandVars.nodeps, "no-dependencies", false, "")
	runFlags.BoolVar(&runCommandVars.nodeps, "n", false, "")
	runFlags.StringVar(&runCommandVars.verbose, "verbose", "loud", "")
	runFlags.StringVar(&runCommandVars.verbose, "v", "loud", "")
	runFlags.BoolVar(&runCommandVars.isTag, "tag", false, "")

	runFlags.Parse(os.Args[2:]) // this may exit

	runCommandVars.tests = runFlags.Args()

	if len(runCommandVars.tests) == 0 {
		return errors.New("At least one test or target must be specified")
	}

	switch runCommandVars.verbose {
	case VERBOSE_LOUD:
	case VERBOSE_QUIET:
	case VERBOSE_WHISPER:
	default:
		return errors.New("verbose flag must be one of 'loud', 'quiet', or 'whisper'")
	}

	return nil
}

func runTestGroup(tg *test161.TestGroup, useDeps bool) int {
	var r test161.TestRunner
	if useDeps {
		r = test161.NewDependencyRunner(tg)
	} else {
		r = test161.NewSimpleRunner(tg)
	}

	if runCommandVars.sequential {
		test161.SetManagerCapacity(1)
	} else {
		test161.SetManagerCapacity(0)
	}

	// Set up a PersistenceManager that just outputs to the console
	if runCommandVars.verbose == VERBOSE_LOUD {
		// Compute the max witdth for pretty-printing lines
		max := 0
		for _, t := range tg.Tests {
			if max < len(t.DependencyID) {
				max = len(t.DependencyID)
			}
		}
		env.Persistence = &ConsolePersistence{max}
	}

	// Run it
	test161.StartManager()
	done := r.Run()

	// For reurn val
	allCorrect := true

	for res := range done {
		if res.Test.Result != test161.TEST_RESULT_CORRECT {
			allCorrect = false
		}
		if res.Err != nil {
			fmt.Fprint(os.Stderr, "Error running %v: %v\n", res.Test.DependencyID, res.Err)
		}
	}

	test161.StopManager()

	printRunSummary(tg, runCommandVars.verbose, useDeps)

	if allCorrect {
		return 0
	} else {
		return 1
	}
}

func printRunSummary(tg *test161.TestGroup, verbosity string, tryDependOrder bool) {
	headers := []*Heading{
		&Heading{
			Text:     "Test",
			MinWidth: 30,
		},
		&Heading{
			Text:     "Result",
			MinWidth: 10,
		},
		&Heading{
			Text:           "Memory Leaks",
			RightJustified: true,
		},
		&Heading{
			Text:           "Score",
			MinWidth:       10,
			RightJustified: true,
		},
	}

	tests := getPrintOrder(tg, tryDependOrder)

	totalPoints, totalAvail := uint(0), uint(0)

	results := make([][]string, 0)

	desc := []string{"Total Correct", "Total Incorrect",
		"Total Skipped", "Total Aborted",
	}

	totals := []int{0, 0, 0, 0}

	for _, test := range tests {
		totalPoints += test.PointsEarned
		totalAvail += test.PointsAvailable

		status := string(test.Result)
		if test.Result == test161.TEST_RESULT_SKIP {
			// Try to find a failed dependency
			for _, dep := range test.ExpandedDeps {
				if dep.Result == test161.TEST_RESULT_INCORRECT ||
					dep.Result == test161.TEST_RESULT_SKIP {

					status += " (" + (dep.DependencyID) + ")"
					break
				}
			}
		}

		leak := "---"
		if test.MemLeakChecked {
			if test.MemLeakBytes == 0 {
				leak = "None"
			} else {
				leak = fmt.Sprintf("%v bytes", test.MemLeakBytes)
			}
		}

		row := []string{
			test.DependencyID,
			status,
			leak,
			fmt.Sprintf("%v/%v", test.PointsEarned, test.PointsAvailable),
		}

		results = append(results, row)

		switch test.Result {
		case test161.TEST_RESULT_CORRECT:
			totals[0] += 1
		case test161.TEST_RESULT_INCORRECT:
			totals[1] += 1
		case test161.TEST_RESULT_SKIP:
			totals[2] += 1
		case test161.TEST_RESULT_ABORT:
			totals[3] += 1
		}
	}

	test161.StopManager()

	if verbosity != VERBOSE_WHISPER {
		// Chop off the score if it's not a graded target
		if totalAvail == 0 {
			headers = headers[0 : len(headers)-1]
			for i, row := range results {
				results[i] = row[0 : len(row)-1]
			}
		}
		fmt.Println()
		printColumns(headers, results, defaultPrintConf)
	}

	// Print totals
	fmt.Println()

	for i := 0; i < len(desc); i++ {
		if i == 0 || totals[i] > 0 {
			fmt.Printf("%-15v: %v/%v\n", desc[i], totals[i], len(tg.Tests))
		}
	}

	if totalAvail > 0 {
		fmt.Printf("\n%-15v: %v/%v\n", "Total Score", totalPoints, totalAvail)
	}

	fmt.Println()
}

func runTests() (int, []error) {

	var target *test161.Target
	var ok bool

	// Try running as a Target first
	if len(runCommandVars.tests) == 1 && !runCommandVars.isTag {
		if target, ok = env.Targets[runCommandVars.tests[0]]; ok {
			tg, errs := target.Instance(env)
			if len(errs) > 0 {
				return 1, errs
			} else {
				if runCommandVars.explain {
					explain(tg)
				} else if runCommandVars.dryRun {
					printDryRun(tg)
				} else {
					runTestGroup(tg, true)
				}
				return 0, nil
			}
		}
	}

	// Not a target, run as a regular (ungraded) TestGroup
	config := &test161.GroupConfig{
		Name:    "test",
		UseDeps: !runCommandVars.nodeps,
		Tests:   runCommandVars.tests,
		Env:     env,
	}

	exitcode := 0

	if tg, errs := test161.GroupFromConfig(config); len(errs) > 0 {
		return 1, errs
	} else {
		if runCommandVars.explain {
			explain(tg)
		} else if runCommandVars.dryRun {
			printDryRun(tg)
		} else {
			exitcode = runTestGroup(tg, config.UseDeps)
		}
		return exitcode, nil
	}
}

type testsByID []*test161.Test

func (t testsByID) Len() int           { return len(t) }
func (t testsByID) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }
func (t testsByID) Less(i, j int) bool { return t[i].DependencyID < t[j].DependencyID }

func printDryRun(tg *test161.TestGroup) {

	headers := []*Heading{
		&Heading{
			Text:     "Test ID",
			MinWidth: 30,
		},
		&Heading{
			Text: "Test Name",
		},
		&Heading{
			Text:           "Points",
			RightJustified: true,
		},
	}

	sorted := getPrintOrder(tg, true)
	rows := make([][]string, 0)

	for _, test := range sorted {
		points := ""
		if test.IsDependency {
			points = "(dependency)"
		} else {
			points = fmt.Sprintf("%v", test.PointsAvailable)
		}
		rows = append(rows, []string{
			test.DependencyID, test.Name, points,
		})
	}

	fmt.Println()
	printColumns(headers, rows, defaultPrintConf)
	fmt.Println()
}

func explain(tg *test161.TestGroup) {

	tests := getPrintOrder(tg, true)

	fmt.Println()

	for _, test := range tests {
		if test.IsDependency {
			fmt.Printf("%-30v (dependency)\n", test.DependencyID)
		}
	}

	for _, test := range tests {
		if test.IsDependency {
			continue
		}

		fmt.Println()

		// Test ID
		fmt.Println(test.DependencyID)
		fmt.Println(strings.Repeat("-", 60))
		fmt.Println("Name        :", test.Name)
		fmt.Println("Description :", strings.TrimSpace(test.Description))

		fmt.Println("\nSys161 Conf:")

		// Merge in test161 defaults for any missing configuration values
		test.SetEnv(env)
		test.MergeAllDefaults()
		conf, _ := test.PrintConf()
		fmt.Println(strings.TrimSpace(conf))
		fmt.Println()

		// Points/scoring
		if test.PointsAvailable > 0 {
			fmt.Println("Points      : ", test.PointsAvailable)
			fmt.Println("Scoring     : ", test.ScoringMethod)
		}

		// Dependencies
		if len(test.ExpandedDeps) > 0 {
			sorted := make([]*test161.Test, 0)
			for _, dep := range test.ExpandedDeps {
				sorted = append(sorted, dep)
			}
			sort.Sort(testsByID(sorted))

			fmt.Println("Dependencies:")
			for _, dep := range sorted {
				fmt.Println("    ", dep.DependencyID)
			}
		}

		// Commands
		fmt.Println("Commands:")

		for _, cmd := range test.Commands {
			// Instantiate the command so we get the expected output
			fmt.Println("    Cmd Line    :", cmd.Input.Line)
			fmt.Println("      Panics    :", cmd.Panic)
			fmt.Println("      Times Out :", cmd.TimesOut)
			fmt.Println("      Timeout   :", cmd.Timeout)
			fmt.Println("      Points    :", cmd.PointsAvailable)
			if len(cmd.ExpectedOutput) > 0 {
				fmt.Println("      Output    :")
				for _, output := range cmd.ExpectedOutput {
					fmt.Println("            Text     :", output.Text)
					fmt.Println("            Trusted  :", output.Trusted)
					fmt.Println("            KeyID    :", output.KeyName)
				}
			}
		}
	}

	fmt.Println()
}

func getPrintOrder(tg *test161.TestGroup, tryDependOrder bool) []*test161.Test {
	tests := make([]*test161.Test, 0, len(tg.Tests))

	if tryDependOrder {
		if graph, err := tg.DependencyGraph(); err == nil {
			if topSort, err := graph.TopSort(); err == nil {

				for i := len(topSort) - 1; i >= 0; i -= 1 {
					if test, ok := tg.Tests[topSort[i]]; !ok {
						break
					} else {
						tests = append(tests, test)
					}
				}
			}

			if len(tests) == len(tg.Tests) {
				return tests
			}
		}
	}

	// Default to alphabetical
	for _, t := range tg.Tests {
		tests = append(tests, t)
	}
	sort.Sort(testsByID(tests))

	return tests
}
<|endoftext|>


<commit_before>// Copyright 2014 Manu Martinez-Almeida.  All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.

package gin

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http/httputil"
	"runtime"
)

var (
	dunno     = []byte("???")
	centerDot = []byte("·")
	dot       = []byte(".")
	slash     = []byte("/")
)

// Recovery returns a middleware that recovers from any panics and writes a 500 if there was one.
func Recovery() HandlerFunc {
	return RecoveryWithWriter(DefaultErrorWriter)
}

func RecoveryWithWriter(out io.Writer) HandlerFunc {
	var logger *log.Logger
	if out != nil {
		logger = log.New(out, "\n\n\x1b[31m", log.LstdFlags)
	}
	return func(c *Context) {
		defer func() {
			if err := recover(); err != nil {
				if logger != nil {
					stack := stack(3)
					httprequest, _ := httputil.DumpRequest(c.Request, false)
					logger.Printf("[Recovery] panic recovered:\n%s\n%s\n%s%s", string(httprequest), err, stack, reset)
				}
				c.AbortWithStatus(500)
			}
		}()
		c.Next()
	}
}

// stack returns a nicely formated stack frame, skipping skip frames.
func stack(skip int) []byte {
	buf := new(bytes.Buffer) // the returned data
	// As we loop, we open files and read them. These variables record the currently
	// loaded file.
	var lines [][]byte
	var lastFile string
	for i := skip; ; i++ { // Skip the expected number of frames
		pc, file, line, ok := runtime.Caller(i)
		if !ok {
			break
		}
		// Print this much at least.  If we can't find the source, it won't show.
		fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc)
		if file != lastFile {
			data, err := ioutil.ReadFile(file)
			if err != nil {
				continue
			}
			lines = bytes.Split(data, []byte{'\n'})
			lastFile = file
		}
		fmt.Fprintf(buf, "\t%s: %s\n", function(pc), source(lines, line))
	}
	return buf.Bytes()
}

// source returns a space-trimmed slice of the n'th line.
func source(lines [][]byte, n int) []byte {
	n-- // in stack trace, lines are 1-indexed but our array is 0-indexed
	if n < 0 || n >= len(lines) {
		return dunno
	}
	return bytes.TrimSpace(lines[n])
}

// function returns, if possible, the name of the function containing the PC.
func function(pc uintptr) []byte {
	fn := runtime.FuncForPC(pc)
	if fn == nil {
		return dunno
	}
	name := []byte(fn.Name())
	// The name includes the path name to the package, which is unnecessary
	// since the file name is already included.  Plus, it has center dots.
	// That is, we see
	//	runtime/debug.*T·ptrmethod
	// and want
	//	*T.ptrmethod
	// Also the package path might contains dot (e.g. code.google.com/...),
	// so first eliminate the path prefix
	if lastslash := bytes.LastIndex(name, slash); lastslash >= 0 {
		name = name[lastslash+1:]
	}
	if period := bytes.Index(name, dot); period >= 0 {
		name = name[period+1:]
	}
	name = bytes.Replace(name, centerDot, dot, -1)
	return name
}
<commit_msg>correct spelling mistake (#1092)<commit_after>// Copyright 2014 Manu Martinez-Almeida.  All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.

package gin

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http/httputil"
	"runtime"
)

var (
	dunno     = []byte("???")
	centerDot = []byte("·")
	dot       = []byte(".")
	slash     = []byte("/")
)

// Recovery returns a middleware that recovers from any panics and writes a 500 if there was one.
func Recovery() HandlerFunc {
	return RecoveryWithWriter(DefaultErrorWriter)
}

func RecoveryWithWriter(out io.Writer) HandlerFunc {
	var logger *log.Logger
	if out != nil {
		logger = log.New(out, "\n\n\x1b[31m", log.LstdFlags)
	}
	return func(c *Context) {
		defer func() {
			if err := recover(); err != nil {
				if logger != nil {
					stack := stack(3)
					httprequest, _ := httputil.DumpRequest(c.Request, false)
					logger.Printf("[Recovery] panic recovered:\n%s\n%s\n%s%s", string(httprequest), err, stack, reset)
				}
				c.AbortWithStatus(500)
			}
		}()
		c.Next()
	}
}

// stack returns a nicely formatted stack frame, skipping skip frames.
func stack(skip int) []byte {
	buf := new(bytes.Buffer) // the returned data
	// As we loop, we open files and read them. These variables record the currently
	// loaded file.
	var lines [][]byte
	var lastFile string
	for i := skip; ; i++ { // Skip the expected number of frames
		pc, file, line, ok := runtime.Caller(i)
		if !ok {
			break
		}
		// Print this much at least.  If we can't find the source, it won't show.
		fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc)
		if file != lastFile {
			data, err := ioutil.ReadFile(file)
			if err != nil {
				continue
			}
			lines = bytes.Split(data, []byte{'\n'})
			lastFile = file
		}
		fmt.Fprintf(buf, "\t%s: %s\n", function(pc), source(lines, line))
	}
	return buf.Bytes()
}

// source returns a space-trimmed slice of the n'th line.
func source(lines [][]byte, n int) []byte {
	n-- // in stack trace, lines are 1-indexed but our array is 0-indexed
	if n < 0 || n >= len(lines) {
		return dunno
	}
	return bytes.TrimSpace(lines[n])
}

// function returns, if possible, the name of the function containing the PC.
func function(pc uintptr) []byte {
	fn := runtime.FuncForPC(pc)
	if fn == nil {
		return dunno
	}
	name := []byte(fn.Name())
	// The name includes the path name to the package, which is unnecessary
	// since the file name is already included.  Plus, it has center dots.
	// That is, we see
	//	runtime/debug.*T·ptrmethod
	// and want
	//	*T.ptrmethod
	// Also the package path might contains dot (e.g. code.google.com/...),
	// so first eliminate the path prefix
	if lastslash := bytes.LastIndex(name, slash); lastslash >= 0 {
		name = name[lastslash+1:]
	}
	if period := bytes.Index(name, dot); period >= 0 {
		name = name[period+1:]
	}
	name = bytes.Replace(name, centerDot, dot, -1)
	return name
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
)

// Check the license of multiplayerpiano.com before fetching their WAV-es.

func main() {
	base := "http://multiplayerpiano.com/mp3/"
	notes := []string{"c", "cs", "d", "ds", "e", "f", "fs", "g", "gs", "a", "as", "b"}
	for oct := 1; oct < 7; oct++ {
		for _, note := range notes {
			prefix := note + fmt.Sprintf("%d", oct)
			resp, _ := http.Get(base + prefix + ".wav.mp3")
			fmt.Printf("fetching:%s\n", prefix)
			defer resp.Body.Close()
			body, _ := ioutil.ReadAll(resp.Body)
			ioutil.WriteFile("/tmp/"+prefix+".wav.mp3", body, os.ModePerm)
		}
	}
}
<commit_msg>dump,convert and read from HOME/sounds<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
)

// Check the license of multiplayerpiano.com before fetching their WAV-es.

func main() {
	dir := filepath.Join(os.Getenv("HOME"), "sounds")
	fmt.Println("writing sounds in", dir)
	base := "http://multiplayerpiano.com/mp3/"
	notes := []string{"c", "cs", "d", "ds", "e", "f", "fs", "g", "gs", "a", "as", "b"}
	for oct := 1; oct < 7; oct++ {
		for _, note := range notes {
			prefix := note + fmt.Sprintf("%d", oct)
			resp, _ := http.Get(base + prefix + ".wav.mp3")
			fmt.Printf("fetching:%s\n", prefix)
			defer resp.Body.Close()
			body, _ := ioutil.ReadAll(resp.Body)
			ioutil.WriteFile(filepath.Join(dir, prefix+".wav.mp3"), body, os.ModePerm)
		}
	}
}
<|endoftext|>


<commit_before>package reflect2

import (
	"github.com/modern-go/concurrent"
	"reflect"
	"unsafe"
)

type Type interface {
	Kind() reflect.Kind
	// New return pointer to data of this type
	New() interface{}
	// UnsafeNew return the allocated space pointed by unsafe.Pointer
	UnsafeNew() unsafe.Pointer
	// PackEFace cast a unsafe pointer to object represented pointer
	PackEFace(ptr unsafe.Pointer) interface{}
	// Indirect dereference object represented pointer to this type
	Indirect(obj interface{}) interface{}
	// UnsafeIndirect dereference pointer to this type
	UnsafeIndirect(ptr unsafe.Pointer) interface{}
	// Type1 returns reflect.Type
	Type1() reflect.Type
	Implements(thatType Type) bool
	String() string
	RType() uintptr
	// interface{} of this type has pointer like behavior
	LikePtr() bool
	IsNullable() bool
	IsNil(obj interface{}) bool
	UnsafeIsNil(ptr unsafe.Pointer) bool
	Set(obj interface{}, val interface{})
	UnsafeSet(ptr unsafe.Pointer, val unsafe.Pointer)
	AssignableTo(anotherType Type) bool
}

type ListType interface {
	Type
	Elem() Type
	SetIndex(obj interface{}, index int, elem interface{})
	UnsafeSetIndex(obj unsafe.Pointer, index int, elem unsafe.Pointer)
	GetIndex(obj interface{}, index int) interface{}
	UnsafeGetIndex(obj unsafe.Pointer, index int) unsafe.Pointer
}

type ArrayType interface {
	ListType
	Len() int
}

type SliceType interface {
	ListType
	MakeSlice(length int, cap int) interface{}
	UnsafeMakeSlice(length int, cap int) unsafe.Pointer
	Grow(obj interface{}, newLength int)
	UnsafeGrow(ptr unsafe.Pointer, newLength int)
	Append(obj interface{}, elem interface{})
	UnsafeAppend(obj unsafe.Pointer, elem unsafe.Pointer)
	LengthOf(obj interface{}) int
	UnsafeLengthOf(ptr unsafe.Pointer) int
	SetNil(obj interface{})
	UnsafeSetNil(ptr unsafe.Pointer)
	Cap(obj interface{}) int
	UnsafeCap(ptr unsafe.Pointer) int
}

type StructType interface {
	Type
	NumField() int
	Field(i int) StructField
	FieldByName(name string) StructField
	FieldByIndex(index []int) StructField
	FieldByNameFunc(match func(string) bool) StructField
}

type StructField interface {
	Offset() uintptr
	Name() string
	PkgPath() string
	Type() Type
	Tag() reflect.StructTag
	Index() []int
	Anonymous() bool
	Set(obj interface{}, value interface{})
	UnsafeSet(obj unsafe.Pointer, value unsafe.Pointer)
	Get(obj interface{}) interface{}
	UnsafeGet(obj unsafe.Pointer) unsafe.Pointer
}

type MapType interface {
	Type
	Key() Type
	Elem() Type
	MakeMap(cap int) interface{}
	UnsafeMakeMap(cap int) unsafe.Pointer
	SetIndex(obj interface{}, key interface{}, elem interface{})
	UnsafeSetIndex(obj unsafe.Pointer, key unsafe.Pointer, elem unsafe.Pointer)
	TryGetIndex(obj interface{}, key interface{}) (interface{}, bool)
	GetIndex(obj interface{}, key interface{}) interface{}
	UnsafeGetIndex(obj unsafe.Pointer, key unsafe.Pointer) unsafe.Pointer
	Iterate(obj interface{}) MapIterator
	UnsafeIterate(obj unsafe.Pointer) MapIterator
}

type MapIterator interface {
	HasNext() bool
	Next() (key interface{}, elem interface{})
	UnsafeNext() (key unsafe.Pointer, elem unsafe.Pointer)
}

type PtrType interface {
	Type
	Elem() Type
}

type InterfaceType interface {
	NumMethod() int
}

type Config struct {
	UseSafeImplementation bool
}

type API interface {
	TypeOf(obj interface{}) Type
	Type2(type1 reflect.Type) Type
}

var ConfigUnsafe = Config{UseSafeImplementation: false}.Froze()
var ConfigSafe = Config{UseSafeImplementation: true}.Froze()

type frozenConfig struct {
	useSafeImplementation bool
	cache                 *concurrent.Map
}

func (cfg Config) Froze() *frozenConfig {
	return &frozenConfig{
		useSafeImplementation: cfg.UseSafeImplementation,
		cache: concurrent.NewMap(),
	}
}

func (cfg *frozenConfig) TypeOf(obj interface{}) Type {
	cacheKey := uintptr(unpackEFace(obj).rtype)
	typeObj, found := cfg.cache.Load(cacheKey)
	if found {
		return typeObj.(Type)
	}
	return cfg.Type2(reflect.TypeOf(obj))
}

func (cfg *frozenConfig) Type2(type1 reflect.Type) Type {
	if type1 == nil {
		return nil
	}
	cacheKey := uintptr(unpackEFace(type1).data)
	typeObj, found := cfg.cache.Load(cacheKey)
	if found {
		return typeObj.(Type)
	}
	type2 := cfg.wrapType(type1)
	cfg.cache.Store(cacheKey, type2)
	return type2
}

func (cfg *frozenConfig) wrapType(type1 reflect.Type) Type {
	safeType := safeType{Type: type1, cfg: cfg}
	switch type1.Kind() {
	case reflect.Struct:
		if cfg.useSafeImplementation {
			return &safeStructType{safeType}
		}
		return newUnsafeStructType(cfg, type1)
	case reflect.Array:
		if cfg.useSafeImplementation {
			return &safeSliceType{safeType}
		}
		return newUnsafeArrayType(cfg, type1)
	case reflect.Slice:
		if cfg.useSafeImplementation {
			return &safeSliceType{safeType}
		}
		return newUnsafeSliceType(cfg, type1)
	case reflect.Map:
		if cfg.useSafeImplementation {
			return &safeMapType{safeType}
		}
		return newUnsafeMapType(cfg, type1)
	case reflect.Ptr, reflect.Chan, reflect.Func:
		if cfg.useSafeImplementation {
			return &safeMapType{safeType}
		}
		return newUnsafePtrType(cfg, type1)
	case reflect.Interface:
		if cfg.useSafeImplementation {
			return &safeMapType{safeType}
		}
		if type1.NumMethod() == 0 {
			return newUnsafeEFaceType(cfg, type1)
		}
		return newUnsafeIFaceType(cfg, type1)
	default:
		if cfg.useSafeImplementation {
			return &safeType
		}
		return newUnsafeType(cfg, type1)
	}
}

func TypeOf(obj interface{}) Type {
	return ConfigUnsafe.TypeOf(obj)
}

func TypeOfPtr(obj interface{}) PtrType {
	return TypeOf(obj).(PtrType)
}

func Type2(type1 reflect.Type) Type {
	if type1 == nil {
		return nil
	}
	return ConfigUnsafe.Type2(type1)
}

func PtrTo(typ Type) Type {
	return Type2(reflect.PtrTo(typ.Type1()))
}

func PtrOf(obj interface{}) unsafe.Pointer {
	return unpackEFace(obj).data
}

func RTypeOf(obj interface{}) uintptr {
	return uintptr(unpackEFace(obj).rtype)
}

func IsNil(obj interface{}) bool {
	if obj == nil {
		return true
	}
	return unpackEFace(obj).data == nil
}

func IsNullable(kind reflect.Kind) bool {
	switch kind {
	case reflect.Ptr, reflect.Map, reflect.Chan, reflect.Func, reflect.Slice, reflect.Interface:
		return true
	}
	return false
}

func likePtrKind(kind reflect.Kind) bool {
	switch kind {
	case reflect.Ptr, reflect.Map, reflect.Chan, reflect.Func:
		return true
	}
	return false
}

func likePtrType(typ reflect.Type) bool {
	if likePtrKind(typ.Kind()) {
		return true
	}
	if typ.Kind() == reflect.Struct {
		if typ.NumField() != 1 {
			return false
		}
		return likePtrType(typ.Field(0).Type)
	}
	if typ.Kind() == reflect.Array {
		if typ.Len() != 1 {
			return false
		}
		return likePtrType(typ.Elem())
	}
	return false
}

// NoEscape hides a pointer from escape analysis.  noescape is
// the identity function but escape analysis doesn't think the
// output depends on the input.  noescape is inlined and currently
// compiles down to zero instructions.
// USE CAREFULLY!
//go:nosplit
func NoEscape(p unsafe.Pointer) unsafe.Pointer {
	x := uintptr(p)
	return unsafe.Pointer(x ^ 0)
}

func UnsafeCastString(str string) []byte {
	bytes := make([]byte, 0)
	stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&str))
	sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&bytes))
	sliceHeader.Data = stringHeader.Data
	sliceHeader.Cap = stringHeader.Len
	sliceHeader.Len = stringHeader.Len
	runtime.KeepAlive(str)
	return bytes
}
<commit_msg><fix> (reflect2.go)  import runtime<commit_after>package reflect2

import (
	"github.com/modern-go/concurrent"
	"reflect"
	"runtime"
	"unsafe"
)

type Type interface {
	Kind() reflect.Kind
	// New return pointer to data of this type
	New() interface{}
	// UnsafeNew return the allocated space pointed by unsafe.Pointer
	UnsafeNew() unsafe.Pointer
	// PackEFace cast a unsafe pointer to object represented pointer
	PackEFace(ptr unsafe.Pointer) interface{}
	// Indirect dereference object represented pointer to this type
	Indirect(obj interface{}) interface{}
	// UnsafeIndirect dereference pointer to this type
	UnsafeIndirect(ptr unsafe.Pointer) interface{}
	// Type1 returns reflect.Type
	Type1() reflect.Type
	Implements(thatType Type) bool
	String() string
	RType() uintptr
	// interface{} of this type has pointer like behavior
	LikePtr() bool
	IsNullable() bool
	IsNil(obj interface{}) bool
	UnsafeIsNil(ptr unsafe.Pointer) bool
	Set(obj interface{}, val interface{})
	UnsafeSet(ptr unsafe.Pointer, val unsafe.Pointer)
	AssignableTo(anotherType Type) bool
}

type ListType interface {
	Type
	Elem() Type
	SetIndex(obj interface{}, index int, elem interface{})
	UnsafeSetIndex(obj unsafe.Pointer, index int, elem unsafe.Pointer)
	GetIndex(obj interface{}, index int) interface{}
	UnsafeGetIndex(obj unsafe.Pointer, index int) unsafe.Pointer
}

type ArrayType interface {
	ListType
	Len() int
}

type SliceType interface {
	ListType
	MakeSlice(length int, cap int) interface{}
	UnsafeMakeSlice(length int, cap int) unsafe.Pointer
	Grow(obj interface{}, newLength int)
	UnsafeGrow(ptr unsafe.Pointer, newLength int)
	Append(obj interface{}, elem interface{})
	UnsafeAppend(obj unsafe.Pointer, elem unsafe.Pointer)
	LengthOf(obj interface{}) int
	UnsafeLengthOf(ptr unsafe.Pointer) int
	SetNil(obj interface{})
	UnsafeSetNil(ptr unsafe.Pointer)
	Cap(obj interface{}) int
	UnsafeCap(ptr unsafe.Pointer) int
}

type StructType interface {
	Type
	NumField() int
	Field(i int) StructField
	FieldByName(name string) StructField
	FieldByIndex(index []int) StructField
	FieldByNameFunc(match func(string) bool) StructField
}

type StructField interface {
	Offset() uintptr
	Name() string
	PkgPath() string
	Type() Type
	Tag() reflect.StructTag
	Index() []int
	Anonymous() bool
	Set(obj interface{}, value interface{})
	UnsafeSet(obj unsafe.Pointer, value unsafe.Pointer)
	Get(obj interface{}) interface{}
	UnsafeGet(obj unsafe.Pointer) unsafe.Pointer
}

type MapType interface {
	Type
	Key() Type
	Elem() Type
	MakeMap(cap int) interface{}
	UnsafeMakeMap(cap int) unsafe.Pointer
	SetIndex(obj interface{}, key interface{}, elem interface{})
	UnsafeSetIndex(obj unsafe.Pointer, key unsafe.Pointer, elem unsafe.Pointer)
	TryGetIndex(obj interface{}, key interface{}) (interface{}, bool)
	GetIndex(obj interface{}, key interface{}) interface{}
	UnsafeGetIndex(obj unsafe.Pointer, key unsafe.Pointer) unsafe.Pointer
	Iterate(obj interface{}) MapIterator
	UnsafeIterate(obj unsafe.Pointer) MapIterator
}

type MapIterator interface {
	HasNext() bool
	Next() (key interface{}, elem interface{})
	UnsafeNext() (key unsafe.Pointer, elem unsafe.Pointer)
}

type PtrType interface {
	Type
	Elem() Type
}

type InterfaceType interface {
	NumMethod() int
}

type Config struct {
	UseSafeImplementation bool
}

type API interface {
	TypeOf(obj interface{}) Type
	Type2(type1 reflect.Type) Type
}

var ConfigUnsafe = Config{UseSafeImplementation: false}.Froze()
var ConfigSafe = Config{UseSafeImplementation: true}.Froze()

type frozenConfig struct {
	useSafeImplementation bool
	cache                 *concurrent.Map
}

func (cfg Config) Froze() *frozenConfig {
	return &frozenConfig{
		useSafeImplementation: cfg.UseSafeImplementation,
		cache: concurrent.NewMap(),
	}
}

func (cfg *frozenConfig) TypeOf(obj interface{}) Type {
	cacheKey := uintptr(unpackEFace(obj).rtype)
	typeObj, found := cfg.cache.Load(cacheKey)
	if found {
		return typeObj.(Type)
	}
	return cfg.Type2(reflect.TypeOf(obj))
}

func (cfg *frozenConfig) Type2(type1 reflect.Type) Type {
	if type1 == nil {
		return nil
	}
	cacheKey := uintptr(unpackEFace(type1).data)
	typeObj, found := cfg.cache.Load(cacheKey)
	if found {
		return typeObj.(Type)
	}
	type2 := cfg.wrapType(type1)
	cfg.cache.Store(cacheKey, type2)
	return type2
}

func (cfg *frozenConfig) wrapType(type1 reflect.Type) Type {
	safeType := safeType{Type: type1, cfg: cfg}
	switch type1.Kind() {
	case reflect.Struct:
		if cfg.useSafeImplementation {
			return &safeStructType{safeType}
		}
		return newUnsafeStructType(cfg, type1)
	case reflect.Array:
		if cfg.useSafeImplementation {
			return &safeSliceType{safeType}
		}
		return newUnsafeArrayType(cfg, type1)
	case reflect.Slice:
		if cfg.useSafeImplementation {
			return &safeSliceType{safeType}
		}
		return newUnsafeSliceType(cfg, type1)
	case reflect.Map:
		if cfg.useSafeImplementation {
			return &safeMapType{safeType}
		}
		return newUnsafeMapType(cfg, type1)
	case reflect.Ptr, reflect.Chan, reflect.Func:
		if cfg.useSafeImplementation {
			return &safeMapType{safeType}
		}
		return newUnsafePtrType(cfg, type1)
	case reflect.Interface:
		if cfg.useSafeImplementation {
			return &safeMapType{safeType}
		}
		if type1.NumMethod() == 0 {
			return newUnsafeEFaceType(cfg, type1)
		}
		return newUnsafeIFaceType(cfg, type1)
	default:
		if cfg.useSafeImplementation {
			return &safeType
		}
		return newUnsafeType(cfg, type1)
	}
}

func TypeOf(obj interface{}) Type {
	return ConfigUnsafe.TypeOf(obj)
}

func TypeOfPtr(obj interface{}) PtrType {
	return TypeOf(obj).(PtrType)
}

func Type2(type1 reflect.Type) Type {
	if type1 == nil {
		return nil
	}
	return ConfigUnsafe.Type2(type1)
}

func PtrTo(typ Type) Type {
	return Type2(reflect.PtrTo(typ.Type1()))
}

func PtrOf(obj interface{}) unsafe.Pointer {
	return unpackEFace(obj).data
}

func RTypeOf(obj interface{}) uintptr {
	return uintptr(unpackEFace(obj).rtype)
}

func IsNil(obj interface{}) bool {
	if obj == nil {
		return true
	}
	return unpackEFace(obj).data == nil
}

func IsNullable(kind reflect.Kind) bool {
	switch kind {
	case reflect.Ptr, reflect.Map, reflect.Chan, reflect.Func, reflect.Slice, reflect.Interface:
		return true
	}
	return false
}

func likePtrKind(kind reflect.Kind) bool {
	switch kind {
	case reflect.Ptr, reflect.Map, reflect.Chan, reflect.Func:
		return true
	}
	return false
}

func likePtrType(typ reflect.Type) bool {
	if likePtrKind(typ.Kind()) {
		return true
	}
	if typ.Kind() == reflect.Struct {
		if typ.NumField() != 1 {
			return false
		}
		return likePtrType(typ.Field(0).Type)
	}
	if typ.Kind() == reflect.Array {
		if typ.Len() != 1 {
			return false
		}
		return likePtrType(typ.Elem())
	}
	return false
}

// NoEscape hides a pointer from escape analysis.  noescape is
// the identity function but escape analysis doesn't think the
// output depends on the input.  noescape is inlined and currently
// compiles down to zero instructions.
// USE CAREFULLY!
//go:nosplit
func NoEscape(p unsafe.Pointer) unsafe.Pointer {
	x := uintptr(p)
	return unsafe.Pointer(x ^ 0)
}

func UnsafeCastString(str string) []byte {
	bytes := make([]byte, 0)
	stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&str))
	sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&bytes))
	sliceHeader.Data = stringHeader.Data
	sliceHeader.Cap = stringHeader.Len
	sliceHeader.Len = stringHeader.Len
	runtime.KeepAlive(str)
	return bytes
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"fmt"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"

	"git.zxq.co/ripple/rippleapi/common"
	"git.zxq.co/ripple/schiavolib"
	"github.com/asaskevich/govalidator"
	"github.com/gin-gonic/gin"
)

func register(c *gin.Context) {
	// todo: check registrations disabled
	if c.Query("stopsign") != "1" {
		u, _ := tryBotnets(c)
		if u != "" {
			simple(c, getSimpleByFilename("register/elmo.html"), nil, map[string]interface{}{
				"Username": u,
			})
			return
		}
	}
	registerResp(c)
}

func registerSubmit(c *gin.Context) {
	// check registrations are enabled
	var enabled bool
	db.QueryRow("SELECT value_int FROM system_settings WHERE name = 'registrations_enabled'").Scan(&enabled)
	if !enabled {
		registerResp(c, errorMessage{"Sorry, it's not possible to register at the moment. Please try again later."})
		return
	}

	// check username is valid by our criteria
	username := strings.TrimSpace(c.PostForm("username"))
	if !usernameRegex.MatchString(username) {
		registerResp(c, errorMessage{"Your username must contain alphanumerical characters, spaces, or any of _[]-"})
		return
	}

	// check whether an username is e.g. cookiezi, shigetora, peppy, wubwoofwolf, loctav
	if in(strings.ToLower(username), forbiddenUsernames) {
		registerResp(c, errorMessage{"You're not allowed to register with that username."})
		return
	}

	// check email is valid
	if !govalidator.IsEmail(c.PostForm("email")) {
		registerResp(c, errorMessage{"Please pass a valid email address."})
		return
	}

	// passwords check (too short/too common)
	if x := validatePassword(c.PostForm("password")); x != "" {
		registerResp(c, errorMessage{x})
		return
	}

	// usernames with both _ and spaces are not allowed
	if strings.Contains(username, "_") && strings.Contains(username, " ") {
		registerResp(c, errorMessage{"An username can't contain both underscores and spaces."})
		return
	}

	// check whether username already exists
	if db.QueryRow("SELECT 1 FROM users WHERE username_safe = ?", safeUsername(username)).
		Scan(new(int)) != sql.ErrNoRows {
		registerResp(c, errorMessage{"An user with that username already exists!"})
		return
	}

	// check whether an user with that email already exists
	if db.QueryRow("SELECT 1 FROM users WHERE email = ?", c.PostForm("email")).
		Scan(new(int)) != sql.ErrNoRows {
		registerResp(c, errorMessage{"An user with that email address already exists!"})
		return
	}

	// recaptcha verify
	if config.RecaptchaPrivate != "" && !recaptchaCheck(c) {
		registerResp(c, errorMessage{"Captcha is invalid."})
		return
	}

	uMulti, criteria := tryBotnets(c)
	if criteria != "" {
		schiavo.CMs.Send(
			fmt.Sprintf(
				"User **%s** registered with the same %s as %s (%s/u/%s). **POSSIBLE MULTIACCOUNT!!!**. Waiting for ingame verification...",
				username, criteria, uMulti, config.BaseURL, url.QueryEscape(uMulti),
			),
		)
	}

	// The actual registration.
	pass, err := generatePassword(c.PostForm("password"))
	if err != nil {
		resp500(c)
		return
	}

	res, _ := db.Exec(`INSERT INTO users(username, username_safe, password_md5, salt, email, register_datetime, privileges, password_version)
							  VALUES (?,        ?,             ?,            '',   ?,     ?,                 ?,          2);`,
		username, safeUsername(username), pass, c.PostForm("email"), time.Now().Unix(), common.UserPrivilegePendingVerification)
	lid, _ := res.LastInsertId()

	db.Exec("INSERT INTO `users_stats`(id, username, user_color, user_style, ranked_score_std, playcount_std, total_score_std, ranked_score_taiko, playcount_taiko, total_score_taiko, ranked_score_ctb, playcount_ctb, total_score_ctb, ranked_score_mania, playcount_mania, total_score_mania) VALUES (?, ?, 'black', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);", lid, username)

	for _, m := range []string{"std", "taiko", "ctb", "mania"} {
		var lastPosition int
		db.QueryRow("SELECT position FROM leaderboard_" + m + " ORDER BY position DESC LIMIT 1").Scan(&lastPosition)
		db.Exec("INSERT INTO leaderboard_"+m+" (position, user, v) VALUES (?, ?, ?)", lastPosition+1, lid, 0)
	}

	schiavo.CMs.Send(fmt.Sprintf("User (**%s** | %s) registered from %s", username, c.PostForm("email"), clientIP(c)))

	setYCookie(int(lid), c)
	logIP(c, int(lid))

	addMessage(c, successMessage{"You have been successfully registered on Ripple! You now need to verify your account."})
	getSession(c).Save()
	c.Redirect(302, "/register/verify?u="+strconv.Itoa(int(lid)))
}

func registerResp(c *gin.Context, messages ...message) {
	resp(c, 200, "register/register.html", &baseTemplateData{
		TitleBar: "Register",
		Scripts:  []string{"https://www.google.com/recaptcha/api.js"},
		Messages: messages,
		FormData: normaliseURLValues(c.Request.PostForm),
	})
}

func verifyAccount(c *gin.Context) {
	i, ret := checkUInQS(c)
	if ret {
		return
	}

	sess := getSession(c)
	var rPrivileges uint64
	db.Get(&rPrivileges, "SELECT privileges FROM users WHERE id = ?", i)
	if common.UserPrivileges(rPrivileges)&common.UserPrivilegePendingVerification == 0 {
		addMessage(c, warningMessage{"Nope."})
		sess.Save()
		c.Redirect(302, "/")
		return
	}

	resp(c, 200, "register/verify.html", &baseTemplateData{
		TitleBar: "Verify account",
	})
}

func welcome(c *gin.Context) {
	i, ret := checkUInQS(c)
	if ret {
		return
	}

	var rPrivileges uint64
	db.Get(&rPrivileges, "SELECT privileges FROM users WHERE id = ?", i)
	if common.UserPrivileges(rPrivileges)&common.UserPrivilegePendingVerification > 0 {
		c.Redirect(302, "/register/verify?u="+c.Query("u"))
		return
	}

	t := "Welcome!"
	if common.UserPrivileges(rPrivileges)&common.UserPrivilegeNormal == 0 {
		// if the user has no UserNormal, it means they're banned = they multiaccounted
		t = "Welcome back!"
	}

	resp(c, 200, "register/welcome.html", &baseTemplateData{
		TitleBar: t,
	})
}

// Check User In Query Is Same As User In Y Cookie
func checkUInQS(c *gin.Context) (int, bool) {
	sess := getSession(c)

	i, _ := strconv.Atoi(c.Query("u"))
	y, _ := c.Cookie("y")
	err := db.QueryRow("SELECT 1 FROM identity_tokens WHERE token = ? AND userid = ?", y, i).Scan(new(int))
	if err == sql.ErrNoRows {
		addMessage(c, warningMessage{"Nope."})
		sess.Save()
		c.Redirect(302, "/")
		return 0, true
	}
	return i, false
}

func tryBotnets(c *gin.Context) (string, string) {
	var username string

	err := db.QueryRow("SELECT u.username FROM ip_user i LEFT JOIN users u ON u.id = i.userid WHERE i.ip = ?", clientIP(c)).Scan(&username)
	if err != nil {
		c.Error(err)
		return "", ""
	}
	if username != "" {
		return username, "IP"
	}

	cook, _ := c.Cookie("y")
	err = db.QueryRow("SELECT u.username FROM identity_tokens i LEFT JOIN users u ON u.id = i.userid WHERE i.token = ?",
		cook).Scan(&username)
	if err != nil {
		c.Error(err)
		return "", ""
	}
	if username != "" {
		return username, "username"
	}

	return "", ""
}

func in(s string, ss []string) bool {
	for _, x := range ss {
		if x == s {
			return true
		}
	}
	return false
}

var usernameRegex = regexp.MustCompile(`^[A-Za-z0-9 _\[\]-]{2,15}$`)
var forbiddenUsernames = []string{
	"peppy",
	"rrtyui",
	"cookiezi",
	"azer",
	"loctav",
	"banchobot",
	"happystick",
	"doomsday",
	"sharingan33",
	"andrea",
	"cptnxn",
	"reimu-desu",
	"hvick225",
	"_index",
	"my aim sucks",
	"kynan",
	"rafis",
	"sayonara-bye",
	"thelewa",
	"wubwoofwolf",
	"millhioref",
	"tom94",
	"tillerino",
	"clsw",
	"spectator",
	"exgon",
	"axarious",
	"angelsim",
	"recia",
	"nara",
	"emperorpenguin83",
	"bikko",
	"xilver",
	"vettel",
	"kuu01",
	"_yu68",
	"tasuke912",
	"dusk",
	"ttobas",
	"velperk",
	"jakads",
	"jhlee0133",
	"abcdullah",
	"yuko-",
	"entozer",
	"hdhr",
	"ekoro",
	"snowwhite",
	"osuplayer111",
	"musty",
	"nero",
	"elysion",
	"ztrot",
	"koreapenguin",
	"fort",
	"asphyxia",
	"niko",
	"shigetora",
}
<commit_msg>Do not allow logged in users to access registration-related pages<commit_after>package main

import (
	"database/sql"
	"fmt"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"

	"git.zxq.co/ripple/rippleapi/common"
	"git.zxq.co/ripple/schiavolib"
	"github.com/asaskevich/govalidator"
	"github.com/gin-gonic/gin"
)

func register(c *gin.Context) {
	if getContext(c).User.ID != 0 {
		resp403(c)
		return
	}
	// todo: check registrations disabled
	if c.Query("stopsign") != "1" {
		u, _ := tryBotnets(c)
		if u != "" {
			simple(c, getSimpleByFilename("register/elmo.html"), nil, map[string]interface{}{
				"Username": u,
			})
			return
		}
	}
	registerResp(c)
}

func registerSubmit(c *gin.Context) {
	if getContext(c).User.ID != 0 {
		resp403(c)
		return
	}
	// check registrations are enabled
	var enabled bool
	db.QueryRow("SELECT value_int FROM system_settings WHERE name = 'registrations_enabled'").Scan(&enabled)
	if !enabled {
		registerResp(c, errorMessage{"Sorry, it's not possible to register at the moment. Please try again later."})
		return
	}

	// check username is valid by our criteria
	username := strings.TrimSpace(c.PostForm("username"))
	if !usernameRegex.MatchString(username) {
		registerResp(c, errorMessage{"Your username must contain alphanumerical characters, spaces, or any of _[]-"})
		return
	}

	// check whether an username is e.g. cookiezi, shigetora, peppy, wubwoofwolf, loctav
	if in(strings.ToLower(username), forbiddenUsernames) {
		registerResp(c, errorMessage{"You're not allowed to register with that username."})
		return
	}

	// check email is valid
	if !govalidator.IsEmail(c.PostForm("email")) {
		registerResp(c, errorMessage{"Please pass a valid email address."})
		return
	}

	// passwords check (too short/too common)
	if x := validatePassword(c.PostForm("password")); x != "" {
		registerResp(c, errorMessage{x})
		return
	}

	// usernames with both _ and spaces are not allowed
	if strings.Contains(username, "_") && strings.Contains(username, " ") {
		registerResp(c, errorMessage{"An username can't contain both underscores and spaces."})
		return
	}

	// check whether username already exists
	if db.QueryRow("SELECT 1 FROM users WHERE username_safe = ?", safeUsername(username)).
		Scan(new(int)) != sql.ErrNoRows {
		registerResp(c, errorMessage{"An user with that username already exists!"})
		return
	}

	// check whether an user with that email already exists
	if db.QueryRow("SELECT 1 FROM users WHERE email = ?", c.PostForm("email")).
		Scan(new(int)) != sql.ErrNoRows {
		registerResp(c, errorMessage{"An user with that email address already exists!"})
		return
	}

	// recaptcha verify
	if config.RecaptchaPrivate != "" && !recaptchaCheck(c) {
		registerResp(c, errorMessage{"Captcha is invalid."})
		return
	}

	uMulti, criteria := tryBotnets(c)
	if criteria != "" {
		schiavo.CMs.Send(
			fmt.Sprintf(
				"User **%s** registered with the same %s as %s (%s/u/%s). **POSSIBLE MULTIACCOUNT!!!**. Waiting for ingame verification...",
				username, criteria, uMulti, config.BaseURL, url.QueryEscape(uMulti),
			),
		)
	}

	// The actual registration.
	pass, err := generatePassword(c.PostForm("password"))
	if err != nil {
		resp500(c)
		return
	}

	res, _ := db.Exec(`INSERT INTO users(username, username_safe, password_md5, salt, email, register_datetime, privileges, password_version)
							  VALUES (?,        ?,             ?,            '',   ?,     ?,                 ?,          2);`,
		username, safeUsername(username), pass, c.PostForm("email"), time.Now().Unix(), common.UserPrivilegePendingVerification)
	lid, _ := res.LastInsertId()

	db.Exec("INSERT INTO `users_stats`(id, username, user_color, user_style, ranked_score_std, playcount_std, total_score_std, ranked_score_taiko, playcount_taiko, total_score_taiko, ranked_score_ctb, playcount_ctb, total_score_ctb, ranked_score_mania, playcount_mania, total_score_mania) VALUES (?, ?, 'black', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);", lid, username)

	for _, m := range []string{"std", "taiko", "ctb", "mania"} {
		var lastPosition int
		db.QueryRow("SELECT position FROM leaderboard_" + m + " ORDER BY position DESC LIMIT 1").Scan(&lastPosition)
		db.Exec("INSERT INTO leaderboard_"+m+" (position, user, v) VALUES (?, ?, ?)", lastPosition+1, lid, 0)
	}

	schiavo.CMs.Send(fmt.Sprintf("User (**%s** | %s) registered from %s", username, c.PostForm("email"), clientIP(c)))

	setYCookie(int(lid), c)
	logIP(c, int(lid))

	addMessage(c, successMessage{"You have been successfully registered on Ripple! You now need to verify your account."})
	getSession(c).Save()
	c.Redirect(302, "/register/verify?u="+strconv.Itoa(int(lid)))
}

func registerResp(c *gin.Context, messages ...message) {
	resp(c, 200, "register/register.html", &baseTemplateData{
		TitleBar: "Register",
		Scripts:  []string{"https://www.google.com/recaptcha/api.js"},
		Messages: messages,
		FormData: normaliseURLValues(c.Request.PostForm),
	})
}

func verifyAccount(c *gin.Context) {
	if getContext(c).User.ID != 0 {
		resp403(c)
		return
	}

	i, ret := checkUInQS(c)
	if ret {
		return
	}

	sess := getSession(c)
	var rPrivileges uint64
	db.Get(&rPrivileges, "SELECT privileges FROM users WHERE id = ?", i)
	if common.UserPrivileges(rPrivileges)&common.UserPrivilegePendingVerification == 0 {
		addMessage(c, warningMessage{"Nope."})
		sess.Save()
		c.Redirect(302, "/")
		return
	}

	resp(c, 200, "register/verify.html", &baseTemplateData{
		TitleBar: "Verify account",
	})
}

func welcome(c *gin.Context) {
	if getContext(c).User.ID != 0 {
		resp403(c)
		return
	}

	i, ret := checkUInQS(c)
	if ret {
		return
	}

	var rPrivileges uint64
	db.Get(&rPrivileges, "SELECT privileges FROM users WHERE id = ?", i)
	if common.UserPrivileges(rPrivileges)&common.UserPrivilegePendingVerification > 0 {
		c.Redirect(302, "/register/verify?u="+c.Query("u"))
		return
	}

	t := "Welcome!"
	if common.UserPrivileges(rPrivileges)&common.UserPrivilegeNormal == 0 {
		// if the user has no UserNormal, it means they're banned = they multiaccounted
		t = "Welcome back!"
	}

	resp(c, 200, "register/welcome.html", &baseTemplateData{
		TitleBar: t,
	})
}

// Check User In Query Is Same As User In Y Cookie
func checkUInQS(c *gin.Context) (int, bool) {
	sess := getSession(c)

	i, _ := strconv.Atoi(c.Query("u"))
	y, _ := c.Cookie("y")
	err := db.QueryRow("SELECT 1 FROM identity_tokens WHERE token = ? AND userid = ?", y, i).Scan(new(int))
	if err == sql.ErrNoRows {
		addMessage(c, warningMessage{"Nope."})
		sess.Save()
		c.Redirect(302, "/")
		return 0, true
	}
	return i, false
}

func tryBotnets(c *gin.Context) (string, string) {
	var username string

	err := db.QueryRow("SELECT u.username FROM ip_user i LEFT JOIN users u ON u.id = i.userid WHERE i.ip = ?", clientIP(c)).Scan(&username)
	if err != nil {
		c.Error(err)
		return "", ""
	}
	if username != "" {
		return username, "IP"
	}

	cook, _ := c.Cookie("y")
	err = db.QueryRow("SELECT u.username FROM identity_tokens i LEFT JOIN users u ON u.id = i.userid WHERE i.token = ?",
		cook).Scan(&username)
	if err != nil {
		c.Error(err)
		return "", ""
	}
	if username != "" {
		return username, "username"
	}

	return "", ""
}

func in(s string, ss []string) bool {
	for _, x := range ss {
		if x == s {
			return true
		}
	}
	return false
}

var usernameRegex = regexp.MustCompile(`^[A-Za-z0-9 _\[\]-]{2,15}$`)
var forbiddenUsernames = []string{
	"peppy",
	"rrtyui",
	"cookiezi",
	"azer",
	"loctav",
	"banchobot",
	"happystick",
	"doomsday",
	"sharingan33",
	"andrea",
	"cptnxn",
	"reimu-desu",
	"hvick225",
	"_index",
	"my aim sucks",
	"kynan",
	"rafis",
	"sayonara-bye",
	"thelewa",
	"wubwoofwolf",
	"millhioref",
	"tom94",
	"tillerino",
	"clsw",
	"spectator",
	"exgon",
	"axarious",
	"angelsim",
	"recia",
	"nara",
	"emperorpenguin83",
	"bikko",
	"xilver",
	"vettel",
	"kuu01",
	"_yu68",
	"tasuke912",
	"dusk",
	"ttobas",
	"velperk",
	"jakads",
	"jhlee0133",
	"abcdullah",
	"yuko-",
	"entozer",
	"hdhr",
	"ekoro",
	"snowwhite",
	"osuplayer111",
	"musty",
	"nero",
	"elysion",
	"ztrot",
	"koreapenguin",
	"fort",
	"asphyxia",
	"niko",
	"shigetora",
}
<|endoftext|>


<commit_before>package of10

import . "github.com/oshothebig/goflow/openflow"

type ActionType uint16

const (
	OFPAT_OUTPUT ActionType = iota
	OFPAT_SET_VLAN_VID
	OFPAT_SET_VLAN_PCP
	OFPAT_SET_STRIP_VLAN
	OFPAT_SET_DL_SRC
	OFPAT_SET_DL_DST
	OFPAT_SET_NW_SRC
	OFPAT_SET_NW_DST
	OFPAT_SET_NW_TOS
	OFPAT_SET_TP_SRC
	OFPAT_SET_TP_DST
	OFPAT_ENQUEUE
	OFPAT_VENDOR ActionType = 0xffff
)

var ActionTypes = struct {
	Output        ActionType
	SetVlanId     ActionType
	SetVlanPcp    ActionType
	StripVlan     ActionType
	SetEtherSrc   ActionType
	SetEtherDst   ActionType
	SetIpSrc      ActionType
	SetIpDst      ActionType
	SetIpTos      ActionType
	SetNetworkSrc ActionType
	SetNetworkDst ActionType
	Enqueue       ActionType
	Vendor        ActionType
}{
	OFPAT_OUTPUT,
	OFPAT_SET_VLAN_VID,
	OFPAT_SET_VLAN_PCP,
	OFPAT_SET_STRIP_VLAN,
	OFPAT_SET_DL_SRC,
	OFPAT_SET_DL_DST,
	OFPAT_SET_NW_SRC,
	OFPAT_SET_NW_DST,
	OFPAT_SET_NW_TOS,
	OFPAT_SET_TP_SRC,
	OFPAT_SET_TP_DST,
	OFPAT_ENQUEUE,
	OFPAT_VENDOR,
}

type Action interface {
	Packetizable
	GetType() ActionType
}

type ActionHeader struct {
	Type   ActionType
	Length uint16
}

func (header *ActionHeader) GetType() ActionType {
	return header.Type
}

type SendOutPort struct {
	ActionHeader
	Port      PortNumber
	MaxLength uint16
}

type Enqueue struct {
	ActionHeader
	Port    PortNumber
	pad     [6]uint8
	QueueId uint32
}
<commit_msg>Declare SetVlanVid struct<commit_after>package of10

import . "github.com/oshothebig/goflow/openflow"

type ActionType uint16

const (
	OFPAT_OUTPUT ActionType = iota
	OFPAT_SET_VLAN_VID
	OFPAT_SET_VLAN_PCP
	OFPAT_SET_STRIP_VLAN
	OFPAT_SET_DL_SRC
	OFPAT_SET_DL_DST
	OFPAT_SET_NW_SRC
	OFPAT_SET_NW_DST
	OFPAT_SET_NW_TOS
	OFPAT_SET_TP_SRC
	OFPAT_SET_TP_DST
	OFPAT_ENQUEUE
	OFPAT_VENDOR ActionType = 0xffff
)

var ActionTypes = struct {
	Output        ActionType
	SetVlanId     ActionType
	SetVlanPcp    ActionType
	StripVlan     ActionType
	SetEtherSrc   ActionType
	SetEtherDst   ActionType
	SetIpSrc      ActionType
	SetIpDst      ActionType
	SetIpTos      ActionType
	SetNetworkSrc ActionType
	SetNetworkDst ActionType
	Enqueue       ActionType
	Vendor        ActionType
}{
	OFPAT_OUTPUT,
	OFPAT_SET_VLAN_VID,
	OFPAT_SET_VLAN_PCP,
	OFPAT_SET_STRIP_VLAN,
	OFPAT_SET_DL_SRC,
	OFPAT_SET_DL_DST,
	OFPAT_SET_NW_SRC,
	OFPAT_SET_NW_DST,
	OFPAT_SET_NW_TOS,
	OFPAT_SET_TP_SRC,
	OFPAT_SET_TP_DST,
	OFPAT_ENQUEUE,
	OFPAT_VENDOR,
}

type Action interface {
	Packetizable
	GetType() ActionType
}

type ActionHeader struct {
	Type   ActionType
	Length uint16
}

func (header *ActionHeader) GetType() ActionType {
	return header.Type
}

type SendOutPort struct {
	ActionHeader
	Port      PortNumber
	MaxLength uint16
}

type Enqueue struct {
	ActionHeader
	Port    PortNumber
	pad     [6]uint8
	QueueId uint32
}

type SetVlanVid struct {
	ActionHeader
	VlanId VlanId
	pad    [2]uint32
}
<|endoftext|>