<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/build"
	"go/parser"
	"go/token"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"testing"
)

// Set --regenerate to regenerate the golden files.
var regenerate = flag.Bool("regenerate", false, "regenerate golden files")

// When the environment variable RUN_AS_PROTOC_GEN_GO is set, we skip running
// tests and instead act as protoc-gen-go. This allows the test binary to
// pass itself to protoc.
func init() {
	if os.Getenv("RUN_AS_PROTOC_GEN_GO") != "" {
		main()
		os.Exit(0)
	}
}

func TestGolden(t *testing.T) {
	workdir, err := ioutil.TempDir("", "proto-test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(workdir)

	// Find all the proto files we need to compile. We assume that each directory
	// contains the files for a single package.
	supportTypeAliases := hasReleaseTag("1.9")
	packages := map[string][]string{}
	err = filepath.Walk("testdata", func(path string, info os.FileInfo, err error) error {
		if filepath.Base(path) == "import_public" && !supportTypeAliases {
			// Public imports require type alias support.
			return filepath.SkipDir
		}
		if !strings.HasSuffix(path, ".proto") {
			return nil
		}
		dir := filepath.Dir(path)
		packages[dir] = append(packages[dir], path)
		return nil
	})
	if err != nil {
		t.Fatal(err)
	}

	// Compile each package, using this binary as protoc-gen-go.
	for _, sources := range packages {
		args := []string{"-Itestdata", "--go_out=plugins=grpc,paths=source_relative:" + workdir}
		args = append(args, sources...)
		protoc(t, args)
	}

	// Compare each generated file to the golden version.
	filepath.Walk(workdir, func(genPath string, info os.FileInfo, _ error) error {
		if info.IsDir() {
			return nil
		}

		// For each generated file, figure out the path to the corresponding
		// golden file in the testdata directory.
		relPath, err := filepath.Rel(workdir, genPath)
		if err != nil {
			t.Errorf("filepath.Rel(%q, %q): %v", workdir, genPath, err)
			return nil
		}
		if filepath.SplitList(relPath)[0] == ".." {
			t.Errorf("generated file %q is not relative to %q", genPath, workdir)
		}
		goldenPath := filepath.Join("testdata", relPath)

		got, err := ioutil.ReadFile(genPath)
		if err != nil {
			t.Error(err)
			return nil
		}
		if *regenerate {
			// If --regenerate set, just rewrite the golden files.
			err := ioutil.WriteFile(goldenPath, got, 0666)
			if err != nil {
				t.Error(err)
			}
			return nil
		}

		want, err := ioutil.ReadFile(goldenPath)
		if err != nil {
			t.Error(err)
			return nil
		}

		want = fdescRE.ReplaceAll(want, nil)
		got = fdescRE.ReplaceAll(got, nil)
		if bytes.Equal(got, want) {
			return nil
		}

		cmd := exec.Command("diff", "-u", goldenPath, genPath)
		out, _ := cmd.CombinedOutput()
		t.Errorf("golden file differs: %v\n%v", relPath, string(out))
		return nil
	})
}

var fdescRE = regexp.MustCompile(`(?ms)^var fileDescriptor.*}`)

// Source files used by TestParameters.
const (
	aProto = `
syntax = "proto3";
package test.alpha;
option go_package = "package/alpha";
import "beta/b.proto";
message M { test.beta.M field = 1; }`

	bProto = `
syntax = "proto3";
package test.beta;
// no go_package option
message M {}`
)

func TestParameters(t *testing.T) {
	for _, test := range []struct {
		parameters   string
		wantFiles    map[string]bool
		wantImportsA map[string]bool
		wantPackageA string
		wantPackageB string
	}{{
		parameters: "",
		wantFiles: map[string]bool{
			"package/alpha/a.pb.go": true,
			"beta/b.pb.go":          true,
		},
		wantPackageA: "alpha",
		wantPackageB: "test_beta",
		wantImportsA: map[string]bool{
			"github.com/golang/protobuf/proto": true,
			"beta": true,
		},
	}, {
		parameters: "import_prefix=prefix",
		wantFiles: map[string]bool{
			"package/alpha/a.pb.go": true,
			"beta/b.pb.go":          true,
		},
		wantPackageA: "alpha",
		wantPackageB: "test_beta",
		wantImportsA: map[string]bool{
			// This really doesn't seem like useful behavior.
			"prefixgithub.com/golang/protobuf/proto": true,
			"prefixbeta":                             true,
		},
	}, {
		// import_path only affects the 'package' line.
		parameters:   "import_path=import/path/of/pkg",
		wantPackageA: "alpha",
		wantPackageB: "pkg",
		wantFiles: map[string]bool{
			"package/alpha/a.pb.go": true,
			"beta/b.pb.go":          true,
		},
	}, {
		parameters: "Mbeta/b.proto=package/gamma",
		wantFiles: map[string]bool{
			"package/alpha/a.pb.go": true,
			"beta/b.pb.go":          true,
		},
		wantPackageA: "alpha",
		wantPackageB: "test_beta",
		wantImportsA: map[string]bool{
			"github.com/golang/protobuf/proto": true,
			// Rewritten by the M parameter.
			"package/gamma": true,
		},
	}, {
		parameters: "import_prefix=prefix,Mbeta/b.proto=package/gamma",
		wantFiles: map[string]bool{
			"package/alpha/a.pb.go": true,
			"beta/b.pb.go":          true,
		},
		wantPackageA: "alpha",
		wantPackageB: "test_beta",
		wantImportsA: map[string]bool{
			// import_prefix applies after M.
			"prefixpackage/gamma": true,
		},
	}, {
		parameters: "paths=source_relative",
		wantFiles: map[string]bool{
			"alpha/a.pb.go": true,
			"beta/b.pb.go":  true,
		},
		wantPackageA: "alpha",
		wantPackageB: "test_beta",
	}, {
		parameters: "paths=source_relative,import_prefix=prefix",
		wantFiles: map[string]bool{
			// import_prefix doesn't affect filenames.
			"alpha/a.pb.go": true,
			"beta/b.pb.go":  true,
		},
		wantPackageA: "alpha",
		wantPackageB: "test_beta",
	}} {
		name := test.parameters
		if name == "" {
			name = "defaults"
		}
		// TODO: Switch to t.Run when we no longer support Go 1.6.
		t.Logf("TEST: %v", name)
		workdir, err := ioutil.TempDir("", "proto-test")
		if err != nil {
			t.Fatal(err)
		}
		defer os.RemoveAll(workdir)

		for _, dir := range []string{"alpha", "beta", "out"} {
			if err := os.MkdirAll(filepath.Join(workdir, dir), 0777); err != nil {
				t.Fatal(err)
			}
		}

		if err := ioutil.WriteFile(filepath.Join(workdir, "alpha", "a.proto"), []byte(aProto), 0666); err != nil {
			t.Fatal(err)
		}

		if err := ioutil.WriteFile(filepath.Join(workdir, "beta", "b.proto"), []byte(bProto), 0666); err != nil {
			t.Fatal(err)
		}

		protoc(t, []string{
			"-I" + workdir,
			"--go_out=" + test.parameters + ":" + filepath.Join(workdir, "out"),
			filepath.Join(workdir, "alpha", "a.proto"),
		})
		protoc(t, []string{
			"-I" + workdir,
			"--go_out=" + test.parameters + ":" + filepath.Join(workdir, "out"),
			filepath.Join(workdir, "beta", "b.proto"),
		})

		contents := make(map[string]string)
		gotFiles := make(map[string]bool)
		outdir := filepath.Join(workdir, "out")
		filepath.Walk(outdir, func(p string, info os.FileInfo, _ error) error {
			if info.IsDir() {
				return nil
			}
			base := filepath.Base(p)
			if base == "a.pb.go" || base == "b.pb.go" {
				b, err := ioutil.ReadFile(p)
				if err != nil {
					t.Fatal(err)
				}
				contents[base] = string(b)
			}
			relPath, _ := filepath.Rel(outdir, p)
			gotFiles[relPath] = true
			return nil
		})
		for got := range gotFiles {
			if runtime.GOOS == "windows" {
				got = filepath.ToSlash(got)
			}
			if !test.wantFiles[got] {
				t.Errorf("unexpected output file: %v", got)
			}
		}
		for want := range test.wantFiles {
			if runtime.GOOS == "windows" {
				want = filepath.FromSlash(want)
			}
			if !gotFiles[want] {
				t.Errorf("missing output file:    %v", want)
			}
		}
		gotPackageA, gotImports, err := parseFile(contents["a.pb.go"])
		if err != nil {
			t.Fatal(err)
		}
		gotPackageB, _, err := parseFile(contents["b.pb.go"])
		if err != nil {
			t.Fatal(err)
		}
		if got, want := gotPackageA, test.wantPackageA; want != got {
			t.Errorf("output file a.pb.go is package %q, want %q", got, want)
		}
		if got, want := gotPackageB, test.wantPackageB; want != got {
			t.Errorf("output file b.pb.go is package %q, want %q", got, want)
		}
		missingImport := false
	WantImport:
		for want := range test.wantImportsA {
			for _, imp := range gotImports {
				if `"`+want+`"` == imp {
					continue WantImport
				}
			}
			t.Errorf("output file a.pb.go does not contain expected import %q", want)
			missingImport = true
		}
		if missingImport {
			t.Error("got imports:")
			for _, imp := range gotImports {
				t.Errorf("  %v", imp)
			}
		}
	}
}

func TestPackageComment(t *testing.T) {
	workdir, err := ioutil.TempDir("", "proto-test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(workdir)

	var packageRE = regexp.MustCompile(`(?m)^package .*`)

	for i, test := range []struct {
		goPackageOption string
		wantPackage     string
	}{{
		goPackageOption: ``,
		wantPackage:     `package proto_package`,
	}, {
		goPackageOption: `option go_package = "go_package";`,
		wantPackage:     `package go_package`,
	}, {
		goPackageOption: `option go_package = "import/path/of/go_package";`,
		wantPackage:     `package go_package // import "import/path/of/go_package"`,
	}, {
		goPackageOption: `option go_package = "import/path/of/something;go_package";`,
		wantPackage:     `package go_package // import "import/path/of/something"`,
	}, {
		goPackageOption: `option go_package = "import_path;go_package";`,
		wantPackage:     `package go_package // import "import_path"`,
	}} {
		srcName := filepath.Join(workdir, fmt.Sprintf("%d.proto", i))
		tgtName := filepath.Join(workdir, fmt.Sprintf("%d.pb.go", i))

		buf := &bytes.Buffer{}
		fmt.Fprintln(buf, `syntax = "proto3";`)
		fmt.Fprintln(buf, `package proto_package;`)
		fmt.Fprintln(buf, test.goPackageOption)
		if err := ioutil.WriteFile(srcName, buf.Bytes(), 0666); err != nil {
			t.Fatal(err)
		}

		protoc(t, []string{"-I" + workdir, "--go_out=paths=source_relative:" + workdir, srcName})

		out, err := ioutil.ReadFile(tgtName)
		if err != nil {
			t.Fatal(err)
		}

		pkg := packageRE.Find(out)
		if pkg == nil {
			t.Errorf("generated .pb.go contains no package line\n\nsource:\n%v\n\noutput:\n%v", buf.String(), string(out))
			continue
		}

		if got, want := string(pkg), test.wantPackage; got != want {
			t.Errorf("unexpected package statement with go_package = %q\n got: %v\nwant: %v", test.goPackageOption, got, want)
		}
	}
}

// parseFile returns a file's package name and a list of all packages it imports.
func parseFile(source string) (packageName string, imports []string, err error) {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, "<source>", source, parser.ImportsOnly)
	if err != nil {
		return "", nil, err
	}
	for _, imp := range f.Imports {
		imports = append(imports, imp.Path.Value)
	}
	return f.Name.Name, imports, nil
}

func protoc(t *testing.T, args []string) {
	cmd := exec.Command("protoc", "--plugin=protoc-gen-go="+os.Args[0])
	cmd.Args = append(cmd.Args, args...)
	// We set the RUN_AS_PROTOC_GEN_GO environment variable to indicate that
	// the subprocess should act as a proto compiler rather than a test.
	cmd.Env = append(os.Environ(), "RUN_AS_PROTOC_GEN_GO=1")
	out, err := cmd.CombinedOutput()
	if len(out) > 0 || err != nil {
		t.Log("RUNNING: ", strings.Join(cmd.Args, " "))
	}
	if len(out) > 0 {
		t.Log(string(out))
	}
	if err != nil {
		t.Fatalf("protoc: %v", err)
	}
}

func hasReleaseTag(want string) bool {
	for _, tag := range build.Default.ReleaseTags {
		if tag == want {
			return true
		}
	}
	return false
}
<commit_msg>protoc-gen-go: fix release tag in golden_test (#590)<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/build"
	"go/parser"
	"go/token"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"testing"
)

// Set --regenerate to regenerate the golden files.
var regenerate = flag.Bool("regenerate", false, "regenerate golden files")

// When the environment variable RUN_AS_PROTOC_GEN_GO is set, we skip running
// tests and instead act as protoc-gen-go. This allows the test binary to
// pass itself to protoc.
func init() {
	if os.Getenv("RUN_AS_PROTOC_GEN_GO") != "" {
		main()
		os.Exit(0)
	}
}

func TestGolden(t *testing.T) {
	workdir, err := ioutil.TempDir("", "proto-test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(workdir)

	// Find all the proto files we need to compile. We assume that each directory
	// contains the files for a single package.
	supportTypeAliases := hasReleaseTag("go1.9")
	packages := map[string][]string{}
	err = filepath.Walk("testdata", func(path string, info os.FileInfo, err error) error {
		if filepath.Base(path) == "import_public" && !supportTypeAliases {
			// Public imports require type alias support.
			return filepath.SkipDir
		}
		if !strings.HasSuffix(path, ".proto") {
			return nil
		}
		dir := filepath.Dir(path)
		packages[dir] = append(packages[dir], path)
		return nil
	})
	if err != nil {
		t.Fatal(err)
	}

	// Compile each package, using this binary as protoc-gen-go.
	for _, sources := range packages {
		args := []string{"-Itestdata", "--go_out=plugins=grpc,paths=source_relative:" + workdir}
		args = append(args, sources...)
		protoc(t, args)
	}

	// Compare each generated file to the golden version.
	filepath.Walk(workdir, func(genPath string, info os.FileInfo, _ error) error {
		if info.IsDir() {
			return nil
		}

		// For each generated file, figure out the path to the corresponding
		// golden file in the testdata directory.
		relPath, err := filepath.Rel(workdir, genPath)
		if err != nil {
			t.Errorf("filepath.Rel(%q, %q): %v", workdir, genPath, err)
			return nil
		}
		if filepath.SplitList(relPath)[0] == ".." {
			t.Errorf("generated file %q is not relative to %q", genPath, workdir)
		}
		goldenPath := filepath.Join("testdata", relPath)

		got, err := ioutil.ReadFile(genPath)
		if err != nil {
			t.Error(err)
			return nil
		}
		if *regenerate {
			// If --regenerate set, just rewrite the golden files.
			err := ioutil.WriteFile(goldenPath, got, 0666)
			if err != nil {
				t.Error(err)
			}
			return nil
		}

		want, err := ioutil.ReadFile(goldenPath)
		if err != nil {
			t.Error(err)
			return nil
		}

		want = fdescRE.ReplaceAll(want, nil)
		got = fdescRE.ReplaceAll(got, nil)
		if bytes.Equal(got, want) {
			return nil
		}

		cmd := exec.Command("diff", "-u", goldenPath, genPath)
		out, _ := cmd.CombinedOutput()
		t.Errorf("golden file differs: %v\n%v", relPath, string(out))
		return nil
	})
}

var fdescRE = regexp.MustCompile(`(?ms)^var fileDescriptor.*}`)

// Source files used by TestParameters.
const (
	aProto = `
syntax = "proto3";
package test.alpha;
option go_package = "package/alpha";
import "beta/b.proto";
message M { test.beta.M field = 1; }`

	bProto = `
syntax = "proto3";
package test.beta;
// no go_package option
message M {}`
)

func TestParameters(t *testing.T) {
	for _, test := range []struct {
		parameters   string
		wantFiles    map[string]bool
		wantImportsA map[string]bool
		wantPackageA string
		wantPackageB string
	}{{
		parameters: "",
		wantFiles: map[string]bool{
			"package/alpha/a.pb.go": true,
			"beta/b.pb.go":          true,
		},
		wantPackageA: "alpha",
		wantPackageB: "test_beta",
		wantImportsA: map[string]bool{
			"github.com/golang/protobuf/proto": true,
			"beta": true,
		},
	}, {
		parameters: "import_prefix=prefix",
		wantFiles: map[string]bool{
			"package/alpha/a.pb.go": true,
			"beta/b.pb.go":          true,
		},
		wantPackageA: "alpha",
		wantPackageB: "test_beta",
		wantImportsA: map[string]bool{
			// This really doesn't seem like useful behavior.
			"prefixgithub.com/golang/protobuf/proto": true,
			"prefixbeta":                             true,
		},
	}, {
		// import_path only affects the 'package' line.
		parameters:   "import_path=import/path/of/pkg",
		wantPackageA: "alpha",
		wantPackageB: "pkg",
		wantFiles: map[string]bool{
			"package/alpha/a.pb.go": true,
			"beta/b.pb.go":          true,
		},
	}, {
		parameters: "Mbeta/b.proto=package/gamma",
		wantFiles: map[string]bool{
			"package/alpha/a.pb.go": true,
			"beta/b.pb.go":          true,
		},
		wantPackageA: "alpha",
		wantPackageB: "test_beta",
		wantImportsA: map[string]bool{
			"github.com/golang/protobuf/proto": true,
			// Rewritten by the M parameter.
			"package/gamma": true,
		},
	}, {
		parameters: "import_prefix=prefix,Mbeta/b.proto=package/gamma",
		wantFiles: map[string]bool{
			"package/alpha/a.pb.go": true,
			"beta/b.pb.go":          true,
		},
		wantPackageA: "alpha",
		wantPackageB: "test_beta",
		wantImportsA: map[string]bool{
			// import_prefix applies after M.
			"prefixpackage/gamma": true,
		},
	}, {
		parameters: "paths=source_relative",
		wantFiles: map[string]bool{
			"alpha/a.pb.go": true,
			"beta/b.pb.go":  true,
		},
		wantPackageA: "alpha",
		wantPackageB: "test_beta",
	}, {
		parameters: "paths=source_relative,import_prefix=prefix",
		wantFiles: map[string]bool{
			// import_prefix doesn't affect filenames.
			"alpha/a.pb.go": true,
			"beta/b.pb.go":  true,
		},
		wantPackageA: "alpha",
		wantPackageB: "test_beta",
	}} {
		name := test.parameters
		if name == "" {
			name = "defaults"
		}
		// TODO: Switch to t.Run when we no longer support Go 1.6.
		t.Logf("TEST: %v", name)
		workdir, err := ioutil.TempDir("", "proto-test")
		if err != nil {
			t.Fatal(err)
		}
		defer os.RemoveAll(workdir)

		for _, dir := range []string{"alpha", "beta", "out"} {
			if err := os.MkdirAll(filepath.Join(workdir, dir), 0777); err != nil {
				t.Fatal(err)
			}
		}

		if err := ioutil.WriteFile(filepath.Join(workdir, "alpha", "a.proto"), []byte(aProto), 0666); err != nil {
			t.Fatal(err)
		}

		if err := ioutil.WriteFile(filepath.Join(workdir, "beta", "b.proto"), []byte(bProto), 0666); err != nil {
			t.Fatal(err)
		}

		protoc(t, []string{
			"-I" + workdir,
			"--go_out=" + test.parameters + ":" + filepath.Join(workdir, "out"),
			filepath.Join(workdir, "alpha", "a.proto"),
		})
		protoc(t, []string{
			"-I" + workdir,
			"--go_out=" + test.parameters + ":" + filepath.Join(workdir, "out"),
			filepath.Join(workdir, "beta", "b.proto"),
		})

		contents := make(map[string]string)
		gotFiles := make(map[string]bool)
		outdir := filepath.Join(workdir, "out")
		filepath.Walk(outdir, func(p string, info os.FileInfo, _ error) error {
			if info.IsDir() {
				return nil
			}
			base := filepath.Base(p)
			if base == "a.pb.go" || base == "b.pb.go" {
				b, err := ioutil.ReadFile(p)
				if err != nil {
					t.Fatal(err)
				}
				contents[base] = string(b)
			}
			relPath, _ := filepath.Rel(outdir, p)
			gotFiles[relPath] = true
			return nil
		})
		for got := range gotFiles {
			if runtime.GOOS == "windows" {
				got = filepath.ToSlash(got)
			}
			if !test.wantFiles[got] {
				t.Errorf("unexpected output file: %v", got)
			}
		}
		for want := range test.wantFiles {
			if runtime.GOOS == "windows" {
				want = filepath.FromSlash(want)
			}
			if !gotFiles[want] {
				t.Errorf("missing output file:    %v", want)
			}
		}
		gotPackageA, gotImports, err := parseFile(contents["a.pb.go"])
		if err != nil {
			t.Fatal(err)
		}
		gotPackageB, _, err := parseFile(contents["b.pb.go"])
		if err != nil {
			t.Fatal(err)
		}
		if got, want := gotPackageA, test.wantPackageA; want != got {
			t.Errorf("output file a.pb.go is package %q, want %q", got, want)
		}
		if got, want := gotPackageB, test.wantPackageB; want != got {
			t.Errorf("output file b.pb.go is package %q, want %q", got, want)
		}
		missingImport := false
	WantImport:
		for want := range test.wantImportsA {
			for _, imp := range gotImports {
				if `"`+want+`"` == imp {
					continue WantImport
				}
			}
			t.Errorf("output file a.pb.go does not contain expected import %q", want)
			missingImport = true
		}
		if missingImport {
			t.Error("got imports:")
			for _, imp := range gotImports {
				t.Errorf("  %v", imp)
			}
		}
	}
}

func TestPackageComment(t *testing.T) {
	workdir, err := ioutil.TempDir("", "proto-test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(workdir)

	var packageRE = regexp.MustCompile(`(?m)^package .*`)

	for i, test := range []struct {
		goPackageOption string
		wantPackage     string
	}{{
		goPackageOption: ``,
		wantPackage:     `package proto_package`,
	}, {
		goPackageOption: `option go_package = "go_package";`,
		wantPackage:     `package go_package`,
	}, {
		goPackageOption: `option go_package = "import/path/of/go_package";`,
		wantPackage:     `package go_package // import "import/path/of/go_package"`,
	}, {
		goPackageOption: `option go_package = "import/path/of/something;go_package";`,
		wantPackage:     `package go_package // import "import/path/of/something"`,
	}, {
		goPackageOption: `option go_package = "import_path;go_package";`,
		wantPackage:     `package go_package // import "import_path"`,
	}} {
		srcName := filepath.Join(workdir, fmt.Sprintf("%d.proto", i))
		tgtName := filepath.Join(workdir, fmt.Sprintf("%d.pb.go", i))

		buf := &bytes.Buffer{}
		fmt.Fprintln(buf, `syntax = "proto3";`)
		fmt.Fprintln(buf, `package proto_package;`)
		fmt.Fprintln(buf, test.goPackageOption)
		if err := ioutil.WriteFile(srcName, buf.Bytes(), 0666); err != nil {
			t.Fatal(err)
		}

		protoc(t, []string{"-I" + workdir, "--go_out=paths=source_relative:" + workdir, srcName})

		out, err := ioutil.ReadFile(tgtName)
		if err != nil {
			t.Fatal(err)
		}

		pkg := packageRE.Find(out)
		if pkg == nil {
			t.Errorf("generated .pb.go contains no package line\n\nsource:\n%v\n\noutput:\n%v", buf.String(), string(out))
			continue
		}

		if got, want := string(pkg), test.wantPackage; got != want {
			t.Errorf("unexpected package statement with go_package = %q\n got: %v\nwant: %v", test.goPackageOption, got, want)
		}
	}
}

// parseFile returns a file's package name and a list of all packages it imports.
func parseFile(source string) (packageName string, imports []string, err error) {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, "<source>", source, parser.ImportsOnly)
	if err != nil {
		return "", nil, err
	}
	for _, imp := range f.Imports {
		imports = append(imports, imp.Path.Value)
	}
	return f.Name.Name, imports, nil
}

func protoc(t *testing.T, args []string) {
	cmd := exec.Command("protoc", "--plugin=protoc-gen-go="+os.Args[0])
	cmd.Args = append(cmd.Args, args...)
	// We set the RUN_AS_PROTOC_GEN_GO environment variable to indicate that
	// the subprocess should act as a proto compiler rather than a test.
	cmd.Env = append(os.Environ(), "RUN_AS_PROTOC_GEN_GO=1")
	out, err := cmd.CombinedOutput()
	if len(out) > 0 || err != nil {
		t.Log("RUNNING: ", strings.Join(cmd.Args, " "))
	}
	if len(out) > 0 {
		t.Log(string(out))
	}
	if err != nil {
		t.Fatalf("protoc: %v", err)
	}
}

func hasReleaseTag(want string) bool {
	for _, tag := range build.Default.ReleaseTags {
		if tag == want {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>// Copyright 2011, 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package ec2_test

import (
	"flag"
	stdtesting "testing"

	"github.com/juju/testing"
	gc "gopkg.in/check.v1"
)

var amazon = flag.Bool("amazon", false, "Also run some tests on live Amazon servers")

func TestPackage(t *stdtesting.T) {
	if testing.RaceEnabled {
		t.Skip("skipping package under -race, see LP 1519141")
	}
	if *amazon {
		registerAmazonTests()
	}
	registerLocalTests()
	gc.TestingT(t)
}
<commit_msg>provider/ec2: re-enable race test<commit_after>// Copyright 2011, 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package ec2_test

import (
	"flag"
	stdtesting "testing"

	gc "gopkg.in/check.v1"
)

var amazon = flag.Bool("amazon", false, "Also run some tests on live Amazon servers")

func TestPackage(t *stdtesting.T) {
	if *amazon {
		registerAmazonTests()
	}
	registerLocalTests()
	gc.TestingT(t)
}
<|endoftext|>


<commit_before>// Package azure implements a DNS provider for solving the DNS-01
// challenge using azure DNS.
// Azure doesn't like trailing dots on domain names, most of the acme code does.
package azure

import (
	"fmt"
	"os"
	"time"

	"github.com/Azure/azure-sdk-for-go/arm/dns"

	"github.com/Azure/go-autorest/autorest/azure"
	"github.com/Azure/go-autorest/autorest/to"
	"github.com/xenolf/lego/acme"
	"strings"
)

// DNSProvider is an implementation of the acme.ChallengeProvider interface
type DNSProvider struct {
	clientId       string
	clientSecret   string
	subscriptionId string
	tenantId       string
	resourceGroup  string
}

// NewDNSProvider returns a DNSProvider instance configured for azure.
// Credentials must be passed in the environment variables: AZURE_CLIENT_ID,
// AZURE_CLIENT_SECRET, AZURE_SUBSCRIPTION_ID, AZURE_TENANT_ID
func NewDNSProvider() (*DNSProvider, error) {
	clientId := os.Getenv("AZURE_CLIENT_ID")
	clientSecret := os.Getenv("AZURE_CLIENT_SECRET")
	subscriptionId := os.Getenv("AZURE_SUBSCRIPTION_ID")
	tenantId := os.Getenv("AZURE_TENANT_ID")
	resourceGroup := os.Getenv("AZURE_RESOURCE_GROUP")
	return NewDNSProviderCredentials(clientId, clientSecret, subscriptionId, tenantId, resourceGroup)
}

// NewDNSProviderCredentials uses the supplied credentials to return a
// DNSProvider instance configured for azure.
func NewDNSProviderCredentials(clientId, clientSecret, subscriptionId, tenantId, resourceGroup string) (*DNSProvider, error) {
	if clientId == "" || clientSecret == "" || subscriptionId == "" || tenantId == "" || resourceGroup == "" {
		return nil, fmt.Errorf("Azure configuration missing")
	}

	return &DNSProvider{
		clientId:       clientId,
		clientSecret:   clientSecret,
		subscriptionId: subscriptionId,
		tenantId:       tenantId,
		resourceGroup:  resourceGroup,
	}, nil
}

// Timeout returns the timeout and interval to use when checking for DNS
// propagation. Adjusting here to cope with spikes in propagation times.
func (c *DNSProvider) Timeout() (timeout, interval time.Duration) {
	return 120 * time.Second, 2 * time.Second
}

// Present creates a TXT record to fulfil the dns-01 challenge
func (c *DNSProvider) Present(domain, token, keyAuth string) error {
	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
	zone, err := c.getHostedZoneID(fqdn)
	if err != nil {
		return err
	}

	rsc := dns.NewRecordSetsClient(c.subscriptionId)
	rsc.Authorizer, err = c.newServicePrincipalTokenFromCredentials(azure.PublicCloud.ResourceManagerEndpoint)
	relative := toRelativeRecord(fqdn, acme.ToFqdn(zone))
	rec := dns.RecordSet{
		Name: &relative,
		RecordSetProperties: &dns.RecordSetProperties{
			TTL:        to.Int64Ptr(60),
			TXTRecords: &[]dns.TxtRecord{dns.TxtRecord{Value: &[]string{value}}},
		},
	}
	_, err = rsc.CreateOrUpdate(c.resourceGroup, zone, relative, dns.TXT, rec, "", "")

	if err != nil {
		return err
	}

	return nil
}

// Returns the relative record to the domain
func toRelativeRecord(domain, zone string) string {
	return acme.UnFqdn(strings.TrimSuffix(domain, zone))
}

// CleanUp removes the TXT record matching the specified parameters
func (c *DNSProvider) CleanUp(domain, token, keyAuth string) error {
	fqdn, _, _ := acme.DNS01Record(domain, keyAuth)

	zone, err := c.getHostedZoneID(fqdn)
	if err != nil {
		return err
	}

	relative := toRelativeRecord(fqdn, acme.ToFqdn(zone))
	rsc := dns.NewRecordSetsClient(c.subscriptionId)
	rsc.Authorizer, err = c.newServicePrincipalTokenFromCredentials(azure.PublicCloud.ResourceManagerEndpoint)
	_, err = rsc.Delete(c.resourceGroup, zone, relative, dns.TXT, "")
	if err != nil {
		return err
	}

	return nil
}

// Checks that azure has a zone for this domain name.
func (c *DNSProvider) getHostedZoneID(fqdn string) (string, error) {
	authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers)
	if err != nil {
		return "", err
	}

	// Now we want to to Azure and get the zone.
	dc := dns.NewZonesClient(c.subscriptionId)
	dc.Authorizer, err = c.newServicePrincipalTokenFromCredentials(azure.PublicCloud.ResourceManagerEndpoint)
	zone, err := dc.Get(c.resourceGroup, acme.UnFqdn(authZone))

	if err != nil {
		return "", err
	}

	// zone.Name shouldn't have a trailing dot(.)
	return to.String(zone.Name), nil
}

// NewServicePrincipalTokenFromCredentials creates a new ServicePrincipalToken using values of the
// passed credentials map.
func (c *DNSProvider) newServicePrincipalTokenFromCredentials(scope string) (*azure.ServicePrincipalToken, error) {
	oauthConfig, err := azure.PublicCloud.OAuthConfigForTenant(c.tenantId)
	if err != nil {
		panic(err)
	}
	return azure.NewServicePrincipalToken(*oauthConfig, c.clientId, c.clientSecret, scope)
}
<commit_msg>Fix breaking change in azure SDK<commit_after>// Package azure implements a DNS provider for solving the DNS-01
// challenge using azure DNS.
// Azure doesn't like trailing dots on domain names, most of the acme code does.
package azure

import (
	"fmt"
	"os"
	"time"

	"github.com/Azure/azure-sdk-for-go/arm/dns"

	"strings"

	"github.com/Azure/go-autorest/autorest/azure"
	"github.com/Azure/go-autorest/autorest/to"
	"github.com/xenolf/lego/acme"
)

// DNSProvider is an implementation of the acme.ChallengeProvider interface
type DNSProvider struct {
	clientId       string
	clientSecret   string
	subscriptionId string
	tenantId       string
	resourceGroup  string
}

// NewDNSProvider returns a DNSProvider instance configured for azure.
// Credentials must be passed in the environment variables: AZURE_CLIENT_ID,
// AZURE_CLIENT_SECRET, AZURE_SUBSCRIPTION_ID, AZURE_TENANT_ID
func NewDNSProvider() (*DNSProvider, error) {
	clientId := os.Getenv("AZURE_CLIENT_ID")
	clientSecret := os.Getenv("AZURE_CLIENT_SECRET")
	subscriptionId := os.Getenv("AZURE_SUBSCRIPTION_ID")
	tenantId := os.Getenv("AZURE_TENANT_ID")
	resourceGroup := os.Getenv("AZURE_RESOURCE_GROUP")
	return NewDNSProviderCredentials(clientId, clientSecret, subscriptionId, tenantId, resourceGroup)
}

// NewDNSProviderCredentials uses the supplied credentials to return a
// DNSProvider instance configured for azure.
func NewDNSProviderCredentials(clientId, clientSecret, subscriptionId, tenantId, resourceGroup string) (*DNSProvider, error) {
	if clientId == "" || clientSecret == "" || subscriptionId == "" || tenantId == "" || resourceGroup == "" {
		return nil, fmt.Errorf("Azure configuration missing")
	}

	return &DNSProvider{
		clientId:       clientId,
		clientSecret:   clientSecret,
		subscriptionId: subscriptionId,
		tenantId:       tenantId,
		resourceGroup:  resourceGroup,
	}, nil
}

// Timeout returns the timeout and interval to use when checking for DNS
// propagation. Adjusting here to cope with spikes in propagation times.
func (c *DNSProvider) Timeout() (timeout, interval time.Duration) {
	return 120 * time.Second, 2 * time.Second
}

// Present creates a TXT record to fulfil the dns-01 challenge
func (c *DNSProvider) Present(domain, token, keyAuth string) error {
	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
	zone, err := c.getHostedZoneID(fqdn)
	if err != nil {
		return err
	}

	rsc := dns.NewRecordSetsClient(c.subscriptionId)
	rsc.Authorizer, err = c.newServicePrincipalTokenFromCredentials(azure.PublicCloud.ResourceManagerEndpoint)
	relative := toRelativeRecord(fqdn, acme.ToFqdn(zone))
	rec := dns.RecordSet{
		Name: &relative,
		RecordSetProperties: &dns.RecordSetProperties{
			TTL:        to.Int64Ptr(60),
			TxtRecords: &[]dns.TxtRecord{dns.TxtRecord{Value: &[]string{value}}},
		},
	}
	_, err = rsc.CreateOrUpdate(c.resourceGroup, zone, relative, dns.TXT, rec, "", "")

	if err != nil {
		return err
	}

	return nil
}

// Returns the relative record to the domain
func toRelativeRecord(domain, zone string) string {
	return acme.UnFqdn(strings.TrimSuffix(domain, zone))
}

// CleanUp removes the TXT record matching the specified parameters
func (c *DNSProvider) CleanUp(domain, token, keyAuth string) error {
	fqdn, _, _ := acme.DNS01Record(domain, keyAuth)

	zone, err := c.getHostedZoneID(fqdn)
	if err != nil {
		return err
	}

	relative := toRelativeRecord(fqdn, acme.ToFqdn(zone))
	rsc := dns.NewRecordSetsClient(c.subscriptionId)
	rsc.Authorizer, err = c.newServicePrincipalTokenFromCredentials(azure.PublicCloud.ResourceManagerEndpoint)
	_, err = rsc.Delete(c.resourceGroup, zone, relative, dns.TXT, "")
	if err != nil {
		return err
	}

	return nil
}

// Checks that azure has a zone for this domain name.
func (c *DNSProvider) getHostedZoneID(fqdn string) (string, error) {
	authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers)
	if err != nil {
		return "", err
	}

	// Now we want to to Azure and get the zone.
	dc := dns.NewZonesClient(c.subscriptionId)
	dc.Authorizer, err = c.newServicePrincipalTokenFromCredentials(azure.PublicCloud.ResourceManagerEndpoint)
	zone, err := dc.Get(c.resourceGroup, acme.UnFqdn(authZone))

	if err != nil {
		return "", err
	}

	// zone.Name shouldn't have a trailing dot(.)
	return to.String(zone.Name), nil
}

// NewServicePrincipalTokenFromCredentials creates a new ServicePrincipalToken using values of the
// passed credentials map.
func (c *DNSProvider) newServicePrincipalTokenFromCredentials(scope string) (*azure.ServicePrincipalToken, error) {
	oauthConfig, err := azure.PublicCloud.OAuthConfigForTenant(c.tenantId)
	if err != nil {
		panic(err)
	}
	return azure.NewServicePrincipalToken(*oauthConfig, c.clientId, c.clientSecret, scope)
}
<|endoftext|>


<commit_before>// Package twitter implements the OAuth protocol for authenticating users through Twitter.
// This package can be used as a reference implementation of an OAuth provider for Goth.
package twitter

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"strings"

	"github.com/markbates/goth"
	"github.com/mrjones/oauth"
)

var (
	requestURL      = "https://api.twitter.com/oauth/request_token"
	authURL         = "https://api.twitter.com/oauth/authorize"
	tokenURL        = "https://api.twitter.com/oauth/access_token"
	endpointProfile = "https://api.twitter.com/1.1/account/verify_credentials.json"
)

// New creates a new Twitter provider, and sets up important connection details.
// You should always call `twitter.New` to get a new Provider. Never try to create
// one manually.
func New(clientKey, secret, callbackURL string) *Provider {
	p := &Provider{
		ClientKey:   clientKey,
		Secret:      secret,
		CallbackURL: callbackURL,
	}
	p.consumer = newConsumer(p)
	return p
}

// Provider is the implementation of `goth.Provider` for accessing Twitter.
type Provider struct {
	ClientKey   string
	Secret      string
	CallbackURL string
	debug       bool
	consumer    *oauth.Consumer
}

// Name is the name used to retrieve this provider later.
func (p *Provider) Name() string {
	return "twitter"
}

// Debug sets the logging of the OAuth client to verbose.
func (p *Provider) Debug(debug bool) {
	p.debug = debug
}

// BeginAuth asks Twitter for an authentication end-point and a request token for a session.
// Twitter does not support the "state" variable.
func (p *Provider) BeginAuth(state string) (goth.Session, error) {
	requestToken, url, err := p.consumer.GetRequestTokenAndUrl(p.CallbackURL)
	session := &Session{
		AuthURL:      url,
		RequestToken: requestToken,
	}
	return session, err
}

// FetchUser will go to Twitter and access basic information about the user.
func (p *Provider) FetchUser(session goth.Session) (goth.User, error) {
	user := goth.User{
		Provider: p.Name(),
	}

	sess := session.(*Session)
	response, err := p.consumer.Get(
		endpointProfile,
		map[string]string{"include_entities": "false", "skip_status": "true"},
		sess.AccessToken)
	if err != nil {
		return user, err
	}
	defer response.Body.Close()

	bits, err := ioutil.ReadAll(response.Body)
	err = json.NewDecoder(bytes.NewReader(bits)).Decode(&user.RawData)
	if err != nil {
		return user, err
	}

	user.Name = user.RawData["name"].(string)
	user.NickName = user.RawData["screen_name"].(string)
	user.Description = user.RawData["description"].(string)
	user.AvatarURL = user.RawData["profile_image_url"].(string)
	user.UserID = user.RawData["id_str"].(string)
	user.Location = user.RawData["location"].(string)
	user.AccessToken = sess.AccessToken.Token
	user.AccessTokenSecret = sess.AccessToken.Secret
	return user, err
}

// UnmarshalSession will unmarshal a JSON string into a session.
func (p *Provider) UnmarshalSession(data string) (goth.Session, error) {
	sess := &Session{}
	err := json.NewDecoder(strings.NewReader(data)).Decode(sess)
	return sess, err
}

func newConsumer(provider *Provider) *oauth.Consumer {
	c := oauth.NewConsumer(
		provider.ClientKey,
		provider.Secret,
		oauth.ServiceProvider{
			RequestTokenUrl:   requestURL,
			AuthorizeTokenUrl: authURL,
			AccessTokenUrl:    tokenURL,
		})

	c.Debug(provider.debug)
	return c
}
<commit_msg>twitter: add authenticate support<commit_after>// Package twitter implements the OAuth protocol for authenticating users through Twitter.
// This package can be used as a reference implementation of an OAuth provider for Goth.
package twitter

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"strings"

	"github.com/markbates/goth"
	"github.com/mrjones/oauth"
)

var (
	requestURL      = "https://api.twitter.com/oauth/request_token"
	authorizeURL    = "https://api.twitter.com/oauth/authorize"
	authenticateURL = "https://api.twitter.com/oauth/authenticate"
	tokenURL        = "https://api.twitter.com/oauth/access_token"
	endpointProfile = "https://api.twitter.com/1.1/account/verify_credentials.json"
)

// New creates a new Twitter provider, and sets up important connection details.
// You should always call `twitter.New` to get a new Provider. Never try to create
// one manually.
func New(clientKey, secret, callbackURL string) *Provider {
	p := &Provider{
		ClientKey:   clientKey,
		Secret:      secret,
		CallbackURL: callbackURL,
	}
	p.consumer = newConsumer(p, authorizeURL)
	return p
}

// NewAuthenticate is the almost same as New.
// NewAuthenticate uses the authenticate URL instead of the authorize URL.
func NewAuthenticate(clientKey, secret, callbackURL string) *Provider {
	p := &Provider{
		ClientKey:   clientKey,
		Secret:      secret,
		CallbackURL: callbackURL,
	}
	p.consumer = newConsumer(p, authenticateURL)
	return p
}

// Provider is the implementation of `goth.Provider` for accessing Twitter.
type Provider struct {
	ClientKey   string
	Secret      string
	CallbackURL string
	debug       bool
	consumer    *oauth.Consumer
}

// Name is the name used to retrieve this provider later.
func (p *Provider) Name() string {
	return "twitter"
}

// Debug sets the logging of the OAuth client to verbose.
func (p *Provider) Debug(debug bool) {
	p.debug = debug
}

// BeginAuth asks Twitter for an authentication end-point and a request token for a session.
// Twitter does not support the "state" variable.
func (p *Provider) BeginAuth(state string) (goth.Session, error) {
	requestToken, url, err := p.consumer.GetRequestTokenAndUrl(p.CallbackURL)
	session := &Session{
		AuthURL:      url,
		RequestToken: requestToken,
	}
	return session, err
}

// FetchUser will go to Twitter and access basic information about the user.
func (p *Provider) FetchUser(session goth.Session) (goth.User, error) {
	user := goth.User{
		Provider: p.Name(),
	}

	sess := session.(*Session)
	response, err := p.consumer.Get(
		endpointProfile,
		map[string]string{"include_entities": "false", "skip_status": "true"},
		sess.AccessToken)
	if err != nil {
		return user, err
	}
	defer response.Body.Close()

	bits, err := ioutil.ReadAll(response.Body)
	err = json.NewDecoder(bytes.NewReader(bits)).Decode(&user.RawData)
	if err != nil {
		return user, err
	}

	user.Name = user.RawData["name"].(string)
	user.NickName = user.RawData["screen_name"].(string)
	user.Description = user.RawData["description"].(string)
	user.AvatarURL = user.RawData["profile_image_url"].(string)
	user.UserID = user.RawData["id_str"].(string)
	user.Location = user.RawData["location"].(string)
	user.AccessToken = sess.AccessToken.Token
	user.AccessTokenSecret = sess.AccessToken.Secret
	return user, err
}

// UnmarshalSession will unmarshal a JSON string into a session.
func (p *Provider) UnmarshalSession(data string) (goth.Session, error) {
	sess := &Session{}
	err := json.NewDecoder(strings.NewReader(data)).Decode(sess)
	return sess, err
}

func newConsumer(provider *Provider, authURL string) *oauth.Consumer {
	c := oauth.NewConsumer(
		provider.ClientKey,
		provider.Secret,
		oauth.ServiceProvider{
			RequestTokenUrl:   requestURL,
			AuthorizeTokenUrl: authURL,
			AccessTokenUrl:    tokenURL,
		})

	c.Debug(provider.debug)
	return c
}
<|endoftext|>


<commit_before>/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
*/

package main

import (
	"errors"
	"fmt"
	"strconv"
	"encoding/json"
	"time"

	"github.com/openblockchain/obc-peer/openchain/chaincode/shim"
)

// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}

var marbleIndex []string						//store marbles here, b/c we need this
var _allIndex []string							//store all variables names here, b/c its handy for debug
var _all string = "_all"						//key name for above. tracks all variables in chaincode state

type Marble struct{
	Name string `json:"name"`					//the fieldtags are needed to keep case from bouncing around
	Color string `json:"color"`
	Size int `json:"size"`
	User string `json:"user"`
}

type Description struct{
	Color string `json:"color"`
	Size int `json:"size"`
}

type AnOpenTrade struct{
	User string `json:"user"`					//user who created the open trade order
	Timestamp int64 `json:"timestamp"`			//utc timestamp of creation
	Want Description  `json:"want"`				//description of desired marble
	Willing []Description `json:"willing"`		//array of marbles willing to trade away
}

type AllTrades struct{
	OpenTrades []AnOpenTrade `json:"open_trades"`
}

var trades AllTrades

// ============================================================================================================================
// Init - reset all the things
// ============================================================================================================================
func (t *SimpleChaincode) init(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var Aval int
	var err error

	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting 1")
	}

	// Initialize the chaincode
	Aval, err = strconv.Atoi(args[0])
	if err != nil {
		return nil, errors.New("Expecting integer value for asset holding")
	}
	fmt.Printf("Aval = %d\n", Aval)

	// Write the state to the ledger
	err = stub.PutState("abc", []byte(strconv.Itoa(Aval)))				//making a test var "abc", I find it handy to read/write to it right away to test the network
	if err != nil {
		return nil, err
	}

	_allIndex = _allIndex[:0]											//clear the _all variables index
	jsonAsBytes1, _ := json.Marshal(_allIndex)
	err = stub.PutState(_all, jsonAsBytes1)
	if err != nil {
		return nil, err
	}

	marbleIndex = marbleIndex[:0]										//clear the marble index
	jsonAsBytes, _ := json.Marshal(marbleIndex)
	err = stub.PutState("marbleIndex", jsonAsBytes)
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// ============================================================================================================================
// Run - Our entry point
// ============================================================================================================================
func (t *SimpleChaincode) Run(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
	fmt.Println("run is running " + function)

	// Handle different functions
	if function == "init" {													//initialize the chaincode state, used as reset
		return t.init(stub, args)
	} else if function == "delete" {										//deletes an entity from its state
		return t.Delete(stub, args)
	} else if function == "write" {											//writes a value to the chaincode state
		return t.Write(stub, args)
	} else if function == "init_marble" {									//create a new marble
		return t.init_marble(stub, args)
	} else if function == "set_user" {										//change owner of a marble
		return t.set_user(stub, args)
	} else if function == "open_trade" {									//create a new trade order
		return t.open_trade(stub, args)
	} else if function == "perform_trade" {									//forfill an open trade order
		return t.perform_trade(stub, args)
	}
	fmt.Println("run did not find func: " + function)						//error

	return nil, errors.New("Received unknown function invocation")
}

// ============================================================================================================================
// Delete - remove an entity from state
// ============================================================================================================================
func (t *SimpleChaincode) Delete(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting 1")
	}

	name := args[0]
	err := stub.DelState(name)													//remove the key from chaincode state
	if err != nil {
		return nil, errors.New("Failed to delete state")
	}

	//remove marble from index
	for i,val := range marbleIndex{
		fmt.Println(strconv.Itoa(i) + " - looking at " + val + " for " + name)
		if val == name{															//find the correct marble
			fmt.Println("found marble")
			marbleIndex = append(marbleIndex[:i], marbleIndex[i+1:]...)			//remove it
			for x:= range marbleIndex{											//debug prints...
				fmt.Println(string(x) + " - " + marbleIndex[x])
			}
			break
		}
	}
	jsonAsBytes, _ := json.Marshal(marbleIndex)									//save new index
	err = stub.PutState("marbleIndex", jsonAsBytes)

	return nil, nil
}

