<commit_before>package getter

import (
	"crypto/sha256"
	"encoding/hex"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"testing"
)

func TestHttpGetter_impl(t *testing.T) {
	var _ Getter = new(HttpGetter)
}

func TestHttpGetter_header(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)
	defer os.RemoveAll(dst)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/header"

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	mainPath := filepath.Join(dst, "main.tf")
	if _, err := os.Stat(mainPath); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func TestHttpGetter_requestHeader(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	g.Header = make(http.Header)
	g.Header.Add("X-Foobar", "foobar")
	dst := tempDir(t)
	defer os.RemoveAll(dst)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/expect-header"
	u.RawQuery = "expected=X-Foobar"

	// Get it!
	if err := g.GetFile(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	if _, err := os.Stat(dst); err != nil {
		t.Fatalf("err: %s", err)
	}
	assertContents(t, dst, "Hello\n")
}

func TestHttpGetter_meta(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)
	defer os.RemoveAll(dst)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/meta"

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	mainPath := filepath.Join(dst, "main.tf")
	if _, err := os.Stat(mainPath); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func TestHttpGetter_metaSubdir(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)
	defer os.RemoveAll(dst)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/meta-subdir"

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	mainPath := filepath.Join(dst, "sub.tf")
	if _, err := os.Stat(mainPath); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func TestHttpGetter_metaSubdirGlob(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)
	defer os.RemoveAll(dst)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/meta-subdir-glob"

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	mainPath := filepath.Join(dst, "sub.tf")
	if _, err := os.Stat(mainPath); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func TestHttpGetter_none(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)
	defer os.RemoveAll(dst)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/none"

	// Get it!
	if err := g.Get(dst, &u); err == nil {
		t.Fatal("should error")
	}
}

func TestHttpGetter_resume(t *testing.T) {
	load := []byte(testHttpMetaStr)
	sha := sha256.New()
	if n, err := sha.Write(load); n != len(load) || err != nil {
		t.Fatalf("sha write failed: %d, %s", n, err)
	}
	checksum := hex.EncodeToString(sha.Sum(nil))
	downloadFrom := len(load) / 2

	ln := testHttpServer(t)
	defer ln.Close()

	dst := tempDir(t)
	defer os.RemoveAll(dst)

	dst = filepath.Join(dst, "..", "range")
	f, err := os.Create(dst)
	if err != nil {
		t.Fatalf("create: %v", err)
	}
	if n, err := f.Write(load[:downloadFrom]); n != downloadFrom || err != nil {
		t.Fatalf("partial file write failed: %d, %s", n, err)
	}
	if err := f.Close(); err != nil {
		t.Fatalf("close failed: %s", err)
	}

	u := url.URL{
		Scheme:   "http",
		Host:     ln.Addr().String(),
		Path:     "/range",
		RawQuery: "checksum=" + checksum,
	}
	t.Logf("url: %s", u.String())

	// Finish getting it!
	if err := GetFile(dst, u.String()); err != nil {
		t.Errorf("finishing download should not error: %v", err)
	}

	b, err := ioutil.ReadFile(dst)
	if err != nil {
		t.Fatalf("readfile failed: %v", err)
	}

	if string(b) != string(load) {
		t.Errorf("file differs: got:\n%s\n expected:\n%s\n", string(b), string(load))
	}

	// Get it again
	if err := GetFile(dst, u.String()); err != nil {
		t.Errorf("should not error: %v", err)
	}
}

func TestHttpGetter_file(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempTestFile(t)
	defer os.RemoveAll(filepath.Dir(dst))

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/file"

	// Get it!
	if err := g.GetFile(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	if _, err := os.Stat(dst); err != nil {
		t.Fatalf("err: %s", err)
	}
	assertContents(t, dst, "Hello\n")
}

func TestHttpGetter_auth(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)
	defer os.RemoveAll(dst)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/meta-auth"
	u.User = url.UserPassword("foo", "bar")

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	mainPath := filepath.Join(dst, "main.tf")
	if _, err := os.Stat(mainPath); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func TestHttpGetter_authNetrc(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)
	defer os.RemoveAll(dst)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/meta"

	// Write the netrc file
	path, closer := tempFileContents(t, fmt.Sprintf(testHttpNetrc, ln.Addr().String()))
	defer closer()
	defer tempEnv(t, "NETRC", path)()

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	mainPath := filepath.Join(dst, "main.tf")
	if _, err := os.Stat(mainPath); err != nil {
		t.Fatalf("err: %s", err)
	}
}

// test round tripper that only returns an error
type errRoundTripper struct{}

func (errRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) {
	return nil, errors.New("test round tripper")
}

// verify that the default httpClient no longer comes from http.DefaultClient
func TestHttpGetter_cleanhttp(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	// break the default http client
	http.DefaultClient.Transport = errRoundTripper{}
	defer func() {
		http.DefaultClient.Transport = http.DefaultTransport
	}()

	g := new(HttpGetter)
	dst := tempDir(t)
	defer os.RemoveAll(dst)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/header"

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func testHttpServer(t *testing.T) net.Listener {
	ln, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	mux := http.NewServeMux()
	mux.HandleFunc("/expect-header", testHttpHandlerExpectHeader)
	mux.HandleFunc("/file", testHttpHandlerFile)
	mux.HandleFunc("/header", testHttpHandlerHeader)
	mux.HandleFunc("/meta", testHttpHandlerMeta)
	mux.HandleFunc("/meta-auth", testHttpHandlerMetaAuth)
	mux.HandleFunc("/meta-subdir", testHttpHandlerMetaSubdir)
	mux.HandleFunc("/meta-subdir-glob", testHttpHandlerMetaSubdirGlob)
	mux.HandleFunc("/range", testHttpHandlerRange)

	var server http.Server
	server.Handler = mux
	go server.Serve(ln)

	return ln
}

func testHttpHandlerExpectHeader(w http.ResponseWriter, r *http.Request) {
	if expected, ok := r.URL.Query()["expected"]; ok {
		if r.Header.Get(expected[0]) != "" {
			w.Write([]byte("Hello\n"))
			return
		}
	}

	w.WriteHeader(400)
}

func testHttpHandlerFile(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Hello\n"))
}

func testHttpHandlerHeader(w http.ResponseWriter, r *http.Request) {
	w.Header().Add("X-Terraform-Get", testModuleURL("basic").String())
	w.WriteHeader(200)
}

func testHttpHandlerMeta(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte(fmt.Sprintf(testHttpMetaStr, testModuleURL("basic").String())))
}

func testHttpHandlerMetaAuth(w http.ResponseWriter, r *http.Request) {
	user, pass, ok := r.BasicAuth()
	if !ok {
		w.WriteHeader(401)
		return
	}

	if user != "foo" || pass != "bar" {
		w.WriteHeader(401)
		return
	}

	w.Write([]byte(fmt.Sprintf(testHttpMetaStr, testModuleURL("basic").String())))
}

func testHttpHandlerMetaSubdir(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte(fmt.Sprintf(testHttpMetaStr, testModuleURL("basic//subdir").String())))
}

func testHttpHandlerMetaSubdirGlob(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte(fmt.Sprintf(testHttpMetaStr, testModuleURL("basic//sub*").String())))
}

func testHttpHandlerNone(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte(testHttpNoneStr))
}

func testHttpHandlerRange(w http.ResponseWriter, r *http.Request) {
	load := []byte(testHttpMetaStr)
	switch r.Method {
	case "HEAD":
		w.Header().Add("accept-ranges", "bytes")
		w.Header().Add("content-length", strconv.Itoa(len(load)))
	default:
		// request should have header "Range: bytes=0-1023"
		// or                         "Range: bytes=123-"
		rangeHeaderValue := strings.Split(r.Header.Get("Range"), "=")[1]
		rng, _ := strconv.Atoi(strings.Split(rangeHeaderValue, "-")[0])
		if rng < 1 || rng > len(load) {
			http.Error(w, "", http.StatusBadRequest)
		}
		w.Write(load[rng:])
	}
}

const testHttpMetaStr = `
<html>
<head>
<meta name="terraform-get" content="%s">
</head>
</html>
`

const testHttpNoneStr = `
<html>
<head>
</head>
</html>
`

const testHttpNetrc = `
machine %s
login foo
password bar
`
<commit_msg>TestHttpGetter_resume: fatal if files are different.<commit_after>package getter

import (
	"crypto/sha256"
	"encoding/hex"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"testing"
)

func TestHttpGetter_impl(t *testing.T) {
	var _ Getter = new(HttpGetter)
}

func TestHttpGetter_header(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)
	defer os.RemoveAll(dst)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/header"

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	mainPath := filepath.Join(dst, "main.tf")
	if _, err := os.Stat(mainPath); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func TestHttpGetter_requestHeader(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	g.Header = make(http.Header)
	g.Header.Add("X-Foobar", "foobar")
	dst := tempDir(t)
	defer os.RemoveAll(dst)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/expect-header"
	u.RawQuery = "expected=X-Foobar"

	// Get it!
	if err := g.GetFile(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	if _, err := os.Stat(dst); err != nil {
		t.Fatalf("err: %s", err)
	}
	assertContents(t, dst, "Hello\n")
}

func TestHttpGetter_meta(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)
	defer os.RemoveAll(dst)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/meta"

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	mainPath := filepath.Join(dst, "main.tf")
	if _, err := os.Stat(mainPath); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func TestHttpGetter_metaSubdir(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)
	defer os.RemoveAll(dst)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/meta-subdir"

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	mainPath := filepath.Join(dst, "sub.tf")
	if _, err := os.Stat(mainPath); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func TestHttpGetter_metaSubdirGlob(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)
	defer os.RemoveAll(dst)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/meta-subdir-glob"

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	mainPath := filepath.Join(dst, "sub.tf")
	if _, err := os.Stat(mainPath); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func TestHttpGetter_none(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)
	defer os.RemoveAll(dst)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/none"

	// Get it!
	if err := g.Get(dst, &u); err == nil {
		t.Fatal("should error")
	}
}

func TestHttpGetter_resume(t *testing.T) {
	load := []byte(testHttpMetaStr)
	sha := sha256.New()
	if n, err := sha.Write(load); n != len(load) || err != nil {
		t.Fatalf("sha write failed: %d, %s", n, err)
	}
	checksum := hex.EncodeToString(sha.Sum(nil))
	downloadFrom := len(load) / 2

	ln := testHttpServer(t)
	defer ln.Close()

	dst := tempDir(t)
	defer os.RemoveAll(dst)

	dst = filepath.Join(dst, "..", "range")
	f, err := os.Create(dst)
	if err != nil {
		t.Fatalf("create: %v", err)
	}
	if n, err := f.Write(load[:downloadFrom]); n != downloadFrom || err != nil {
		t.Fatalf("partial file write failed: %d, %s", n, err)
	}
	if err := f.Close(); err != nil {
		t.Fatalf("close failed: %s", err)
	}

	u := url.URL{
		Scheme:   "http",
		Host:     ln.Addr().String(),
		Path:     "/range",
		RawQuery: "checksum=" + checksum,
	}
	t.Logf("url: %s", u.String())

	// Finish getting it!
	if err := GetFile(dst, u.String()); err != nil {
		t.Errorf("finishing download should not error: %v", err)
	}

	b, err := ioutil.ReadFile(dst)
	if err != nil {
		t.Fatalf("readfile failed: %v", err)
	}

	if string(b) != string(load) {
		t.Fatalf("file differs: got:\n%s\n expected:\n%s\n", string(b), string(load))
	}

	// Get it again
	if err := GetFile(dst, u.String()); err != nil {
		t.Errorf("should not error: %v", err)
	}
}

func TestHttpGetter_file(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempTestFile(t)
	defer os.RemoveAll(filepath.Dir(dst))

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/file"

	// Get it!
	if err := g.GetFile(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	if _, err := os.Stat(dst); err != nil {
		t.Fatalf("err: %s", err)
	}
	assertContents(t, dst, "Hello\n")
}

func TestHttpGetter_auth(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)
	defer os.RemoveAll(dst)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/meta-auth"
	u.User = url.UserPassword("foo", "bar")

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	mainPath := filepath.Join(dst, "main.tf")
	if _, err := os.Stat(mainPath); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func TestHttpGetter_authNetrc(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	g := new(HttpGetter)
	dst := tempDir(t)
	defer os.RemoveAll(dst)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/meta"

	// Write the netrc file
	path, closer := tempFileContents(t, fmt.Sprintf(testHttpNetrc, ln.Addr().String()))
	defer closer()
	defer tempEnv(t, "NETRC", path)()

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}

	// Verify the main file exists
	mainPath := filepath.Join(dst, "main.tf")
	if _, err := os.Stat(mainPath); err != nil {
		t.Fatalf("err: %s", err)
	}
}

// test round tripper that only returns an error
type errRoundTripper struct{}

func (errRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) {
	return nil, errors.New("test round tripper")
}

// verify that the default httpClient no longer comes from http.DefaultClient
func TestHttpGetter_cleanhttp(t *testing.T) {
	ln := testHttpServer(t)
	defer ln.Close()

	// break the default http client
	http.DefaultClient.Transport = errRoundTripper{}
	defer func() {
		http.DefaultClient.Transport = http.DefaultTransport
	}()

	g := new(HttpGetter)
	dst := tempDir(t)
	defer os.RemoveAll(dst)

	var u url.URL
	u.Scheme = "http"
	u.Host = ln.Addr().String()
	u.Path = "/header"

	// Get it!
	if err := g.Get(dst, &u); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func testHttpServer(t *testing.T) net.Listener {
	ln, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	mux := http.NewServeMux()
	mux.HandleFunc("/expect-header", testHttpHandlerExpectHeader)
	mux.HandleFunc("/file", testHttpHandlerFile)
	mux.HandleFunc("/header", testHttpHandlerHeader)
	mux.HandleFunc("/meta", testHttpHandlerMeta)
	mux.HandleFunc("/meta-auth", testHttpHandlerMetaAuth)
	mux.HandleFunc("/meta-subdir", testHttpHandlerMetaSubdir)
	mux.HandleFunc("/meta-subdir-glob", testHttpHandlerMetaSubdirGlob)
	mux.HandleFunc("/range", testHttpHandlerRange)

	var server http.Server
	server.Handler = mux
	go server.Serve(ln)

	return ln
}

func testHttpHandlerExpectHeader(w http.ResponseWriter, r *http.Request) {
	if expected, ok := r.URL.Query()["expected"]; ok {
		if r.Header.Get(expected[0]) != "" {
			w.Write([]byte("Hello\n"))
			return
		}
	}

	w.WriteHeader(400)
}

func testHttpHandlerFile(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Hello\n"))
}

func testHttpHandlerHeader(w http.ResponseWriter, r *http.Request) {
	w.Header().Add("X-Terraform-Get", testModuleURL("basic").String())
	w.WriteHeader(200)
}

func testHttpHandlerMeta(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte(fmt.Sprintf(testHttpMetaStr, testModuleURL("basic").String())))
}

func testHttpHandlerMetaAuth(w http.ResponseWriter, r *http.Request) {
	user, pass, ok := r.BasicAuth()
	if !ok {
		w.WriteHeader(401)
		return
	}

	if user != "foo" || pass != "bar" {
		w.WriteHeader(401)
		return
	}

	w.Write([]byte(fmt.Sprintf(testHttpMetaStr, testModuleURL("basic").String())))
}

func testHttpHandlerMetaSubdir(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte(fmt.Sprintf(testHttpMetaStr, testModuleURL("basic//subdir").String())))
}

func testHttpHandlerMetaSubdirGlob(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte(fmt.Sprintf(testHttpMetaStr, testModuleURL("basic//sub*").String())))
}

func testHttpHandlerNone(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte(testHttpNoneStr))
}

func testHttpHandlerRange(w http.ResponseWriter, r *http.Request) {
	load := []byte(testHttpMetaStr)
	switch r.Method {
	case "HEAD":
		w.Header().Add("accept-ranges", "bytes")
		w.Header().Add("content-length", strconv.Itoa(len(load)))
	default:
		// request should have header "Range: bytes=0-1023"
		// or                         "Range: bytes=123-"
		rangeHeaderValue := strings.Split(r.Header.Get("Range"), "=")[1]
		rng, _ := strconv.Atoi(strings.Split(rangeHeaderValue, "-")[0])
		if rng < 1 || rng > len(load) {
			http.Error(w, "", http.StatusBadRequest)
		}
		w.Write(load[rng:])
	}
}

const testHttpMetaStr = `
<html>
<head>
<meta name="terraform-get" content="%s">
</head>
</html>
`

const testHttpNoneStr = `
<html>
<head>
</head>
</html>
`

const testHttpNetrc = `
machine %s
login foo
password bar
`
<|endoftext|>


<commit_before>package tictactoe

import (
	"bytes"
	"fmt"
)

const (
	standardFieldValue = 4
	dimension          = 3
)

// Game represents a game of Tic-Tac-Toe. Obtain it by invoking the factory function
// NewGame().
type Game struct {
	board         [][]int
	currentPlayer int
	moveCount     int
	gameOver      bool
	hasWinner     bool
}

func (g Game) String() string {
	result := bytes.NewBufferString(fmt.Sprintf(" %s | %s | %s\n", mapValue(g.board[0][0]), mapValue(g.board[0][1]), mapValue(g.board[0][2])))
	result.WriteString("---+---+---\n")
	result.WriteString(fmt.Sprintf(" %s | %s | %s\n", mapValue(g.board[1][0]), mapValue(g.board[1][1]), mapValue(g.board[1][2])))
	result.WriteString("---+---+---\n")
	result.WriteString(fmt.Sprintf(" %s | %s | %s\n", mapValue(g.board[2][0]), mapValue(g.board[2][1]), mapValue(g.board[2][2])))
	return result.String()
}

// NewGame is a factory function for a new game of Tic-Tac-Toe.
func NewGame() *Game {
	b := [][]int{
		{standardFieldValue, standardFieldValue, standardFieldValue},
		{standardFieldValue, standardFieldValue, standardFieldValue},
		{standardFieldValue, standardFieldValue, standardFieldValue},
	}
	return &Game{board: b}
}

// CurrentPlayer returns the player id (0 or 1) of the player who has to play next.
func (g Game) CurrentPlayer() int {
	return g.currentPlayer
}

// Winner returns the player id (0 or 1) of the player who has won or -1 if there
// is no winner (yet).
func (g Game) Winner() int {
	if !g.hasWinner {
		return -1
	}
	return g.currentPlayer
}

// Over returns true if the game is finished and false otherwise.
func (g Game) Over() bool {
	return g.gameOver
}

// Play takes x and y coordinates (each between 0 and 2) and marks it for the
// current player. If the coordinates are out of bounds or the field is already
// marked it will return an error.
func (g *Game) Play(x, y int) error {
	switch {
	case g.gameOver:
		return fmt.Errorf("Game is already over")
	case x < 0 || x > 2 || y < 0 || y > 2:
		return fmt.Errorf("Invalid coordinates")
	case g.board[y][x] != standardFieldValue:
		return fmt.Errorf("Field already marked")
	}

	g.board[y][x] = g.currentPlayer
	g.moveCount++

	checkGameStatus(g, x, y)
	if !g.gameOver {
		g.currentPlayer = (g.currentPlayer + 1) % 2
	}
	return nil
}

func checkGameStatus(g *Game, x, y int) {
	switch {
	case g.moveCount < 4:
		return
	case g.moveCount > 8:
		g.gameOver = true
	}

	winCase := dimension * g.currentPlayer
	var row, col, dia, rdia int
	for i := 0; i < dimension; i++ {
		row += g.board[y][i]
		col += g.board[i][x]
		dia += g.board[i][i]
		rdia += g.board[i][dimension-(i+1)]
	}

	if checkFor(winCase, row, col, dia, rdia) {
		g.gameOver = true
		g.hasWinner = true
	}
}

/* Helper functions */

func mapValue(x int) string {
	switch {
	case x == 0:
		return "X"
	case x == 1:
		return "O"
	default:
		return " "
	}
}

func checkFor(value int, items ...int) bool {
	for _, item := range items {
		if value == item {
			return true
		}
	}
	return false
}
<commit_msg>Fixed typo<commit_after>package tictactoe

import (
	"bytes"
	"fmt"
)

const (
	standardFieldValue = 4
	dimension          = 3
)

// Game represents a game of Tic-Tac-Toe. Obtain it by invoking the factory function
// NewGame().
type Game struct {
	board         [][]int
	currentPlayer int
	moveCount     int
	gameOver      bool
	hasWinner     bool
}

func (g Game) String() string {
	result := bytes.NewBufferString(fmt.Sprintf(" %s | %s | %s\n", mapValue(g.board[0][0]), mapValue(g.board[0][1]), mapValue(g.board[0][2])))
	result.WriteString("---+---+---\n")
	result.WriteString(fmt.Sprintf(" %s | %s | %s\n", mapValue(g.board[1][0]), mapValue(g.board[1][1]), mapValue(g.board[1][2])))
	result.WriteString("---+---+---\n")
	result.WriteString(fmt.Sprintf(" %s | %s | %s\n", mapValue(g.board[2][0]), mapValue(g.board[2][1]), mapValue(g.board[2][2])))
	return result.String()
}

// NewGame is a factory function for a new game of Tic-Tac-Toe.
func NewGame() *Game {
	b := [][]int{
		{standardFieldValue, standardFieldValue, standardFieldValue},
		{standardFieldValue, standardFieldValue, standardFieldValue},
		{standardFieldValue, standardFieldValue, standardFieldValue},
	}
	return &Game{board: b}
}

// CurrentPlayer returns the player id (0 or 1) of the player who has to play next.
func (g Game) CurrentPlayer() int {
	return g.currentPlayer
}

// Winner returns the player id (0 or 1) of the player who has won or -1 if there
// is no winner (yet).
func (g Game) Winner() int {
	if !g.hasWinner {
		return -1
	}
	return g.currentPlayer
}

// Over returns true if the game is finished and false otherwise.
func (g Game) Over() bool {
	return g.gameOver
}

// Play takes x and y coordinates (each between 0 and 2) and marks the field for the
// current player. If the coordinates are out of bounds or the field is already
// marked it will return an error.
func (g *Game) Play(x, y int) error {
	switch {
	case g.gameOver:
		return fmt.Errorf("Game is already over")
	case x < 0 || x > 2 || y < 0 || y > 2:
		return fmt.Errorf("Invalid coordinates")
	case g.board[y][x] != standardFieldValue:
		return fmt.Errorf("Field already marked")
	}

	g.board[y][x] = g.currentPlayer
	g.moveCount++

	checkGameStatus(g, x, y)
	if !g.gameOver {
		g.currentPlayer = (g.currentPlayer + 1) % 2
	}
	return nil
}