// ============================================================================================================================
// Query - read a variable from chaincode state - (aka read)
// ============================================================================================================================
func (t *SimpleChaincode) Query(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
	if function != "query" {
		return nil, errors.New("Invalid query function name. Expecting \"query\"")
	}
	var name, jsonResp string
	var err error

	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting name of the person to query")
	}

	name = args[0]
	valAsbytes, err := stub.GetState(name)									//get the var from chaincode state
	if err != nil {
		jsonResp = "{\"Error\":\"Failed to get state for " + name + "\"}"
		return nil, errors.New(jsonResp)
	}

	return valAsbytes, nil													//send it onward
}

func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}

// ============================================================================================================================
// Write - write variable into chaincode state
// ============================================================================================================================
func (t *SimpleChaincode) Write(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var name, value string // Entities
	var err error
	fmt.Println("running write()")

	if len(args) != 2 {
		return nil, errors.New("Incorrect number of arguments. Expecting 2. name of the variable and value to set")
	}

	name = args[0]															//rename for funsies
	value = args[1]
	err = stub.PutState(name, []byte(value))								//write the variable into the chaincode state
	if err != nil {
		return nil, err
	}
	t.remember_me(stub, name)

	return nil, nil
}

// ============================================================================================================================
// Remember Me - remember the name of variables we stored in ledger
// ============================================================================================================================
func (t *SimpleChaincode) remember_me(stub *shim.ChaincodeStub, name string) ([]byte, error) {
	var err error

	_allIndex = append(_allIndex, name)										//add var name to index list
	jsonAsBytes, _ := json.Marshal(_allIndex)
	err = stub.PutState(_all, jsonAsBytes)									//store it
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// ============================================================================================================================
// Init Marble
// ============================================================================================================================
func (t *SimpleChaincode) init_marble(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var err error

	if len(args) != 4 {
		return nil, errors.New("Incorrect number of arguments. Expecting 4")
	}

	val, err := strconv.Atoi(args[2])
	if err != nil {
		val = 16															//default value
	}
	str := `{"name": "` + args[0] + `", "color": "` + args[1] + `", "size": ` + strconv.Itoa(val) + `, "user": "` + args[3] + `"}`

	err = stub.PutState(args[0], []byte(str))								//store marble with id as key
	if err != nil {
		return nil, err
	}
	t.remember_me(stub, args[0])

	marbleIndex = append(marbleIndex, args[0])								//add marble name to index list
	jsonAsBytes, _ := json.Marshal(marbleIndex)
	err = stub.PutState("marbleIndex", jsonAsBytes)							//store name of marble

	return nil, nil
}

// ============================================================================================================================
// Set User Permission on Marble
// ============================================================================================================================
func (t *SimpleChaincode) set_user(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var err error

	// "asdf", "bob"
	if len(args) < 2 {
		return nil, errors.New("Incorrect number of arguments. Expecting 2")
	}

	marbleAsBytes, err := stub.GetState(args[0])
	if err != nil {
		return nil, errors.New("Failed to get thing")
	}
	res := Marble{}
	json.Unmarshal(marbleAsBytes, &res)										//un stringify it aka JSON.parse()
	fmt.Println(res)
	res.User = args[1]														//change the user

	jsonAsBytes, _ := json.Marshal(res)
	err = stub.PutState(args[0], jsonAsBytes)								//rewrite the marble with id as key
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// ============================================================================================================================
// Open Trade - create an open trade for a marble you want with marbles you have
// ============================================================================================================================
func (t *SimpleChaincode) open_trade(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var err error

	//"bob", "blue", "16", "red", "16"
	if len(args) < 5 {
		return nil, errors.New("Incorrect number of arguments. Expecting like 5?")
	}

	size1, err := strconv.Atoi(args[2])
	if err != nil {
		return nil, errors.New("3rd argument must be a numeric string")
	}
	size2, err := strconv.Atoi(args[4])
	if err != nil {
		return nil, errors.New("5th argument must be a numeric string")
	}

	open := AnOpenTrade{};
	open.User = args[0];
	open.Timestamp = makeTimestamp()											//use this as an ID
	open.Want.Color = args[1];
	open.Want.Size =  size1;
	fmt.Println("! start open trade")
	jsonAsBytes, _ := json.Marshal(open)
	err = stub.PutState("_debug1", jsonAsBytes)

	trade_away := Description{};
	trade_away.Color = args[3];
	trade_away.Size =  size2;
	fmt.Println("! created trade_away")
	jsonAsBytes, _ = json.Marshal(trade_away)
	err = stub.PutState("_debug2", jsonAsBytes)

	open.Willing = append(open.Willing, trade_away)
	fmt.Println("! appended willing to open")
	jsonAsBytes, _ = json.Marshal(open)
	err = stub.PutState("_debug3", jsonAsBytes)

	trades.OpenTrades = append(trades.OpenTrades, open);						//append to open trades
	fmt.Println("! appended open to trades")
	jsonAsBytes, _ = json.Marshal(trades)
	err = stub.PutState("_opentrades", jsonAsBytes)								//rewrite open orders
	if err != nil {
		return nil, err
	}
	fmt.Println("! open trade success ")
	return nil, nil
}

// ============================================================================================================================
// Perform Trade - close an open trade and move ownership
// ============================================================================================================================
func (t *SimpleChaincode) perform_trade(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var err error

	//"bob", "444444444444", "asdf"
	if len(args) < 3 {
		return nil, errors.New("Incorrect number of arguments. Expecting 3")
	}

	fmt.Println("! start close trade")
	timestamp, err := strconv.ParseInt(args[1], 10, 64)
	if err != nil {
		return nil, errors.New("2nd argument must be a numeric string")
	}

	for i := range trades.OpenTrades{														//look for the trade
		fmt.Println("looking at " + strconv.FormatInt(trades.OpenTrades[i].Timestamp, 10) + " for " + strconv.FormatInt(timestamp, 10))
		if trades.OpenTrades[i].Timestamp == timestamp{
			fmt.Println("found trade");

			t.set_user(stub, []string{args[0], args[2]})

			trades.OpenTrades = append(trades.OpenTrades[:i], trades.OpenTrades[i+1:]...)	//remove trade
			jsonAsBytes, _ := json.Marshal(trades)
			err = stub.PutState("_opentrades", jsonAsBytes)									//rewrite open orders
			if err != nil {
				return nil, err
			}
		}
	}
	fmt.Println("! close trade success ")
	return nil, nil
}

func makeTimestamp() int64 {
    return time.Now().UnixNano() / (int64(time.Millisecond)/int64(time.Nanosecond))
}<commit_msg>- send marble to user who opened trade<commit_after>/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
*/

package main

import (
	"errors"
	"fmt"
	"strconv"
	"encoding/json"
	"time"

	"github.com/openblockchain/obc-peer/openchain/chaincode/shim"
)

// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}

var marbleIndex []string						//store marbles here, b/c we need this
var _allIndex []string							//store all variables names here, b/c its handy for debug
var _all string = "_all"						//key name for above. tracks all variables in chaincode state

type Marble struct{
	Name string `json:"name"`					//the fieldtags are needed to keep case from bouncing around
	Color string `json:"color"`
	Size int `json:"size"`
	User string `json:"user"`
}

type Description struct{
	Color string `json:"color"`
	Size int `json:"size"`
}

type AnOpenTrade struct{
	User string `json:"user"`					//user who created the open trade order
	Timestamp int64 `json:"timestamp"`			//utc timestamp of creation
	Want Description  `json:"want"`				//description of desired marble
	Willing []Description `json:"willing"`		//array of marbles willing to trade away
}

type AllTrades struct{
	OpenTrades []AnOpenTrade `json:"open_trades"`
}

var trades AllTrades

// ============================================================================================================================
// Init - reset all the things
// ============================================================================================================================
func (t *SimpleChaincode) init(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var Aval int
	var err error

	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting 1")
	}

	// Initialize the chaincode
	Aval, err = strconv.Atoi(args[0])
	if err != nil {
		return nil, errors.New("Expecting integer value for asset holding")
	}
	fmt.Printf("Aval = %d\n", Aval)

	// Write the state to the ledger
	err = stub.PutState("abc", []byte(strconv.Itoa(Aval)))				//making a test var "abc", I find it handy to read/write to it right away to test the network
	if err != nil {
		return nil, err
	}

	_allIndex = _allIndex[:0]											//clear the _all variables index
	jsonAsBytes1, _ := json.Marshal(_allIndex)
	err = stub.PutState(_all, jsonAsBytes1)
	if err != nil {
		return nil, err
	}

	marbleIndex = marbleIndex[:0]										//clear the marble index
	jsonAsBytes, _ := json.Marshal(marbleIndex)
	err = stub.PutState("marbleIndex", jsonAsBytes)
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// ============================================================================================================================
// Run - Our entry point
// ============================================================================================================================
func (t *SimpleChaincode) Run(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
	fmt.Println("run is running " + function)

	// Handle different functions
	if function == "init" {													//initialize the chaincode state, used as reset
		return t.init(stub, args)
	} else if function == "delete" {										//deletes an entity from its state
		return t.Delete(stub, args)
	} else if function == "write" {											//writes a value to the chaincode state
		return t.Write(stub, args)
	} else if function == "init_marble" {									//create a new marble
		return t.init_marble(stub, args)
	} else if function == "set_user" {										//change owner of a marble
		return t.set_user(stub, args)
	} else if function == "open_trade" {									//create a new trade order
		return t.open_trade(stub, args)
	} else if function == "perform_trade" {									//forfill an open trade order
		return t.perform_trade(stub, args)
	}
	fmt.Println("run did not find func: " + function)						//error

	return nil, errors.New("Received unknown function invocation")
}

// ============================================================================================================================
// Delete - remove an entity from state
// ============================================================================================================================
func (t *SimpleChaincode) Delete(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting 1")
	}

	name := args[0]
	err := stub.DelState(name)													//remove the key from chaincode state
	if err != nil {
		return nil, errors.New("Failed to delete state")
	}

	//remove marble from index
	for i,val := range marbleIndex{
		fmt.Println(strconv.Itoa(i) + " - looking at " + val + " for " + name)
		if val == name{															//find the correct marble
			fmt.Println("found marble")
			marbleIndex = append(marbleIndex[:i], marbleIndex[i+1:]...)			//remove it
			for x:= range marbleIndex{											//debug prints...
				fmt.Println(string(x) + " - " + marbleIndex[x])
			}
			break
		}
	}
	jsonAsBytes, _ := json.Marshal(marbleIndex)									//save new index
	err = stub.PutState("marbleIndex", jsonAsBytes)

	return nil, nil
}

// ============================================================================================================================
// Query - read a variable from chaincode state - (aka read)
// ============================================================================================================================
func (t *SimpleChaincode) Query(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
	if function != "query" {
		return nil, errors.New("Invalid query function name. Expecting \"query\"")
	}
	var name, jsonResp string
	var err error

	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting name of the person to query")
	}

	name = args[0]
	valAsbytes, err := stub.GetState(name)									//get the var from chaincode state
	if err != nil {
		jsonResp = "{\"Error\":\"Failed to get state for " + name + "\"}"
		return nil, errors.New(jsonResp)
	}

	return valAsbytes, nil													//send it onward
}