func checkGameStatus(g *Game, x, y int) {
	switch {
	case g.moveCount < 4:
		return
	case g.moveCount > 8:
		g.gameOver = true
	}

	winCase := dimension * g.currentPlayer
	var row, col, dia, rdia int
	for i := 0; i < dimension; i++ {
		row += g.board[y][i]
		col += g.board[i][x]
		dia += g.board[i][i]
		rdia += g.board[i][dimension-(i+1)]
	}

	if checkFor(winCase, row, col, dia, rdia) {
		g.gameOver = true
		g.hasWinner = true
	}
}

/* Helper functions */

func mapValue(x int) string {
	switch {
	case x == 0:
		return "X"
	case x == 1:
		return "O"
	default:
		return " "
	}
}

func checkFor(value int, items ...int) bool {
	for _, item := range items {
		if value == item {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package github

import (
	"errors"
	"fmt"
	"github.com/jingweno/octokat"
)

const (
	GitHubHost  string = "github.com"
	OAuthAppURL string = "http://owenou.com/gh"
)

type GitHub struct {
	Project *Project
	Config  *Config
}

func (gh *GitHub) PullRequest(id string) (*octokat.PullRequest, error) {
	client := gh.client()

	return client.PullRequest(gh.repo(), id, nil)
}

func (gh *GitHub) CreatePullRequest(base, head, title, body string) (string, error) {
	client := gh.client()
	params := octokat.PullRequestParams{Base: base, Head: head, Title: title, Body: body}
	options := octokat.Options{Params: params}
	pullRequest, err := client.CreatePullRequest(gh.repo(), &options)
	if err != nil {
		return "", err
	}

	return pullRequest.HTMLURL, nil
}

func (gh *GitHub) CreatePullRequestForIssue(base, head, issue string) (string, error) {
	client := gh.client()
	params := octokat.PullRequestForIssueParams{Base: base, Head: head, Issue: issue}
	options := octokat.Options{Params: params}
	pullRequest, err := client.CreatePullRequest(gh.repo(), &options)
	if err != nil {
		return "", err
	}

	return pullRequest.HTMLURL, nil
}

func (gh *GitHub) Repository(project Project) (*octokat.Repository, error) {
	client := gh.client()
	repo := octokat.Repo{Name: project.Name, UserName: project.Owner}

	return client.Repository(repo, nil)
}

// TODO: detach GitHub from Project
func (gh *GitHub) IsRepositoryExist(project Project) bool {
	repo, err := gh.Repository(project)

	return err == nil && repo != nil
}

func (gh *GitHub) CreateRepository(project Project, description, homepage string, isPrivate bool) (*octokat.Repository, error) {
	params := octokat.RepositoryParams{Name: project.Name, Description: description, Homepage: homepage, Private: isPrivate}
	var org string
	if project.Owner != gh.Config.FetchUser() {
		org = project.Owner
	}

	client := gh.client()
	options := octokat.Options{Params: params}
	return client.CreateRepository(org, &options)
}

func (gh *GitHub) Releases() ([]octokat.Release, error) {
	client := gh.client()
	releases, err := client.Releases(gh.repo(), nil)
	if err != nil {
		return nil, err
	}

	return releases, nil
}

func (gh *GitHub) CiStatus(sha string) (*octokat.Status, error) {
	client := gh.client()
	statuses, err := client.Statuses(gh.repo(), sha, nil)
	if err != nil {
		return nil, err
	}

	if len(statuses) == 0 {
		return nil, nil
	}

	return &statuses[len(statuses)-1], nil
}

func (gh *GitHub) ForkRepository(name, owner string, noRemote bool) (repo *octokat.Repository, err error) {
	client := gh.client()
	config := gh.Config
	r := octokat.Repo{Name: name, UserName: config.User}
	repo, err = client.Repository(r, nil)
	if repo != nil && err == nil {
		msg := fmt.Sprintf("Error creating fork: %s exists on %s", repo.FullName, GitHubHost)
		err = errors.New(msg)
		return
	}

	repo, err = client.Fork(octokat.Repo{Name: name, UserName: owner}, nil)

	return
}

func (gh *GitHub) ExpandRemoteUrl(owner, name string, isSSH bool) (url string) {
	project := gh.Project
	if owner == "origin" {
		config := gh.Config
		owner = config.FetchUser()
	}

	return project.GitURL(name, owner, isSSH)
}

func (gh *GitHub) repo() octokat.Repo {
	project := gh.Project
	return octokat.Repo{Name: project.Name, UserName: project.Owner}
}

func findOrCreateToken(user, password, twoFactorCode string) (string, error) {
	client := octokat.NewClient().WithLogin(user, password)
	options := &octokat.Options{}
	if twoFactorCode != "" {
		headers := octokat.Headers{"X-GitHub-OTP": twoFactorCode}
		options.Headers = headers
	}

	auths, err := client.Authorizations(options)
	if err != nil {
		return "", err
	}

	var token string
	for _, auth := range auths {
		if auth.NoteURL == OAuthAppURL {
			token = auth.Token
			break
		}
	}

	if token == "" {
		authParam := octokat.AuthorizationParams{}
		authParam.Scopes = append(authParam.Scopes, "repo")
		authParam.Note = "gh"
		authParam.NoteURL = OAuthAppURL
		options.Params = authParam

		auth, err := client.CreateAuthorization(options)
		if err != nil {
			return "", err
		}

		token = auth.Token
	}

	return token, nil
}

func (gh *GitHub) client() *octokat.Client {
	config := gh.Config
	config.FetchCredentials()

	return octokat.NewClient().WithToken(config.Token)
}

func New() *GitHub {
	project := CurrentProject()
	c := CurrentConfig()
	c.FetchUser()

	return &GitHub{project, c}
}

// TODO: detach project from GitHub
func NewWithoutProject() *GitHub {
	c := CurrentConfig()
	c.FetchUser()

	return &GitHub{nil, c}
}

func (gh *GitHub) Issues() ([]octokat.Issue, error) {
	client := gh.client()
	issues, err := client.Issues(gh.repo(), nil)
	if err != nil {
		return nil, err
	}

	return issues, nil
}
<commit_msg>Use the first status<commit_after>package github

import (
	"errors"
	"fmt"
	"github.com/jingweno/octokat"
)

const (
	GitHubHost  string = "github.com"
	OAuthAppURL string = "http://owenou.com/gh"
)

type GitHub struct {
	Project *Project
	Config  *Config
}

func (gh *GitHub) PullRequest(id string) (*octokat.PullRequest, error) {
	client := gh.client()

	return client.PullRequest(gh.repo(), id, nil)
}

func (gh *GitHub) CreatePullRequest(base, head, title, body string) (string, error) {
	client := gh.client()
	params := octokat.PullRequestParams{Base: base, Head: head, Title: title, Body: body}
	options := octokat.Options{Params: params}
	pullRequest, err := client.CreatePullRequest(gh.repo(), &options)
	if err != nil {
		return "", err
	}

	return pullRequest.HTMLURL, nil
}

func (gh *GitHub) CreatePullRequestForIssue(base, head, issue string) (string, error) {
	client := gh.client()
	params := octokat.PullRequestForIssueParams{Base: base, Head: head, Issue: issue}
	options := octokat.Options{Params: params}
	pullRequest, err := client.CreatePullRequest(gh.repo(), &options)
	if err != nil {
		return "", err
	}

	return pullRequest.HTMLURL, nil
}

func (gh *GitHub) Repository(project Project) (*octokat.Repository, error) {
	client := gh.client()
	repo := octokat.Repo{Name: project.Name, UserName: project.Owner}

	return client.Repository(repo, nil)
}

// TODO: detach GitHub from Project
func (gh *GitHub) IsRepositoryExist(project Project) bool {
	repo, err := gh.Repository(project)

	return err == nil && repo != nil
}

func (gh *GitHub) CreateRepository(project Project, description, homepage string, isPrivate bool) (*octokat.Repository, error) {
	params := octokat.RepositoryParams{Name: project.Name, Description: description, Homepage: homepage, Private: isPrivate}
	var org string
	if project.Owner != gh.Config.FetchUser() {
		org = project.Owner
	}

	client := gh.client()
	options := octokat.Options{Params: params}
	return client.CreateRepository(org, &options)
}

func (gh *GitHub) Releases() ([]octokat.Release, error) {
	client := gh.client()
	releases, err := client.Releases(gh.repo(), nil)
	if err != nil {
		return nil, err
	}

	return releases, nil
}

func (gh *GitHub) CiStatus(sha string) (*octokat.Status, error) {
	client := gh.client()
	statuses, err := client.Statuses(gh.repo(), sha, nil)
	if err != nil {
		return nil, err
	}

	if len(statuses) == 0 {
		return nil, nil
	}

	return &statuses[0], nil
}

func (gh *GitHub) ForkRepository(name, owner string, noRemote bool) (repo *octokat.Repository, err error) {
	client := gh.client()
	config := gh.Config
	r := octokat.Repo{Name: name, UserName: config.User}
	repo, err = client.Repository(r, nil)
	if repo != nil && err == nil {
		msg := fmt.Sprintf("Error creating fork: %s exists on %s", repo.FullName, GitHubHost)
		err = errors.New(msg)
		return
	}

	repo, err = client.Fork(octokat.Repo{Name: name, UserName: owner}, nil)

	return
}

func (gh *GitHub) ExpandRemoteUrl(owner, name string, isSSH bool) (url string) {
	project := gh.Project
	if owner == "origin" {
		config := gh.Config
		owner = config.FetchUser()
	}

	return project.GitURL(name, owner, isSSH)
}

func (gh *GitHub) repo() octokat.Repo {
	project := gh.Project
	return octokat.Repo{Name: project.Name, UserName: project.Owner}
}

func findOrCreateToken(user, password, twoFactorCode string) (string, error) {
	client := octokat.NewClient().WithLogin(user, password)
	options := &octokat.Options{}
	if twoFactorCode != "" {
		headers := octokat.Headers{"X-GitHub-OTP": twoFactorCode}
		options.Headers = headers
	}

	auths, err := client.Authorizations(options)
	if err != nil {
		return "", err
	}

	var token string
	for _, auth := range auths {
		if auth.NoteURL == OAuthAppURL {
			token = auth.Token
			break
		}
	}

	if token == "" {
		authParam := octokat.AuthorizationParams{}
		authParam.Scopes = append(authParam.Scopes, "repo")
		authParam.Note = "gh"
		authParam.NoteURL = OAuthAppURL
		options.Params = authParam

		auth, err := client.CreateAuthorization(options)
		if err != nil {
			return "", err
		}

		token = auth.Token
	}

	return token, nil
}

func (gh *GitHub) client() *octokat.Client {
	config := gh.Config
	config.FetchCredentials()

	return octokat.NewClient().WithToken(config.Token)
}

func New() *GitHub {
	project := CurrentProject()
	c := CurrentConfig()
	c.FetchUser()

	return &GitHub{project, c}
}

// TODO: detach project from GitHub
func NewWithoutProject() *GitHub {
	c := CurrentConfig()
	c.FetchUser()

	return &GitHub{nil, c}
}

func (gh *GitHub) Issues() ([]octokat.Issue, error) {
	client := gh.client()
	issues, err := client.Issues(gh.repo(), nil)
	if err != nil {
		return nil, err
	}

	return issues, nil
}
<|endoftext|>


<commit_before>package github

import (
	"errors"
	"fmt"
	"github.com/jingweno/octokat"
	"github.com/octokit/go-octokit"
)

const (
	GitHubHost  string = "github.com"
	OAuthAppURL string = "http://owenou.com/gh"
)

type GitHub struct {
	Project *Project
	Config  *Config
}

func (gh *GitHub) PullRequest(id string) (*octokat.PullRequest, error) {
	client := gh.client()

	return client.PullRequest(gh.repo(), id, nil)
}

func (gh *GitHub) CreatePullRequest(base, head, title, body string) (string, error) {
	client := gh.client()
	params := octokat.PullRequestParams{Base: base, Head: head, Title: title, Body: body}
	options := octokat.Options{Params: params}
	pullRequest, err := client.CreatePullRequest(gh.repo(), &options)
	if err != nil {
		return "", err
	}

	return pullRequest.HTMLURL, nil
}

func (gh *GitHub) CreatePullRequestForIssue(base, head, issue string) (string, error) {
	client := gh.client()
	params := octokat.PullRequestForIssueParams{Base: base, Head: head, Issue: issue}
	options := octokat.Options{Params: params}
	pullRequest, err := client.CreatePullRequest(gh.repo(), &options)
	if err != nil {
		return "", err
	}

	return pullRequest.HTMLURL, nil
}

func (gh *GitHub) Repository(project Project) (*octokat.Repository, error) {
	client := gh.client()
	repo := octokat.Repo{Name: project.Name, UserName: project.Owner}

	return client.Repository(repo, nil)
}

// TODO: detach GitHub from Project
func (gh *GitHub) IsRepositoryExist(project Project) bool {
	repo, err := gh.Repository(project)

	return err == nil && repo != nil
}

func (gh *GitHub) CreateRepository(project Project, description, homepage string, isPrivate bool) (*octokat.Repository, error) {
	params := octokat.RepositoryParams{Name: project.Name, Description: description, Homepage: homepage, Private: isPrivate}
	var org string
	if project.Owner != gh.Config.FetchUser() {
		org = project.Owner
	}

	client := gh.client()
	options := octokat.Options{Params: params}
	return client.CreateRepository(org, &options)
}

func (gh *GitHub) Releases() ([]octokat.Release, error) {
	client := gh.client()
	releases, err := client.Releases(gh.repo(), nil)
	if err != nil {
		return nil, err
	}

	return releases, nil
}

func (gh *GitHub) CiStatus(sha string) (*octokat.Status, error) {
	client := gh.client()
	statuses, err := client.Statuses(gh.repo(), sha, nil)
	if err != nil {
		return nil, err
	}

	if len(statuses) == 0 {
		return nil, nil
	}

	return &statuses[0], nil
}

func (gh *GitHub) ForkRepository(name, owner string, noRemote bool) (repo *octokat.Repository, err error) {
	client := gh.client()
	config := gh.Config
	r := octokat.Repo{Name: name, UserName: config.User}
	repo, err = client.Repository(r, nil)
	if repo != nil && err == nil {
		msg := fmt.Sprintf("Error creating fork: %s exists on %s", repo.FullName, GitHubHost)
		err = errors.New(msg)
		return
	}

	repo, err = client.Fork(octokat.Repo{Name: name, UserName: owner}, nil)

	return
}

func (gh *GitHub) ExpandRemoteUrl(owner, name string, isSSH bool) (url string) {
	project := gh.Project
	if owner == "origin" {
		config := gh.Config
		owner = config.FetchUser()
	}

	return project.GitURL(name, owner, isSSH)
}

func (gh *GitHub) repo() octokat.Repo {
	project := gh.Project
	return octokat.Repo{Name: project.Name, UserName: project.Owner}
}

func findOrCreateToken(user, password, twoFactorCode string) (string, error) {
	client := octokat.NewClient().WithLogin(user, password)
	options := &octokat.Options{}
	if twoFactorCode != "" {
		headers := octokat.Headers{"X-GitHub-OTP": twoFactorCode}
		options.Headers = headers
	}

	auths, err := client.Authorizations(options)
	if err != nil {
		return "", err
	}

	var token string
	for _, auth := range auths {
		if auth.NoteURL == OAuthAppURL {
			token = auth.Token
			break
		}
	}

	if token == "" {
		authParam := octokat.AuthorizationParams{}
		authParam.Scopes = append(authParam.Scopes, "repo")
		authParam.Note = "gh"
		authParam.NoteURL = OAuthAppURL
		options.Params = authParam

		auth, err := client.CreateAuthorization(options)
		if err != nil {
			return "", err
		}

		token = auth.Token
	}

	return token, nil
}

func (gh *GitHub) client() *octokat.Client {
	config := gh.Config
	config.FetchCredentials()

	return octokat.NewClient().WithToken(config.Token)
}

func (gh *GitHub) octokit() *octokit.Client {
	return octokit.NewClient()
}

func New() *GitHub {
	project := CurrentProject()
	c := CurrentConfig()
	c.FetchUser()

	return &GitHub{project, c}
}

// TODO: detach project from GitHub
func NewWithoutProject() *GitHub {
	c := CurrentConfig()
	c.FetchUser()

	return &GitHub{nil, c}
}

func (gh *GitHub) Issues() ([]octokat.Issue, error) {
	client := gh.client()
	issues, err := client.Issues(gh.repo(), nil)
	if err != nil {
		return nil, err
	}

	return issues, nil
}
<commit_msg>Change repository API to use octokit<commit_after>package github

import (
	"errors"
	"fmt"
	"github.com/jingweno/octokat"
	"github.com/octokit/go-octokit"
)

const (
	GitHubHost  string = "github.com"
	OAuthAppURL string = "http://owenou.com/gh"
)

type GitHub struct {
	Project *Project
	Config  *Config
}

func (gh *GitHub) PullRequest(id string) (*octokat.PullRequest, error) {
	client := gh.client()

	return client.PullRequest(gh.repo(), id, nil)
}

func (gh *GitHub) CreatePullRequest(base, head, title, body string) (string, error) {
	client := gh.client()
	params := octokat.PullRequestParams{Base: base, Head: head, Title: title, Body: body}
	options := octokat.Options{Params: params}
	pullRequest, err := client.CreatePullRequest(gh.repo(), &options)
	if err != nil {
		return "", err
	}

	return pullRequest.HTMLURL, nil
}

func (gh *GitHub) CreatePullRequestForIssue(base, head, issue string) (string, error) {
	client := gh.client()
	params := octokat.PullRequestForIssueParams{Base: base, Head: head, Issue: issue}
	options := octokat.Options{Params: params}
	pullRequest, err := client.CreatePullRequest(gh.repo(), &options)
	if err != nil {
		return "", err
	}

	return pullRequest.HTMLURL, nil
}

func (gh *GitHub) Repository(project Project) (repo *octokit.Repository, err error) {
	client := gh.octokit()
	repoService, err := client.Repositories(&octokit.RepositoryURL, octokit.M{"owner": project.Owner, "repo": project.Name})
	if err != nil {
		return
	}

	repo, err = repoService.Get()

	return
}

// TODO: detach GitHub from Project
func (gh *GitHub) IsRepositoryExist(project Project) bool {
	repo, err := gh.Repository(project)

	return err == nil && repo != nil
}

func (gh *GitHub) CreateRepository(project Project, description, homepage string, isPrivate bool) (repo *octokit.Repository, err error) {
	var repoURL octokit.Hyperlink
	if project.Owner != gh.Config.FetchUser() {
		repoURL = octokit.OrgRepositoriesURL
	} else {
		repoURL = octokit.UserRepositoriesURL
	}

	client := gh.octokit()
	repoService, err := client.Repositories(&repoURL, octokit.M{"org": project.Owner})
	if err != nil {
		return
	}

	params := octokat.Repository{Name: project.Name, Description: description, Homepage: homepage, Private: isPrivate}
	repo, err = repoService.Create(params)

	return
}

func (gh *GitHub) Releases() ([]octokat.Release, error) {
	client := gh.client()
	releases, err := client.Releases(gh.repo(), nil)
	if err != nil {
		return nil, err
	}

	return releases, nil
}

func (gh *GitHub) CiStatus(sha string) (*octokat.Status, error) {
	client := gh.client()
	statuses, err := client.Statuses(gh.repo(), sha, nil)
	if err != nil {
		return nil, err
	}

	if len(statuses) == 0 {
		return nil, nil
	}

	return &statuses[0], nil
}

func (gh *GitHub) ForkRepository(name, owner string, noRemote bool) (repo *octokat.Repository, err error) {
	client := gh.client()
	config := gh.Config
	r := octokat.Repo{Name: name, UserName: config.User}
	repo, err = client.Repository(r, nil)
	if repo != nil && err == nil {
		msg := fmt.Sprintf("Error creating fork: %s exists on %s", repo.FullName, GitHubHost)
		err = errors.New(msg)
		return
	}

	repo, err = client.Fork(octokat.Repo{Name: name, UserName: owner}, nil)

	return
}

func (gh *GitHub) ExpandRemoteUrl(owner, name string, isSSH bool) (url string) {
	project := gh.Project
	if owner == "origin" {
		config := gh.Config
		owner = config.FetchUser()
	}

	return project.GitURL(name, owner, isSSH)
}

func (gh *GitHub) repo() octokat.Repo {
	project := gh.Project
	return octokat.Repo{Name: project.Name, UserName: project.Owner}
}

func findOrCreateToken(user, password, twoFactorCode string) (string, error) {
	client := octokat.NewClient().WithLogin(user, password)
	options := &octokat.Options{}
	if twoFactorCode != "" {
		headers := octokat.Headers{"X-GitHub-OTP": twoFactorCode}
		options.Headers = headers
	}

	auths, err := client.Authorizations(options)
	if err != nil {
		return "", err
	}

	var token string
	for _, auth := range auths {
		if auth.NoteURL == OAuthAppURL {
			token = auth.Token
			break
		}
	}

	if token == "" {
		authParam := octokat.AuthorizationParams{}
		authParam.Scopes = append(authParam.Scopes, "repo")
		authParam.Note = "gh"
		authParam.NoteURL = OAuthAppURL
		options.Params = authParam

		auth, err := client.CreateAuthorization(options)
		if err != nil {
			return "", err
		}

		token = auth.Token
	}

	return token, nil
}

func (gh *GitHub) client() *octokat.Client {
	config := gh.Config
	config.FetchCredentials()

	return octokat.NewClient().WithToken(config.Token)
}

func (gh *GitHub) octokit() *octokit.Client {
	config := gh.Config
	config.FetchCredentials()
	tokenAuth := octokit.TokenAuth{AccessToken: config.Token}

	return octokit.NewClient(tokenAuth)
}

func New() *GitHub {
	project := CurrentProject()
	c := CurrentConfig()
	c.FetchUser()

	return &GitHub{project, c}
}

// TODO: detach project from GitHub
func NewWithoutProject() *GitHub {
	c := CurrentConfig()
	c.FetchUser()

	return &GitHub{nil, c}
}

func (gh *GitHub) Issues() ([]octokat.Issue, error) {
	client := gh.client()
	issues, err := client.Issues(gh.repo(), nil)
	if err != nil {
		return nil, err
	}

	return issues, nil
}
<|endoftext|>


<commit_before>package godot

import (
	"unsafe"
)

/*
#include <stdio.h>
#include <stdlib.h>
#include <godot/gdnative.h>
#include <godot_nativescript.h>
*/
import "C"

// goToGodotConverter is a function that will convert a Go object into
// a Godot object.
type goToGodotConverter func(goObject interface{}) unsafe.Pointer

// goToGodotConversionMap is an internal mapping of Go types to functions that can
// convert to Godot types. This mapping is essentially a more optimal case/switch
// system for converting Go types to Godot types that can be used as arguments to
// a Godot function. This is used with CallParentMethod to convert go types into
// godot types as an unsafe pointer. These go inside a C function call, and regular
// Go pointers should not be used.
var goToGodotConversionMap = map[string]goToGodotConverter{
	"bool": func(goObject interface{}) unsafe.Pointer {
		boolArg := C.godot_bool(goObject.(bool))
		return unsafe.Pointer(&boolArg)
	},
	"int64": func(goObject interface{}) unsafe.Pointer {
		var intArg C.int64_t
		intArg = C.int64_t(goObject.(int64))
		return unsafe.Pointer(&intArg)
	},
	"uint64": func(goObject interface{}) unsafe.Pointer {
		var intArg C.uint64_t
		intArg = C.uint64_t(goObject.(uint64))
		return unsafe.Pointer(&intArg)
	},
	"float64": func(goObject interface{}) unsafe.Pointer {
		floatArg := C.double(goObject.(float64))
		return unsafe.Pointer(&floatArg)
	},
	"string": func(goObject interface{}) unsafe.Pointer {
		stringArg := stringAsGodotString(goObject.(string))
		return unsafe.Pointer(stringArg)
	},
	"*Array": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*Array)
		return unsafe.Pointer(arg.array)
	},
	"*Basis": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*Basis)
		return unsafe.Pointer(arg.basis)
	},
	"*Color": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*Color)
		return unsafe.Pointer(arg.color)
	},
	"*Dictionary": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*Dictionary)
		return unsafe.Pointer(arg.dictionary)
	},
	"*NodePath": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*NodePath)
		return unsafe.Pointer(arg.nodePath)
	},
	"*Plane": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*Plane)
		return unsafe.Pointer(arg.plane)
	},
	"*Quat": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*Quat)
		return unsafe.Pointer(arg.quat)
	},
	"*Rect2": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*Rect2)
		return unsafe.Pointer(arg.rect2)
	},
	"*Rect3": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*Rect3)
		return unsafe.Pointer(arg.rect3)
	},
	"*RID": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*RID)
		return unsafe.Pointer(arg.rid)
	},
	"*Transform": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*Transform)
		return unsafe.Pointer(arg.transform)
	},
	"*Transform2D": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*Transform2D)
		return unsafe.Pointer(arg.transform2d)
	},
	"*Variant": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*Variant)
		return unsafe.Pointer(arg.variant)
	},
	"*Vector2": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*Vector2)
		return unsafe.Pointer(arg.vector2)
	},
	"*Vector3": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*Vector3)
		return unsafe.Pointer(arg.vector3)
	},
}

//variant type conversions
func variantAsBool(variant *C.godot_variant) bool {
	godotBool := C.godot_variant_as_bool(variant)
	return bool(godotBool)
}

func boolAsVariant(value bool) *C.godot_variant {
	var variant C.godot_variant
	godotBool := boolAsGodotBool(value)
	C.godot_variant_new_bool(&variant, godotBool)

	return &variant
}

func variantAsUInt(variant *C.godot_variant) uint64 {
	godotUInt := C.godot_variant_as_uint(variant)
	return uint64(godotUInt)
}

func uIntAsVariant(value uint64) *C.godot_variant {
	var variant C.godot_variant
	cUInt64 := uIntAsCUInt64(value)
	C.godot_variant_new_uint(&variant, cUInt64)

	return &variant
}

func variantAsInt(variant *C.godot_variant) int64 {
	godotInt := C.godot_variant_as_int(variant)
	return int64(godotInt)
}

func intAsVariant(value int64) *C.godot_variant {
	var variant C.godot_variant
	cInt64 := intAsCInt64(value)
	C.godot_variant_new_int(&variant, cInt64)

	return &variant
}

func variantAsReal(variant *C.godot_variant) float64 {
	godotFloat := C.godot_variant_as_real(variant)
	return float64(godotFloat)
}