func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}

// ============================================================================================================================
// Write - write variable into chaincode state
// ============================================================================================================================
func (t *SimpleChaincode) Write(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var name, value string // Entities
	var err error
	fmt.Println("running write()")

	if len(args) != 2 {
		return nil, errors.New("Incorrect number of arguments. Expecting 2. name of the variable and value to set")
	}

	name = args[0]															//rename for funsies
	value = args[1]
	err = stub.PutState(name, []byte(value))								//write the variable into the chaincode state
	if err != nil {
		return nil, err
	}
	t.remember_me(stub, name)

	return nil, nil
}

// ============================================================================================================================
// Remember Me - remember the name of variables we stored in ledger
// ============================================================================================================================
func (t *SimpleChaincode) remember_me(stub *shim.ChaincodeStub, name string) ([]byte, error) {
	var err error

	_allIndex = append(_allIndex, name)										//add var name to index list
	jsonAsBytes, _ := json.Marshal(_allIndex)
	err = stub.PutState(_all, jsonAsBytes)									//store it
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// ============================================================================================================================
// Init Marble
// ============================================================================================================================
func (t *SimpleChaincode) init_marble(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var err error

	if len(args) != 4 {
		return nil, errors.New("Incorrect number of arguments. Expecting 4")
	}

	fmt.Println("! start init marble")
	val, err := strconv.Atoi(args[2])
	if err != nil {
		val = 16															//default value
	}
	str := `{"name": "` + args[0] + `", "color": "` + args[1] + `", "size": ` + strconv.Itoa(val) + `, "user": "` + args[3] + `"}`

	err = stub.PutState(args[0], []byte(str))								//store marble with id as key
	if err != nil {
		return nil, err
	}
	t.remember_me(stub, args[0])

	marbleIndex = append(marbleIndex, args[0])								//add marble name to index list
	jsonAsBytes, _ := json.Marshal(marbleIndex)
	err = stub.PutState("marbleIndex", jsonAsBytes)							//store name of marble

	fmt.Println("! end init marble")
	return nil, nil
}

// ============================================================================================================================
// Set User Permission on Marble
// ============================================================================================================================
func (t *SimpleChaincode) set_user(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var err error

	// "asdf", "bob"
	if len(args) < 2 {
		return nil, errors.New("Incorrect number of arguments. Expecting 2")
	}

	fmt.Println("! start set user")
	marbleAsBytes, err := stub.GetState(args[0])
	if err != nil {
		return nil, errors.New("Failed to get thing")
	}
	res := Marble{}
	json.Unmarshal(marbleAsBytes, &res)										//un stringify it aka JSON.parse()
	fmt.Println(res)
	res.User = args[1]														//change the user

	jsonAsBytes, _ := json.Marshal(res)
	err = stub.PutState(args[0], jsonAsBytes)								//rewrite the marble with id as key
	if err != nil {
		return nil, err
	}

	fmt.Println("! end set user")
	return nil, nil
}

// ============================================================================================================================
// Open Trade - create an open trade for a marble you want with marbles you have
// ============================================================================================================================
func (t *SimpleChaincode) open_trade(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var err error

	//"bob", "blue", "16", "red", "16"
	if len(args) < 5 {
		return nil, errors.New("Incorrect number of arguments. Expecting like 5?")
	}

	size1, err := strconv.Atoi(args[2])
	if err != nil {
		return nil, errors.New("3rd argument must be a numeric string")
	}
	size2, err := strconv.Atoi(args[4])
	if err != nil {
		return nil, errors.New("5th argument must be a numeric string")
	}

	open := AnOpenTrade{};
	open.User = args[0];
	open.Timestamp = makeTimestamp()											//use this as an ID
	open.Want.Color = args[1];
	open.Want.Size =  size1;
	fmt.Println("! start open trade")
	jsonAsBytes, _ := json.Marshal(open)
	err = stub.PutState("_debug1", jsonAsBytes)

	trade_away := Description{};
	trade_away.Color = args[3];
	trade_away.Size =  size2;
	fmt.Println("! created trade_away")
	jsonAsBytes, _ = json.Marshal(trade_away)
	err = stub.PutState("_debug2", jsonAsBytes)

	open.Willing = append(open.Willing, trade_away)
	fmt.Println("! appended willing to open")
	jsonAsBytes, _ = json.Marshal(open)
	err = stub.PutState("_debug3", jsonAsBytes)

	trades.OpenTrades = append(trades.OpenTrades, open);						//append to open trades
	fmt.Println("! appended open to trades")
	jsonAsBytes, _ = json.Marshal(trades)
	err = stub.PutState("_opentrades", jsonAsBytes)								//rewrite open orders
	if err != nil {
		return nil, err
	}
	fmt.Println("! end open trade")
	return nil, nil
}

// ============================================================================================================================
// Perform Trade - close an open trade and move ownership
// ============================================================================================================================
func (t *SimpleChaincode) perform_trade(stub *shim.ChaincodeStub, args []string) ([]byte, error) {
	var err error

	//"bob", "444444444444", "asdf"
	if len(args) < 3 {
		return nil, errors.New("Incorrect number of arguments. Expecting 3")
	}

	fmt.Println("! start close trade")
	timestamp, err := strconv.ParseInt(args[1], 10, 64)
	if err != nil {
		return nil, errors.New("2nd argument must be a numeric string")
	}

	for i := range trades.OpenTrades{														//look for the trade
		fmt.Println("looking at " + strconv.FormatInt(trades.OpenTrades[i].Timestamp, 10) + " for " + strconv.FormatInt(timestamp, 10))
		if trades.OpenTrades[i].Timestamp == timestamp{
			fmt.Println("found trade");

			t.set_user(stub, []string{args[0], trades.OpenTrades[i].User})					//change owner

			trades.OpenTrades = append(trades.OpenTrades[:i], trades.OpenTrades[i+1:]...)	//remove trade
			jsonAsBytes, _ := json.Marshal(trades)
			err = stub.PutState("_opentrades", jsonAsBytes)									//rewrite open orders
			if err != nil {
				return nil, err
			}
		}
	}
	fmt.Println("! end close trade")
	return nil, nil
}

func makeTimestamp() int64 {
    return time.Now().UnixNano() / (int64(time.Millisecond)/int64(time.Nanosecond))
}<|endoftext|>


<commit_before>// go-rst - A reStructuredText parser for Go
// 2014 (c) The go-rst Authors
// MIT Licensed. See LICENSE for details.

package parse

import (
	"code.google.com/p/go.text/unicode/norm"
	"fmt"
	"github.com/demizer/go-elog"
	"github.com/demizer/go-spew/spew"
	"reflect"
)

var spd = spew.ConfigState{Indent: "\t", DisableMethods: true}

type systemMessageLevel int

const (
	levelInfo systemMessageLevel = iota
	levelWarning
	levelError
	levelSevere
)

var systemMessageLevels = [...]string{
	"INFO",
	"WARNING",
	"ERROR",
	"SEVERE",
}

func (s systemMessageLevel) String() string {
	return systemMessageLevels[s]
}

type parserMessage int

const (
	warningShortUnderline parserMessage = iota
	errorUnexpectedSectionTitle
	errorUnexpectedSectionTitleOrTransition
	severeIncompleteSectionTitle
)

var parserErrors = [...]string{
	"warningShortUnderline",
	"errorUnexpectedSectionTitle",
	"errorUnexpectedSectionTitleOrTransition",
	"severeIncompleteSectionTitle",
}

func (p parserMessage) String() string {
	return parserErrors[p]
}

func (p parserMessage) Message() (s string) {
	switch p {
	case warningShortUnderline:
		s = "Title underline too short."
	case errorUnexpectedSectionTitle:
		s = "Unexpected section title."
	case errorUnexpectedSectionTitleOrTransition:
		s = "Unexpected section title or transition."
	case severeIncompleteSectionTitle:
		s = "Incomplete section title."
	}
	return
}

func (p parserMessage) Level() (s systemMessageLevel) {
	switch p {
	case warningShortUnderline:
		s = levelWarning
	case errorUnexpectedSectionTitle:
		s = levelSevere
	case errorUnexpectedSectionTitleOrTransition:
		s = levelSevere
	case severeIncompleteSectionTitle:
		s = levelSevere
	}
	return
}

type sectionLevels []*SectionNode

func (s *sectionLevels) String() string {
	var out string
	for _, sec := range *s {
		out += fmt.Sprintf("level: %d, rune: %q, overline: %t, length: %d\n",
			sec.Level, sec.UnderLine.Rune, sec.OverLine != nil, sec.Length)
	}
	return out
}

// Returns nil if not found
func (s *sectionLevels) FindByRune(adornChar rune) *SectionNode {
	for _, sec := range *s {
		if sec.UnderLine.Rune == adornChar {
			return sec
		}
	}
	return nil
}

// If exists == true, a section node with the same text and underline has been found in
// sectionLevels, sec is the matching SectionNode. If exists == false, then the sec return value is
// the similarly leveled SectionNode. If exists == false and sec == nil, then the SectionNode added
// to sectionLevels is a new Node.
func (s *sectionLevels) Add(section *SectionNode) (exists bool, sec *SectionNode) {
	sec = s.FindByRune(section.UnderLine.Rune)
	if sec != nil {
		if sec.Text != section.Text {
			section.Level = sec.Level
		}
	} else {
		section.Level = len(*s) + 1
	}
	exists = false
	*s = append(*s, section)
	return
}

func (s *sectionLevels) Level() int {
	return len(*s)
}

// Parse is the entry point for the reStructuredText parser.
func Parse(name, text string) (t *Tree, errors []error) {
	t = New(name)
	if !norm.NFC.IsNormalString(text) {
		text = norm.NFC.String(text)
	}
	t.text = text
	_, errors = t.Parse(text, t)
	return
}

func New(name string) *Tree {
	return &Tree{
		Name:          name,
		Nodes:         newList(),
		nodeTarget:    newList(),
		sectionLevels: new(sectionLevels),
		indentWidth:   indentWidth,
	}
}

const (
	zed         = 3
	indentWidth = 4 // Default indent width
)

type Tree struct {
	Name             string
	Nodes            *NodeList // The root node list
	nodeTarget       *NodeList // Used by the parser to add nodes to a target NodeList
	Errors           []error
	text             string
	lex              *lexer
	tokenBackupCount int
	peekCount        int
	token            [7]*item
	sectionLevels    *sectionLevels // Encountered section levels
	id               int            // The unique id of the node in the tree
	indentWidth      int
	indentLevel      int
}

// startParse initializes the parser, using the lexer.
func (t *Tree) startParse(lex *lexer) {
	t.lex = lex
}

func (t *Tree) Parse(text string, treeSet *Tree) (tree *Tree, errors []error) {
	log.Debugln("Start")
	t.startParse(lex(t.Name, text))
	t.text = text
	t.parse(treeSet)
	log.Debugln("End")
	return t, t.Errors
}

func (t *Tree) parse(tree *Tree) {
	log.Debugln("Start")

	t.nodeTarget = t.Nodes

	for t.peek(1).Type != itemEOF {
		var n Node

		token := t.next()
		log.Infof("\nParser got token: %#+v\n\n", token)

		switch token.Type {
		case itemSectionAdornment:
			n = t.section(token)
		case itemParagraph:
			n = newParagraph(token, &t.id)
		case itemSpace:
			n = t.indent(token)
			if n == nil {
				continue
			}
		case itemTitle, itemBlankLine:
			// itemTitle is consumed when evaluating itemSectionAdornment
			continue
		}

		t.nodeTarget.append(n)
		switch n.NodeType() {
		case NodeSection, NodeBlockQuote:
			// Set the loop to append items to the NodeList of the new section
			t.nodeTarget = reflect.ValueOf(n).Elem().FieldByName("NodeList").Addr().Interface().(*NodeList)
		}
	}

	log.Debugln("End")
}

func (t *Tree) peekBack(pos int) *item {
	return t.token[zed-pos]
}

func (t *Tree) peek(pos int) *item {
	// log.Debugln("\n", "Pos:", pos)
	// log.Debugf("##### peek() before #####\n")
	// spd.Dump(t.token)
	nItem := t.token[zed]
	for i := 1; i <= pos; i++ {
		if t.token[zed+i] != nil {
			nItem = t.token[zed+i]
			log.Debugf("Using %#+v\n", nItem)
			continue
		} else {
			log.Debugln("Getting next item")
			t.token[zed+i] = t.lex.nextItem()
			nItem = t.token[zed+i]
		}
	}
	// log.Debugf("\n##### peek() aftermath #####\n")
	// spd.Dump(t.token)
	// log.Debugf("Returning: %#+v\n", nItem)
	return nItem
}

func (t *Tree) peekSkip(iSkip itemElement) *item {
	var nItem *item
	var count int = 1
	for {
		nItem = t.peek(count)
		if nItem.Type != iSkip {
			 break
		}
		count++
	}
	return nItem
}

func (t *Tree) next() *item {
	// log.Debugf("\n##### next() before #####\n")
	// spd.Dump(t.token)
	for x := 0; x < len(t.token)-1; x++ {
		t.token[x] = t.token[x+1]
		t.token[x+1] = nil
	}
	if t.token[zed] == nil {
		t.token[zed] = t.lex.nextItem()
	}
	// log.Debugf("\n##### next() aftermath #####\n\n")
	// spd.Dump(t.token)
	return t.token[zed]
}

func (t *Tree) section(i *item) Node {
	log.Debugln("Start")
	var overAdorn, indent, title, underAdorn *item

	if pBack := t.peekBack(1); pBack != nil && pBack.Type == itemTitle {
		title = t.peekBack(1)
		underAdorn = i
	} else if pBack := t.peekBack(1); pBack != nil && pBack.Type == itemSpace {
		if t.peekBack(2).Type == itemTitle {
			return t.systemMessage(errorUnexpectedSectionTitle)
		}
		return t.systemMessage(errorUnexpectedSectionTitleOrTransition)
	} else if pFor := t.peekSkip(itemSpace); pFor != nil && pFor.Type == itemTitle {
		overAdorn = i
		t.next()
	loop:
		for {
			switch tTok := t.token[zed]; tTok.Type {
			case itemTitle:
				title = tTok
				t.next()
			case itemSpace:
				indent = tTok
				t.next()
			case itemSectionAdornment:
				underAdorn = tTok
				break loop
			}
		}
	} else if pFor := t.peekSkip(itemSpace); pFor != nil && pFor.Type == itemParagraph {
		t.next()
		t.next()
		return t.systemMessage(severeIncompleteSectionTitle)
	}

	sec := newSection(title, overAdorn, underAdorn, indent, &t.id)
	exists, eSec := t.sectionLevels.Add(sec)
	if !exists && eSec != nil {
		// There is a matching level in sectionLevels
		t.nodeTarget = &(*t.sectionLevels)[sec.Level-2].NodeList
	}

	if indent == nil {
		if title.Length != underAdorn.Length {
			sec.NodeList = append(sec.NodeList, t.systemMessage(warningShortUnderline))
		}
	}

	log.Debugln("End")
	return sec
}

func (t *Tree) systemMessage(err parserMessage) Node {
	var lbText string
	var lbTextLen int
	var backToken int

	s := newSystemMessage(&item{
		Type: itemSystemMessage,
		Line: t.token[zed].Line,
	},
		err.Level(), &t.id)

	msg := newParagraph(&item{
		Text:   err.Message(),
		Length: len(err.Message()),
	}, &t.id)

	log.Debugln("FOUND", err)

	switch err {
	case severeIncompleteSectionTitle:
		lbText = t.token[zed-2].Text.(string) + "\n" +t.token[zed-1].Text.(string)+
			t.token[zed].Text.(string)
		lbTextLen = len(lbText) + 1
	case warningShortUnderline, errorUnexpectedSectionTitle:
		backToken = zed - 1
		if t.peekBack(1).Type == itemSpace {
			backToken = zed - 2
		}
		lbText = t.token[backToken].Text.(string) + "\n" + t.token[zed].Text.(string)
		lbTextLen = len(lbText) + 1
	case errorUnexpectedSectionTitleOrTransition:
		lbText = t.token[zed].Text.(string)
		lbTextLen = len(lbText)
	}

	lb := newLiteralBlock(&item{
		Type:   itemLiteralBlock,
		Text:   lbText,
		Length: lbTextLen, // Add one to account for the backslash
	}, &t.id)

	s.NodeList = append(s.NodeList, msg, lb)
	return s
}

func (t *Tree) indent(i *item) Node {
	level := i.Length / t.indentWidth
	if t.peekBack(1).Type == itemBlankLine {
		if t.indentLevel == level {
			// Append to the current blockquote NodeList
			return nil
		}
		t.indentLevel = level
		return newBlockQuote(&item{Type: itemBlockquote, Line: i.Line}, level, &t.id)
	}
	return nil
}
<commit_msg>parse.go: Rename parser messages<commit_after>// go-rst - A reStructuredText parser for Go
// 2014 (c) The go-rst Authors
// MIT Licensed. See LICENSE for details.

package parse

import (
	"code.google.com/p/go.text/unicode/norm"
	"fmt"
	"github.com/demizer/go-elog"
	"github.com/demizer/go-spew/spew"
	"reflect"
)

var spd = spew.ConfigState{Indent: "\t", DisableMethods: true}

type systemMessageLevel int

const (
	levelInfo systemMessageLevel = iota
	levelWarning
	levelError
	levelSevere
)

var systemMessageLevels = [...]string{
	"INFO",
	"WARNING",
	"ERROR",
	"SEVERE",
}

func (s systemMessageLevel) String() string {
	return systemMessageLevels[s]
}

type parserMessage int

const (
	warningShortUnderline parserMessage = iota
	severeUnexpectedSectionTitle
	severeUnexpectedSectionTitleOrTransition
	severeIncompleteSectionTitle
)

var parserErrors = [...]string{
	"warningShortUnderline",
	"severeUnexpectedSectionTitle",
	"severeUnexpectedSectionTitleOrTransition",
	"severeIncompleteSectionTitle",
}

func (p parserMessage) String() string {
	return parserErrors[p]
}

func (p parserMessage) Message() (s string) {
	switch p {
	case warningShortUnderline:
		s = "Title underline too short."
	case severeUnexpectedSectionTitle:
		s = "Unexpected section title."
	case severeUnexpectedSectionTitleOrTransition:
		s = "Unexpected section title or transition."
	case severeIncompleteSectionTitle:
		s = "Incomplete section title."
	}
	return
}

func (p parserMessage) Level() (s systemMessageLevel) {
	switch p {
	case warningShortUnderline:
		s = levelWarning
	case severeUnexpectedSectionTitle:
		s = levelSevere
	case severeUnexpectedSectionTitleOrTransition:
		s = levelSevere
	case severeIncompleteSectionTitle:
		s = levelSevere
	}
	return
}

type sectionLevels []*SectionNode

func (s *sectionLevels) String() string {
	var out string
	for _, sec := range *s {
		out += fmt.Sprintf("level: %d, rune: %q, overline: %t, length: %d\n",
			sec.Level, sec.UnderLine.Rune, sec.OverLine != nil, sec.Length)
	}
	return out
}

// Returns nil if not found
func (s *sectionLevels) FindByRune(adornChar rune) *SectionNode {
	for _, sec := range *s {
		if sec.UnderLine.Rune == adornChar {
			return sec
		}
	}
	return nil
}

// If exists == true, a section node with the same text and underline has been found in
// sectionLevels, sec is the matching SectionNode. If exists == false, then the sec return value is
// the similarly leveled SectionNode. If exists == false and sec == nil, then the SectionNode added
// to sectionLevels is a new Node.
func (s *sectionLevels) Add(section *SectionNode) (exists bool, sec *SectionNode) {
	sec = s.FindByRune(section.UnderLine.Rune)
	if sec != nil {
		if sec.Text != section.Text {
			section.Level = sec.Level
		}
	} else {
		section.Level = len(*s) + 1
	}
	exists = false
	*s = append(*s, section)
	return
}

func (s *sectionLevels) Level() int {
	return len(*s)
}

// Parse is the entry point for the reStructuredText parser.
func Parse(name, text string) (t *Tree, errors []error) {
	t = New(name)
	if !norm.NFC.IsNormalString(text) {
		text = norm.NFC.String(text)
	}
	t.text = text
	_, errors = t.Parse(text, t)
	return
}

func New(name string) *Tree {
	return &Tree{
		Name:          name,
		Nodes:         newList(),
		nodeTarget:    newList(),
		sectionLevels: new(sectionLevels),
		indentWidth:   indentWidth,
	}
}

const (
	zed         = 3
	indentWidth = 4 // Default indent width
)

type Tree struct {
	Name             string
	Nodes            *NodeList // The root node list
	nodeTarget       *NodeList // Used by the parser to add nodes to a target NodeList
	Errors           []error
	text             string
	lex              *lexer
	tokenBackupCount int
	peekCount        int
	token            [7]*item
	sectionLevels    *sectionLevels // Encountered section levels
	id               int            // The unique id of the node in the tree
	indentWidth      int
	indentLevel      int
}

// startParse initializes the parser, using the lexer.
func (t *Tree) startParse(lex *lexer) {
	t.lex = lex
}

func (t *Tree) Parse(text string, treeSet *Tree) (tree *Tree, errors []error) {
	log.Debugln("Start")
	t.startParse(lex(t.Name, text))
	t.text = text
	t.parse(treeSet)
	log.Debugln("End")
	return t, t.Errors
}

func (t *Tree) parse(tree *Tree) {
	log.Debugln("Start")

	t.nodeTarget = t.Nodes

	for t.peek(1).Type != itemEOF {
		var n Node

		token := t.next()
		log.Infof("\nParser got token: %#+v\n\n", token)

		switch token.Type {
		case itemSectionAdornment:
			n = t.section(token)
		case itemParagraph:
			n = newParagraph(token, &t.id)
		case itemSpace:
			n = t.indent(token)
			if n == nil {
				continue
			}
		case itemTitle, itemBlankLine:
			// itemTitle is consumed when evaluating itemSectionAdornment
			continue
		}

		t.nodeTarget.append(n)
		switch n.NodeType() {
		case NodeSection, NodeBlockQuote:
			// Set the loop to append items to the NodeList of the new section
			t.nodeTarget = reflect.ValueOf(n).Elem().FieldByName("NodeList").Addr().Interface().(*NodeList)
		}
	}

	log.Debugln("End")
}

func (t *Tree) peekBack(pos int) *item {
	return t.token[zed-pos]
}

func (t *Tree) peek(pos int) *item {
	// log.Debugln("\n", "Pos:", pos)
	// log.Debugf("##### peek() before #####\n")
	// spd.Dump(t.token)
	nItem := t.token[zed]
	for i := 1; i <= pos; i++ {
		if t.token[zed+i] != nil {
			nItem = t.token[zed+i]
			log.Debugf("Using %#+v\n", nItem)
			continue
		} else {
			log.Debugln("Getting next item")
			t.token[zed+i] = t.lex.nextItem()
			nItem = t.token[zed+i]
		}
	}
	// log.Debugf("\n##### peek() aftermath #####\n")
	// spd.Dump(t.token)
	// log.Debugf("Returning: %#+v\n", nItem)
	return nItem
}

func (t *Tree) peekSkip(iSkip itemElement) *item {
	var nItem *item
	var count int = 1
	for {
		nItem = t.peek(count)
		if nItem.Type != iSkip {
			 break
		}
		count++
	}
	return nItem
}

func (t *Tree) next() *item {
	// log.Debugf("\n##### next() before #####\n")
	// spd.Dump(t.token)
	for x := 0; x < len(t.token)-1; x++ {
		t.token[x] = t.token[x+1]
		t.token[x+1] = nil
	}
	if t.token[zed] == nil {
		t.token[zed] = t.lex.nextItem()
	}
	// log.Debugf("\n##### next() aftermath #####\n\n")
	// spd.Dump(t.token)
	return t.token[zed]
}

func (t *Tree) section(i *item) Node {
	log.Debugln("Start")
	var overAdorn, indent, title, underAdorn *item

	if pBack := t.peekBack(1); pBack != nil && pBack.Type == itemTitle {
		title = t.peekBack(1)
		underAdorn = i
	} else if pBack := t.peekBack(1); pBack != nil && pBack.Type == itemSpace {
		if t.peekBack(2).Type == itemTitle {
			return t.systemMessage(severeUnexpectedSectionTitle)
		}
		return t.systemMessage(severeUnexpectedSectionTitleOrTransition)
	} else if pFor := t.peekSkip(itemSpace); pFor != nil && pFor.Type == itemTitle {
		overAdorn = i
		t.next()
	loop:
		for {
			switch tTok := t.token[zed]; tTok.Type {
			case itemTitle:
				title = tTok
				t.next()
			case itemSpace:
				indent = tTok
				t.next()
			case itemSectionAdornment:
				underAdorn = tTok
				break loop
			}
		}
	} else if pFor := t.peekSkip(itemSpace); pFor != nil && pFor.Type == itemParagraph {
		t.next()
		t.next()
		return t.systemMessage(severeIncompleteSectionTitle)
	}

	sec := newSection(title, overAdorn, underAdorn, indent, &t.id)
	exists, eSec := t.sectionLevels.Add(sec)
	if !exists && eSec != nil {
		// There is a matching level in sectionLevels
		t.nodeTarget = &(*t.sectionLevels)[sec.Level-2].NodeList
	}

	if indent == nil {
		if title.Length != underAdorn.Length {
			sec.NodeList = append(sec.NodeList, t.systemMessage(warningShortUnderline))
		}
	}

	log.Debugln("End")
	return sec
}

func (t *Tree) systemMessage(err parserMessage) Node {
	var lbText string
	var lbTextLen int
	var backToken int

	s := newSystemMessage(&item{
		Type: itemSystemMessage,
		Line: t.token[zed].Line,
	},
		err.Level(), &t.id)

	msg := newParagraph(&item{
		Text:   err.Message(),
		Length: len(err.Message()),
	}, &t.id)

	log.Debugln("FOUND", err)

	switch err {
	case severeIncompleteSectionTitle:
		lbText = t.token[zed-2].Text.(string) + "\n" +t.token[zed-1].Text.(string)+
			t.token[zed].Text.(string)
		lbTextLen = len(lbText) + 1
	case warningShortUnderline, severeUnexpectedSectionTitle:
		backToken = zed - 1
		if t.peekBack(1).Type == itemSpace {
			backToken = zed - 2
		}
		lbText = t.token[backToken].Text.(string) + "\n" + t.token[zed].Text.(string)
		lbTextLen = len(lbText) + 1
	case severeUnexpectedSectionTitleOrTransition:
		lbText = t.token[zed].Text.(string)
		lbTextLen = len(lbText)
	}

	lb := newLiteralBlock(&item{
		Type:   itemLiteralBlock,
		Text:   lbText,
		Length: lbTextLen, // Add one to account for the backslash
	}, &t.id)

	s.NodeList = append(s.NodeList, msg, lb)
	return s
}

func (t *Tree) indent(i *item) Node {
	level := i.Length / t.indentWidth
	if t.peekBack(1).Type == itemBlankLine {
		if t.indentLevel == level {
			// Append to the current blockquote NodeList
			return nil
		}
		t.indentLevel = level
		return newBlockQuote(&item{Type: itemBlockquote, Line: i.Line}, level, &t.id)
	}
	return nil
}
<|endoftext|>