func realAsVariant(value float64) *C.godot_variant {
	var variant C.godot_variant
	cDouble := realAsCReal(value)
	C.godot_variant_new_real(&variant, cDouble)

	return &variant
}

func variantAsString(variant *C.godot_variant) string {
	godotString := C.godot_variant_as_string(variant)

	return godotStringAsString(&godotString)
}

func stringAsVariant(value string) *C.godot_variant {
	var variant C.godot_variant
	godotString := stringAsGodotString(value)
	C.godot_variant_new_string(&variant, godotString)

	return &variant
}

func variantAsNodePath(variant *C.godot_variant) *NodePath {
	nodePath := C.godot_variant_as_node_path(variant)

	return &NodePath{
		nodePath: &nodePath,
	}
}

func nodePathAsVariant(nodePath *NodePath) *C.godot_variant {
	var variant C.godot_variant
	C.godot_variant_new_node_path(&variant, nodePath.nodePath)

	return &variant
}

//Non-variant type conversions
func basisAsGodotBasis(value Basis) *C.godot_basis {
	return value.basis
}

func godotBasisAsBasis(value C.godot_basis) *Basis {
	return &Basis{basis: &value}
}

func boolAsGodotBool(value bool) C.godot_bool {
	return C.godot_bool(value)
}

func godotBoolAsBool(value C.godot_bool) bool {
	return bool(value)
}

func uIntAsCUInt64(value uint64) C.uint64_t {
	return C.uint64_t(value)
}

func intAsCInt64(value int64) C.int64_t {
	return C.int64_t(value)
}

func intAsGodotInt(value int64) C.godot_int {
	return C.godot_int(value)
}

func godotIntAsInt(value C.godot_int) int64 {
	return int64(value)
}

func quatAsGodotQuat(value *Quat) *C.godot_quat {

	return value.quat
}

func godotQuatAsQuat(value C.godot_quat) *Quat {
	return &Quat{quat: &value}
}

func realAsCReal(value float64) C.double {
	return C.double(value)
}

func realAsGodotReal(value float64) C.godot_real {
	return C.godot_real(value)
}

func godotRealAsReal(value C.godot_real) float64 {
	return float64(value)
}

func stringAsGodotString(value string) *C.godot_string {
	var godotString C.godot_string
	cString := C.CString(value)
	C.godot_string_new_data(&godotString, cString, C.int(len(value)))

	return &godotString
}

func godotStringAsString(value *C.godot_string) string {
	godotCString := C.godot_string_c_str(value)

	return C.GoString(godotCString)
}

func vec2AsGodotVec2(value Vector2) *C.godot_vector2 {
	return value.vector2
}

func godotVec2AsVec2(value C.godot_vector2) *Vector2 {
	return &Vector2{vector2: &value}
}

func vec3AsGodotVec3(value Vector3) *C.godot_vector3 {
	return value.vector3
}

func godotVec3AsVec3(value C.godot_vector3) *Vector3 {
	return &Vector3{vector3: &value}
}

func vec3AxisAsGodotVec3Axis(value Vec3Axis) C.godot_vector3_axis {
	return C.godot_vector3_axis(value)
}

func godotVec3AxisAsVec3Axis(value C.godot_vector3_axis) Vec3Axis {
	return Vec3Axis(value)
}

/*
TODO:
godot_array GDAPI godot_variant_as_array(const godot_variant *p_self);
godot_color GDAPI godot_variant_as_color(const godot_variant *p_self);
godot_dictionary GDAPI godot_variant_as_dictionary(const godot_variant *p_self);
godot_object GDAPI *godot_variant_as_object(const godot_variant *p_self);
godot_plane GDAPI godot_variant_as_plane(const godot_variant *p_self);
godot_pool_byte_array GDAPI godot_variant_as_pool_byte_array(const godot_variant *p_self);
godot_pool_color_array GDAPI godot_variant_as_pool_color_array(const godot_variant *p_self);
godot_pool_int_array GDAPI godot_variant_as_pool_int_array(const godot_variant *p_self);
godot_pool_real_array GDAPI godot_variant_as_pool_real_array(const godot_variant *p_self);
godot_pool_string_array GDAPI godot_variant_as_pool_string_array(const godot_variant *p_self);
godot_pool_vector2_array GDAPI godot_variant_as_pool_vector2_array(const godot_variant *p_self);
godot_pool_vector3_array GDAPI godot_variant_as_pool_vector3_array(const godot_variant *p_self);
godot_quat GDAPI godot_variant_as_quat(const godot_variant *p_self);
godot_rect2 GDAPI godot_variant_as_rect2(const godot_variant *p_self);
godot_rect3 GDAPI godot_variant_as_rect3(const godot_variant *p_self);
godot_rid GDAPI godot_variant_as_rid(const godot_variant *p_self);
godot_transform GDAPI godot_variant_as_transform(const godot_variant *p_self);
godot_transform2d GDAPI godot_variant_as_transform2d(const godot_variant *p_self);

PRIORITY:
godot_basis GDAPI godot_variant_as_basis(const godot_variant *p_self);
godot_vector2 GDAPI godot_variant_as_vector2(const godot_variant *p_self);
godot_vector3 GDAPI godot_variant_as_vector3(const godot_variant *p_self);
*/
<commit_msg>Update convert.go<commit_after>package godot

import (
	"unsafe"
)

/*
#include <stdio.h>
#include <stdlib.h>
#include <godot/gdnative.h>
#include <godot_nativescript.h>
*/
import "C"

// goToGodotConverter is a function that will convert a Go object into
// a Godot object.
type goToGodotConverter func(goObject interface{}) unsafe.Pointer

// goToGodotConversionMap is an internal mapping of Go types to functions that can
// convert to Godot types. This mapping is essentially a more optimal case/switch
// system for converting Go types to Godot types that can be used as arguments to
// a Godot function. This is used with CallParentMethod to convert go types into
// godot types as an unsafe pointer. These go inside a C function call, and regular
// Go pointers should not be used.
var goToGodotConversionMap = map[string]goToGodotConverter{
	"bool": func(goObject interface{}) unsafe.Pointer {
		boolArg := C.godot_bool(goObject.(bool))
		return unsafe.Pointer(&boolArg)
	},
	"int64": func(goObject interface{}) unsafe.Pointer {
		var intArg C.int64_t
		intArg = C.int64_t(goObject.(int64))
		return unsafe.Pointer(&intArg)
	},
	"uint64": func(goObject interface{}) unsafe.Pointer {
		var intArg C.uint64_t
		intArg = C.uint64_t(goObject.(uint64))
		return unsafe.Pointer(&intArg)
	},
	"float64": func(goObject interface{}) unsafe.Pointer {
		floatArg := C.double(goObject.(float64))
		return unsafe.Pointer(&floatArg)
	},
	"string": func(goObject interface{}) unsafe.Pointer {
		stringArg := stringAsGodotString(goObject.(string))
		return unsafe.Pointer(stringArg)
	},
	"*Array": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*Array)
		return unsafe.Pointer(arg.array)
	},
	"*Basis": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*Basis)
		return unsafe.Pointer(arg.basis)
	},
	"*Color": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*Color)
		return unsafe.Pointer(arg.color)
	},
	"*Dictionary": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*Dictionary)
		return unsafe.Pointer(arg.dictionary)
	},
	"*NodePath": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*NodePath)
		return unsafe.Pointer(arg.nodePath)
	},
	"*Plane": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*Plane)
		return unsafe.Pointer(arg.plane)
	},
	"*Quat": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*Quat)
		return unsafe.Pointer(arg.quat)
	},
	"*Rect2": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*Rect2)
		return unsafe.Pointer(arg.rect2)
	},
	"*Rect3": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*Rect3)
		return unsafe.Pointer(arg.rect3)
	},
	"*RID": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*RID)
		return unsafe.Pointer(arg.rid)
	},
	"*Transform": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*Transform)
		return unsafe.Pointer(arg.transform)
	},
	"*Transform2D": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*Transform2D)
		return unsafe.Pointer(arg.transform2d)
	},
	"*Variant": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*Variant)
		return unsafe.Pointer(arg.variant)
	},
	"*Vector2": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*Vector2)
		return unsafe.Pointer(arg.vector2)
	},
	"*Vector3": func(goObject interface{}) unsafe.Pointer {
		arg := goObject.(*Vector3)
		return unsafe.Pointer(arg.vector3)
	},
}

//variant type conversions
func variantAsBool(variant *C.godot_variant) bool {
	godotBool := C.godot_variant_as_bool(variant)
	return bool(godotBool)
}

func boolAsVariant(value bool) *C.godot_variant {
	var variant C.godot_variant
	godotBool := boolAsGodotBool(value)
	C.godot_variant_new_bool(&variant, godotBool)

	return &variant
}

func variantAsUInt(variant *C.godot_variant) uint64 {
	godotUInt := C.godot_variant_as_uint(variant)
	return uint64(godotUInt)
}

func uIntAsVariant(value uint64) *C.godot_variant {
	var variant C.godot_variant
	cUInt64 := uIntAsCUInt64(value)
	C.godot_variant_new_uint(&variant, cUInt64)

	return &variant
}

func variantAsInt(variant *C.godot_variant) int64 {
	godotInt := C.godot_variant_as_int(variant)
	return int64(godotInt)
}

func intAsVariant(value int64) *C.godot_variant {
	var variant C.godot_variant
	cInt64 := intAsCInt64(value)
	C.godot_variant_new_int(&variant, cInt64)

	return &variant
}

func variantAsReal(variant *C.godot_variant) float64 {
	godotFloat := C.godot_variant_as_real(variant)
	return float64(godotFloat)
}

func realAsVariant(value float64) *C.godot_variant {
	var variant C.godot_variant
	cDouble := realAsCReal(value)
	C.godot_variant_new_real(&variant, cDouble)

	return &variant
}

func variantAsString(variant *C.godot_variant) string {
	godotString := C.godot_variant_as_string(variant)

	return godotStringAsString(&godotString)
}

func stringAsVariant(value string) *C.godot_variant {
	var variant C.godot_variant
	godotString := stringAsGodotString(value)
	C.godot_variant_new_string(&variant, godotString)

	return &variant
}

func variantAsNodePath(variant *C.godot_variant) *NodePath {
	nodePath := C.godot_variant_as_node_path(variant)

	return &NodePath{
		nodePath: &nodePath,
	}
}

func nodePathAsVariant(nodePath *NodePath) *C.godot_variant {
	var variant C.godot_variant
	C.godot_variant_new_node_path(&variant, nodePath.nodePath)

	return &variant
}

//Non-variant type conversions
func basisAsGodotBasis(value Basis) *C.godot_basis {
	return value.basis
}

func godotBasisAsBasis(value C.godot_basis) *Basis {
	return &Basis{basis: &value}
}

func boolAsGodotBool(value bool) C.godot_bool {
	return C.godot_bool(value)
}

func godotBoolAsBool(value C.godot_bool) bool {
	return bool(value)
}

func uIntAsCUInt64(value uint64) C.uint64_t {
	return C.uint64_t(value)
}

func intAsCInt64(value int64) C.int64_t {
	return C.int64_t(value)
}

func intAsGodotInt(value int64) C.godot_int {
	return C.godot_int(value)
}

func godotIntAsInt(value C.godot_int) int64 {
	return int64(value)
}

func quatAsGodotQuat(value *Quat) *C.godot_quat {
	return value.quat
}

func godotQuatAsQuat(value C.godot_quat) *Quat {
	return &Quat{quat: &value}
}

func realAsCReal(value float64) C.double {
	return C.double(value)
}

func realAsGodotReal(value float64) C.godot_real {
	return C.godot_real(value)
}

func godotRealAsReal(value C.godot_real) float64 {
	return float64(value)
}

func stringAsGodotString(value string) *C.godot_string {
	var godotString C.godot_string
	cString := C.CString(value)
	C.godot_string_new_data(&godotString, cString, C.int(len(value)))

	return &godotString
}

func godotStringAsString(value *C.godot_string) string {
	godotCString := C.godot_string_c_str(value)

	return C.GoString(godotCString)
}

func vec2AsGodotVec2(value Vector2) *C.godot_vector2 {
	return value.vector2
}

func godotVec2AsVec2(value C.godot_vector2) *Vector2 {
	return &Vector2{vector2: &value}
}

func vec3AsGodotVec3(value Vector3) *C.godot_vector3 {
	return value.vector3
}

func godotVec3AsVec3(value C.godot_vector3) *Vector3 {
	return &Vector3{vector3: &value}
}

func vec3AxisAsGodotVec3Axis(value Vec3Axis) C.godot_vector3_axis {
	return C.godot_vector3_axis(value)
}

func godotVec3AxisAsVec3Axis(value C.godot_vector3_axis) Vec3Axis {
	return Vec3Axis(value)
}

/*
TODO:
godot_array GDAPI godot_variant_as_array(const godot_variant *p_self);
godot_color GDAPI godot_variant_as_color(const godot_variant *p_self);
godot_dictionary GDAPI godot_variant_as_dictionary(const godot_variant *p_self);
godot_object GDAPI *godot_variant_as_object(const godot_variant *p_self);
godot_plane GDAPI godot_variant_as_plane(const godot_variant *p_self);
godot_pool_byte_array GDAPI godot_variant_as_pool_byte_array(const godot_variant *p_self);
godot_pool_color_array GDAPI godot_variant_as_pool_color_array(const godot_variant *p_self);
godot_pool_int_array GDAPI godot_variant_as_pool_int_array(const godot_variant *p_self);
godot_pool_real_array GDAPI godot_variant_as_pool_real_array(const godot_variant *p_self);
godot_pool_string_array GDAPI godot_variant_as_pool_string_array(const godot_variant *p_self);
godot_pool_vector2_array GDAPI godot_variant_as_pool_vector2_array(const godot_variant *p_self);
godot_pool_vector3_array GDAPI godot_variant_as_pool_vector3_array(const godot_variant *p_self);
godot_quat GDAPI godot_variant_as_quat(const godot_variant *p_self);
godot_rect2 GDAPI godot_variant_as_rect2(const godot_variant *p_self);
godot_rect3 GDAPI godot_variant_as_rect3(const godot_variant *p_self);
godot_rid GDAPI godot_variant_as_rid(const godot_variant *p_self);
godot_transform GDAPI godot_variant_as_transform(const godot_variant *p_self);
godot_transform2d GDAPI godot_variant_as_transform2d(const godot_variant *p_self);

PRIORITY:
godot_basis GDAPI godot_variant_as_basis(const godot_variant *p_self);
godot_vector2 GDAPI godot_variant_as_vector2(const godot_variant *p_self);
godot_vector3 GDAPI godot_variant_as_vector3(const godot_variant *p_self);
*/
<|endoftext|>


<commit_before>package dragon

import (
	"go/ast"
	"go/parser"
	"go/token"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/blang/semver"
)

type mod struct {
	version string
	lib     lib
}

var regPath = regexp.MustCompile("@v[0-9]+\\.[0-9]+\\.[0-9].*?(/|$)")

func extractImportPathAndVersion(path string) (string, string) {
	version := regPath.FindString(path)
	importPath := regPath.ReplaceAllString(path, "/")
	return strings.TrimSuffix(importPath, "/"), strings.Trim(version, "@/")
}

type versions struct {
	libByVersion map[string][]lib
}

func (v *versions) append(version string, l lib) {
	v.libByVersion[version] = append(v.libByVersion[version], l)
}

func (v *versions) latest() []lib {
	var versions semver.Versions
	for version, _ := range v.libByVersion {
		sv, err := semver.ParseTolerant(version)
		if err != nil {
			continue
		}
		versions = append(versions, sv)
	}
	semver.Sort(versions)

	latest := versions[len(versions)-1]
	if libs, ok := v.libByVersion["v"+latest.String()]; ok {
		return libs
	}
	return []lib{}
}

func gomoduleLibs(libChan chan lib) error {
	modChan := make(chan mod, 1000)
	done := make(chan bool)

	go func() {
		modules := map[string]*versions{}
		for mod := range modChan {
			vs, ok := modules[mod.lib.path]
			if !ok {
				vs = &versions{libByVersion: map[string][]lib{}}
				modules[mod.lib.path] = vs
			}
			vs.append(mod.version, mod.lib)
		}
		for _, v := range modules {
			for _, lib := range v.latest() {
				libChan <- lib
			}
		}
		done <- true
	}()

	for _, modDir := range modDirs() {
		ignoreDirs, err := fetchGoImportsIgnore(modDir)
		if err != nil {
			return err
		}
		err = concurrentWalk(modDir, func(info fileInfo) error {
			if info.isDir(false) {
				if isSkipDir(info, ignoreDirs) {
					return filepath.SkipDir
				}
				return nil
			}
			if strings.HasSuffix(info.Name(), "_test.go") {
				return nil
			}
			if !strings.HasSuffix(info.Name(), ".go") {
				return nil
			}

			path := info.path
			fset := token.NewFileSet()
			f, err := parser.ParseFile(fset, path, nil, 0)
			if err != nil {
				return nil
			}

			pkg := f.Name.Name
			if pkg == "main" {
				return nil
			}

			importPath, err := filepath.Rel(modDir, filepath.Dir(path))
			if err != nil {
				return nil
			}

			importPath, version := extractImportPathAndVersion(importPath)
			for _, v := range f.Scope.Objects {
				if ast.IsExported(v.Name) {
					modChan <- mod{
						version: version,
						lib: lib{
							object: v.Name,
							path:   importPath,
						},
					}
				}
			}
			return nil
		})
		if err != nil {
			return err
		}
	}
	close(modChan)
	<-done
	return nil
}
<commit_msg>use vice official semver package instead of blang/semver<commit_after>package dragon

import (
	"go/ast"
	"go/parser"
	"go/token"
	"path/filepath"
	"regexp"
	"strings"

	"golang.org/x/mod/semver"
)

type mod struct {
	version string
	lib     lib
}

var regPath = regexp.MustCompile("@v[0-9]+\\.[0-9]+\\.[0-9].*?(/|$)")

func extractImportPathAndVersion(path string) (string, string) {
	version := regPath.FindString(path)
	importPath := regPath.ReplaceAllString(path, "/")
	return strings.TrimSuffix(importPath, "/"), strings.Trim(version, "@/")
}

type versions struct {
	libByVersion map[string][]lib
}

func (v *versions) append(version string, l lib) {
	v.libByVersion[version] = append(v.libByVersion[version], l)
}

func (v *versions) latest() []lib {
	var latestVer string
	for version, _ := range v.libByVersion {
		latestVer = semver.Max(latestVer, version)
	}
	if libs, ok := v.libByVersion[latestVer]; ok {
		return libs
	}
	return []lib{}
}

func gomoduleLibs(libChan chan lib) error {
	modChan := make(chan mod, 1000)
	done := make(chan bool)

	go func() {
		modules := map[string]*versions{}
		for mod := range modChan {
			vs, ok := modules[mod.lib.path]
			if !ok {
				vs = &versions{libByVersion: map[string][]lib{}}
				modules[mod.lib.path] = vs
			}
			vs.append(mod.version, mod.lib)
		}
		for _, v := range modules {
			for _, lib := range v.latest() {
				libChan <- lib
			}
		}
		done <- true
	}()

	for _, modDir := range modDirs() {
		ignoreDirs, err := fetchGoImportsIgnore(modDir)
		if err != nil {
			return err
		}
		err = concurrentWalk(modDir, func(info fileInfo) error {
			if info.isDir(false) {
				if isSkipDir(info, ignoreDirs) {
					return filepath.SkipDir
				}
				return nil
			}
			if strings.HasSuffix(info.Name(), "_test.go") {
				return nil
			}
			if !strings.HasSuffix(info.Name(), ".go") {
				return nil
			}

			path := info.path
			fset := token.NewFileSet()
			f, err := parser.ParseFile(fset, path, nil, 0)
			if err != nil {
				return nil
			}

			pkg := f.Name.Name
			if pkg == "main" {
				return nil
			}

			importPath, err := filepath.Rel(modDir, filepath.Dir(path))
			if err != nil {
				return nil
			}

			importPath, version := extractImportPathAndVersion(importPath)
			for _, v := range f.Scope.Objects {
				if ast.IsExported(v.Name) {
					modChan <- mod{
						version: version,
						lib: lib{
							object: v.Name,
							path:   importPath,
						},
					}
				}
			}
			return nil
		})
		if err != nil {
			return err
		}
	}
	close(modChan)
	<-done
	return nil
}
<|endoftext|>


<commit_before>package goflow

import (
	"fmt"
	"reflect"
)

// address is a full port accessor including the index part
type address struct {
	proc string
	port string
	key  string
	// index int
}

func (a address) String() string {
	if a.key != "" {
		return fmt.Sprintf("%s.%s[%s]", a.proc, a.port, a.key)
	}
	return fmt.Sprintf("%s.%s", a.proc, a.port)
}

// connection stores information about a connection within the net.
type connection struct {
	src     address
	tgt     address
	channel reflect.Value
	buffer  int
}

// Connect connects a sender to a receiver and creates a channel between them using BufferSize configuratio nof the graph.
// Normally such a connection is unbuffered but you can change by setting flow.DefaultBufferSize > 0 or
// by using ConnectBuf() function instead.
// It returns true on success or panics and returns false if error occurs.
func (n *Graph) Connect(senderName, senderPort, receiverName, receiverPort string) error {
	return n.ConnectBuf(senderName, senderPort, receiverName, receiverPort, n.conf.BufferSize)
}

// ConnectBuf connects a sender to a receiver using a channel with a buffer of a given size.
// It returns true on success or panics and returns false if error occurs.
func (n *Graph) ConnectBuf(senderName, senderPort, receiverName, receiverPort string, bufferSize int) error {
	sendAddr := parseAddress(senderName, senderPort)
	sendPort, err := n.getProcPort(senderName, sendAddr.port, reflect.SendDir)
	if err != nil {
		return fmt.Errorf("connect: %w", err)
	}

	recvAddr := parseAddress(receiverName, receiverPort)
	recvPort, err := n.getProcPort(receiverName, recvAddr.port, reflect.RecvDir)
	if err != nil {
		return fmt.Errorf("connect: %w", err)
	}

	isNewChan := false // tells if a new channel will need to be created for this connection
	// Try to find an existing outbound channel from the same sender,
	// so it can be used as fan-out FIFO
	ch := n.findExistingChan(sendAddr, reflect.SendDir)
	if !ch.IsValid() || ch.IsNil() {
		// Then try to find an existing inbound channel to the same receiver,
		// so it can be used as a fan-in FIFO
		ch = n.findExistingChan(recvAddr, reflect.RecvDir)
		if ch.IsValid() && !ch.IsNil() {
			// Increase the number of listeners on this already used channel
			n.incChanListenersCount(ch)
		} else {
			isNewChan = true
		}
	}
	ch, err = attachPort(sendPort, sendAddr, reflect.SendDir, ch, bufferSize)
	if err != nil {
		return fmt.Errorf("connect '%s.%s': %w", senderName, senderPort, err)
	}

	if _, err = attachPort(recvPort, recvAddr, reflect.RecvDir, ch, bufferSize); err != nil {
		return fmt.Errorf("connect '%s.%s': %w", receiverName, receiverPort, err)
	}
	if isNewChan {
		// Register the first listener on a newly created channel
		n.incChanListenersCount(ch)
	}

	// Add connection info
	n.connections = append(n.connections, connection{
		src:     sendAddr,
		tgt:     recvAddr,
		channel: ch,
		buffer:  bufferSize})

	return nil
}

// getProcPort finds an assignable port field in one of the subprocesses
func (n *Graph) getProcPort(procName, portName string, dir reflect.ChanDir) (reflect.Value, error) {
	nilValue := reflect.ValueOf(nil)
	// Check if process exists
	proc, ok := n.procs[procName]
	if !ok {
		return nilValue, fmt.Errorf("getProcPort: process '%s' not found", procName)
	}

	// Check if process is settable
	val := reflect.ValueOf(proc)
	if val.Kind() == reflect.Ptr && val.IsValid() {
		val = val.Elem()
	}
	if !val.CanSet() {
		return nilValue, fmt.Errorf("getProcPort: process '%s' is not settable", procName)
	}

	// Get the port value
	var portVal reflect.Value
	var err error
	// Check if sender is a net
	net, ok := val.Interface().(Graph)
	if ok {
		// Sender is a net
		var ports map[string]port
		if dir == reflect.SendDir {
			ports = net.outPorts
		} else {
			ports = net.inPorts
		}
		port, ok := ports[portName]
		if !ok {
			return nilValue, fmt.Errorf("getProcPort: subgraph '%s' does not have inport '%s'", procName, portName)
		}
		portVal, err = net.getProcPort(port.addr.proc, port.addr.port, dir)

	} else {
		// Sender is a proc
		portVal = val.FieldByName(portName)
	}
	if err == nil && (!portVal.IsValid()) {
		err = fmt.Errorf("process '%s' does not have a valid port '%s'", procName, portName)
	}
	if err != nil {
		return nilValue, fmt.Errorf("getProcPort: %w", err)
	}

	return portVal, nil
}

func (n *Graph) getChan(addr address, dir reflect.ChanDir) (reflect.Value, error) {
	port, err := n.getProcPort(addr.proc, addr.port, dir)
	if err != nil {
		return reflect.ValueOf(nil), err
	}
	if addr.key == "" {
		return port, nil
	}
	ch := port.MapIndex(reflect.ValueOf(addr.key))
	if !ch.IsValid() || ch.IsNil() {
		return ch, fmt.Errorf("getChan: port '%s.%s' does not have index '%s'", addr.proc, addr.port, addr.key)
	}
	return ch, nil
}

func attachPort(port reflect.Value, addr address, dir reflect.ChanDir, ch reflect.Value, bufSize int) (reflect.Value, error) {
	if addr.key != "" {
		return attachMapPort(port, addr.key, dir, ch, bufSize)
	}
	return attachChanPort(port, dir, ch, bufSize)
}

func attachChanPort(port reflect.Value, dir reflect.ChanDir, ch reflect.Value, bufSize int) (reflect.Value, error) {
	if err := validateChanDir(port.Type(), dir); err != nil {
		return ch, err
	}
	if err := validateCanSet(port); err != nil {
		return ch, err
	}
	ch = selectOrMakeChan(ch, port, port.Type().Elem(), bufSize)
	port.Set(ch)
	return ch, nil
}

func attachMapPort(port reflect.Value, key string, dir reflect.ChanDir, ch reflect.Value, bufSize int) (reflect.Value, error) {
	if err := validateChanDir(port.Type().Elem(), dir); err != nil {
		return ch, err
	}
	kv := reflect.ValueOf(key)
	item := port.MapIndex(kv)
	ch = selectOrMakeChan(ch, item, port.Type().Elem().Elem(), bufSize)
	if port.IsNil() {
		m := reflect.MakeMap(port.Type())
		port.Set(m)
	}
	port.SetMapIndex(kv, ch)
	return ch, nil
}

func validateChanDir(portType reflect.Type, dir reflect.ChanDir) error {
	if portType.Kind() != reflect.Chan {
		return fmt.Errorf("not a channel")
	}

	if portType.ChanDir()&dir == 0 {
		return fmt.Errorf("channel does not support direction %s", dir.String())
	}
	return nil
}

func validateCanSet(portVal reflect.Value) error {
	if !portVal.CanSet() {
		return fmt.Errorf("port is not assignable")
	}
	return nil
}

func selectOrMakeChan(new, existing reflect.Value, t reflect.Type, bufSize int) reflect.Value {
	if !new.IsValid() || new.IsNil() {
		if existing.IsValid() && !existing.IsNil() {
			return existing
		}
		chanType := reflect.ChanOf(reflect.BothDir, t)
		new = reflect.MakeChan(chanType, bufSize)
	}
	return new
}

// parseAddress unfolds a string port name into parts, including array index or hashmap key
func parseAddress(proc, port string) address {
	n := address{
		proc: proc,
		port: port,
		// index: -1,
	}
	keyPos := 0
	key := ""
	for i, r := range port {
		if r == '[' {
			keyPos = i + 1
			n.port = port[0:i]
		}
		if r == ']' {
			key = port[keyPos:i]
		}
	}
	if key == "" {
		return n
	}
	// if i, err := strconv.Atoi(key); err == nil {
	// 	n.index = i
	// } else {
	// 	n.key = key
	// }
	n.key = key
	return n
}

// findExistingChan returns a channel attached to receiver if it already exists among connections
func (n *Graph) findExistingChan(addr address, dir reflect.ChanDir) reflect.Value {
	var channel reflect.Value
	// Find existing channel attached to the receiver
	for _, conn := range n.connections {
		var a address
		if dir == reflect.SendDir {
			a = conn.src
		} else {
			a = conn.tgt
		}
		if a == addr {
			channel = conn.channel
			break
		}
	}
	return channel
}

// incChanListenersCount increments SendChanRefCount.
// The count is needed when multiple senders are connected
// to the same receiver. When the network is terminated and
// senders need to close their output port, this counter
// can help to avoid closing the same channel multiple times.
func (n *Graph) incChanListenersCount(c reflect.Value) {
	n.chanListenersCountLock.Lock()
	defer n.chanListenersCountLock.Unlock()

	ptr := c.Pointer()
	cnt := n.chanListenersCount[ptr]
	cnt++
	n.chanListenersCount[ptr] = cnt
}

// decChanListenersCount decrements SendChanRefCount
// It returns true if the RefCount has reached 0
func (n *Graph) decChanListenersCount(c reflect.Value) bool {
	n.chanListenersCountLock.Lock()
	defer n.chanListenersCountLock.Unlock()

	ptr := c.Pointer()
	cnt := n.chanListenersCount[ptr]
	if cnt == 0 {
		return true //yes you may try to close a nonexistant channel, see what happens...
	}
	cnt--
	n.chanListenersCount[ptr] = cnt
	return cnt == 0
}

// // Disconnect removes a connection between sender's outport and receiver's inport.
// func (n *Graph) Disconnect(senderName, senderPort, receiverName, receiverPort string) bool {
// 	var sender, receiver interface{}
// 	var ok bool
// 	sender, ok = n.procs[senderName]
// 	if !ok {
// 		return false
// 	}
// 	receiver, ok = n.procs[receiverName]
// 	if !ok {
// 		return false
// 	}
// 	res := unsetProcPort(sender, senderPort, true)
// 	res = res && unsetProcPort(receiver, receiverPort, false)
// 	return res
// }

// // Unsets an port of a given process
// func unsetProcPort(proc interface{}, portName string, isOut bool) bool {
// 	v := reflect.ValueOf(proc)
// 	var ch reflect.Value
// 	if v.Elem().FieldByName("Graph").IsValid() {
// 		if subnet, ok := v.Elem().FieldByName("Graph").Addr().Interface().(*Graph); ok {
// 			if isOut {
// 				ch = subnet.getOutPort(portName)
// 			} else {
// 				ch = subnet.getInPort(portName)
// 			}
// 		} else {
// 			return false
// 		}
// 	} else {
// 		ch = v.Elem().FieldByName(portName)
// 	}
// 	if !ch.IsValid() {
// 		return false
// 	}
// 	ch.Set(reflect.Zero(ch.Type()))
// 	return true
// }
<commit_msg>Remove unused func<commit_after>package goflow

import (
	"fmt"
	"reflect"
)

// address is a full port accessor including the index part
type address struct {
	proc string
	port string
	key  string
	// index int
}

func (a address) String() string {
	if a.key != "" {
		return fmt.Sprintf("%s.%s[%s]", a.proc, a.port, a.key)
	}
	return fmt.Sprintf("%s.%s", a.proc, a.port)
}

// connection stores information about a connection within the net.
type connection struct {
	src     address
	tgt     address
	channel reflect.Value
	buffer  int
}

// Connect connects a sender to a receiver and creates a channel between them using BufferSize configuratio nof the graph.
// Normally such a connection is unbuffered but you can change by setting flow.DefaultBufferSize > 0 or
// by using ConnectBuf() function instead.
// It returns true on success or panics and returns false if error occurs.
func (n *Graph) Connect(senderName, senderPort, receiverName, receiverPort string) error {
	return n.ConnectBuf(senderName, senderPort, receiverName, receiverPort, n.conf.BufferSize)
}

// ConnectBuf connects a sender to a receiver using a channel with a buffer of a given size.
// It returns true on success or panics and returns false if error occurs.
func (n *Graph) ConnectBuf(senderName, senderPort, receiverName, receiverPort string, bufferSize int) error {
	sendAddr := parseAddress(senderName, senderPort)
	sendPort, err := n.getProcPort(senderName, sendAddr.port, reflect.SendDir)
	if err != nil {
		return fmt.Errorf("connect: %w", err)
	}

	recvAddr := parseAddress(receiverName, receiverPort)
	recvPort, err := n.getProcPort(receiverName, recvAddr.port, reflect.RecvDir)
	if err != nil {
		return fmt.Errorf("connect: %w", err)
	}

	isNewChan := false // tells if a new channel will need to be created for this connection
	// Try to find an existing outbound channel from the same sender,
	// so it can be used as fan-out FIFO
	ch := n.findExistingChan(sendAddr, reflect.SendDir)
	if !ch.IsValid() || ch.IsNil() {
		// Then try to find an existing inbound channel to the same receiver,
		// so it can be used as a fan-in FIFO
		ch = n.findExistingChan(recvAddr, reflect.RecvDir)
		if ch.IsValid() && !ch.IsNil() {
			// Increase the number of listeners on this already used channel
			n.incChanListenersCount(ch)
		} else {
			isNewChan = true
		}
	}
	ch, err = attachPort(sendPort, sendAddr, reflect.SendDir, ch, bufferSize)
	if err != nil {
		return fmt.Errorf("connect '%s.%s': %w", senderName, senderPort, err)
	}

	if _, err = attachPort(recvPort, recvAddr, reflect.RecvDir, ch, bufferSize); err != nil {
		return fmt.Errorf("connect '%s.%s': %w", receiverName, receiverPort, err)
	}
	if isNewChan {
		// Register the first listener on a newly created channel
		n.incChanListenersCount(ch)
	}

	// Add connection info
	n.connections = append(n.connections, connection{
		src:     sendAddr,
		tgt:     recvAddr,
		channel: ch,
		buffer:  bufferSize})

	return nil
}

// getProcPort finds an assignable port field in one of the subprocesses
func (n *Graph) getProcPort(procName, portName string, dir reflect.ChanDir) (reflect.Value, error) {
	nilValue := reflect.ValueOf(nil)
	// Check if process exists
	proc, ok := n.procs[procName]
	if !ok {
		return nilValue, fmt.Errorf("getProcPort: process '%s' not found", procName)
	}

	// Check if process is settable
	val := reflect.ValueOf(proc)
	if val.Kind() == reflect.Ptr && val.IsValid() {
		val = val.Elem()
	}
	if !val.CanSet() {
		return nilValue, fmt.Errorf("getProcPort: process '%s' is not settable", procName)
	}

	// Get the port value
	var portVal reflect.Value
	var err error
	// Check if sender is a net
	net, ok := val.Interface().(Graph)
	if ok {
		// Sender is a net
		var ports map[string]port
		if dir == reflect.SendDir {
			ports = net.outPorts
		} else {
			ports = net.inPorts
		}
		port, ok := ports[portName]
		if !ok {
			return nilValue, fmt.Errorf("getProcPort: subgraph '%s' does not have inport '%s'", procName, portName)
		}
		portVal, err = net.getProcPort(port.addr.proc, port.addr.port, dir)

	} else {
		// Sender is a proc
		portVal = val.FieldByName(portName)
	}
	if err == nil && (!portVal.IsValid()) {
		err = fmt.Errorf("process '%s' does not have a valid port '%s'", procName, portName)
	}
	if err != nil {
		return nilValue, fmt.Errorf("getProcPort: %w", err)
	}

	return portVal, nil
}

func attachPort(port reflect.Value, addr address, dir reflect.ChanDir, ch reflect.Value, bufSize int) (reflect.Value, error) {
	if addr.key != "" {
		return attachMapPort(port, addr.key, dir, ch, bufSize)
	}
	return attachChanPort(port, dir, ch, bufSize)
}

func attachChanPort(port reflect.Value, dir reflect.ChanDir, ch reflect.Value, bufSize int) (reflect.Value, error) {
	if err := validateChanDir(port.Type(), dir); err != nil {
		return ch, err
	}
	if err := validateCanSet(port); err != nil {
		return ch, err
	}
	ch = selectOrMakeChan(ch, port, port.Type().Elem(), bufSize)
	port.Set(ch)
	return ch, nil
}

func attachMapPort(port reflect.Value, key string, dir reflect.ChanDir, ch reflect.Value, bufSize int) (reflect.Value, error) {
	if err := validateChanDir(port.Type().Elem(), dir); err != nil {
		return ch, err
	}
	kv := reflect.ValueOf(key)
	item := port.MapIndex(kv)
	ch = selectOrMakeChan(ch, item, port.Type().Elem().Elem(), bufSize)
	if port.IsNil() {
		m := reflect.MakeMap(port.Type())
		port.Set(m)
	}
	port.SetMapIndex(kv, ch)
	return ch, nil
}

func validateChanDir(portType reflect.Type, dir reflect.ChanDir) error {
	if portType.Kind() != reflect.Chan {
		return fmt.Errorf("not a channel")
	}

	if portType.ChanDir()&dir == 0 {
		return fmt.Errorf("channel does not support direction %s", dir.String())
	}
	return nil
}

func validateCanSet(portVal reflect.Value) error {
	if !portVal.CanSet() {
		return fmt.Errorf("port is not assignable")
	}
	return nil
}

func selectOrMakeChan(new, existing reflect.Value, t reflect.Type, bufSize int) reflect.Value {
	if !new.IsValid() || new.IsNil() {
		if existing.IsValid() && !existing.IsNil() {
			return existing
		}
		chanType := reflect.ChanOf(reflect.BothDir, t)
		new = reflect.MakeChan(chanType, bufSize)
	}
	return new
}

// parseAddress unfolds a string port name into parts, including array index or hashmap key
func parseAddress(proc, port string) address {
	n := address{
		proc: proc,
		port: port,
		// index: -1,
	}
	keyPos := 0
	key := ""
	for i, r := range port {
		if r == '[' {
			keyPos = i + 1
			n.port = port[0:i]
		}
		if r == ']' {
			key = port[keyPos:i]
		}
	}
	if key == "" {
		return n
	}
	// if i, err := strconv.Atoi(key); err == nil {
	// 	n.index = i
	// } else {
	// 	n.key = key
	// }
	n.key = key
	return n
}

// findExistingChan returns a channel attached to receiver if it already exists among connections
func (n *Graph) findExistingChan(addr address, dir reflect.ChanDir) reflect.Value {
	var channel reflect.Value
	// Find existing channel attached to the receiver
	for _, conn := range n.connections {
		var a address
		if dir == reflect.SendDir {
			a = conn.src
		} else {
			a = conn.tgt
		}
		if a == addr {
			channel = conn.channel
			break
		}
	}
	return channel
}

// incChanListenersCount increments SendChanRefCount.
// The count is needed when multiple senders are connected
// to the same receiver. When the network is terminated and
// senders need to close their output port, this counter
// can help to avoid closing the same channel multiple times.
func (n *Graph) incChanListenersCount(c reflect.Value) {
	n.chanListenersCountLock.Lock()
	defer n.chanListenersCountLock.Unlock()

	ptr := c.Pointer()
	cnt := n.chanListenersCount[ptr]
	cnt++
	n.chanListenersCount[ptr] = cnt
}

// decChanListenersCount decrements SendChanRefCount
// It returns true if the RefCount has reached 0
func (n *Graph) decChanListenersCount(c reflect.Value) bool {
	n.chanListenersCountLock.Lock()
	defer n.chanListenersCountLock.Unlock()

	ptr := c.Pointer()
	cnt := n.chanListenersCount[ptr]
	if cnt == 0 {
		return true //yes you may try to close a nonexistant channel, see what happens...
	}
	cnt--
	n.chanListenersCount[ptr] = cnt
	return cnt == 0
}

// // Disconnect removes a connection between sender's outport and receiver's inport.
// func (n *Graph) Disconnect(senderName, senderPort, receiverName, receiverPort string) bool {
// 	var sender, receiver interface{}
// 	var ok bool
// 	sender, ok = n.procs[senderName]
// 	if !ok {
// 		return false
// 	}
// 	receiver, ok = n.procs[receiverName]
// 	if !ok {
// 		return false
// 	}
// 	res := unsetProcPort(sender, senderPort, true)
// 	res = res && unsetProcPort(receiver, receiverPort, false)
// 	return res
// }

// // Unsets an port of a given process
// func unsetProcPort(proc interface{}, portName string, isOut bool) bool {
// 	v := reflect.ValueOf(proc)
// 	var ch reflect.Value
// 	if v.Elem().FieldByName("Graph").IsValid() {
// 		if subnet, ok := v.Elem().FieldByName("Graph").Addr().Interface().(*Graph); ok {
// 			if isOut {
// 				ch = subnet.getOutPort(portName)
// 			} else {
// 				ch = subnet.getInPort(portName)
// 			}
// 		} else {
// 			return false
// 		}
// 	} else {
// 		ch = v.Elem().FieldByName(portName)
// 	}
// 	if !ch.IsValid() {
// 		return false
// 	}
// 	ch.Set(reflect.Zero(ch.Type()))
// 	return true
// }
<|endoftext|>