<commit_before>package isolated

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"

	"code.cloudfoundry.org/cli/integration/helpers"
)

var _ = Describe("set-org-role command", func() {
	BeforeEach(func() {
		helpers.SkipIfClientCredentialsTestMode()
	})

	Describe("help text and argument validation", func() {
		When("-h is passed", func() {
			It("prints the help text", func() {
				session := helpers.CF("set-org-role", "-h")
				Eventually(session).Should(Say(`NAME:`))
				Eventually(session).Should(Say(`\s+set-org-role - Assign an org role to a user`))
				Eventually(session).Should(Say(`USAGE:`))
				Eventually(session).Should(Say(`\s+cf set-org-role USERNAME ORG ROLE \[--client\]`))
				Eventually(session).Should(Say(`ROLES:`))
				Eventually(session).Should(Say(`\s+'OrgManager' - Invite and manage users, select and change plans, and set spending limits`))
				Eventually(session).Should(Say(`\s+'BillingManager' - Create and manage the billing account and payment info`))
				Eventually(session).Should(Say(`\s+'OrgAuditor' - Read-only access to org info and reports`))
				Eventually(session).Should(Say("OPTIONS:"))
				Eventually(session).Should(Say(`--client\s+Treat USERNAME as the client-id of a \(non-user\) service account`))
				Eventually(session).Should(Say(`SEE ALSO:`))
				Eventually(session).Should(Say(`\s+org-users, set-space-role`))
				Eventually(session).Should(Exit(0))
			})
		})

		When("not enough arguments are provided", func() {
			It("prints an error and help text", func() {
				session := helpers.CF("set-org-role", "foo", "bar")
				Eventually(session.Err).Should(Say("Incorrect Usage: the required argument `ROLE` was not provided"))
				Eventually(session).Should(Say("NAME:"))
				Eventually(session).Should(Say("   set-org-role - Assign an org role to a user"))
				Eventually(session).Should(Say("USAGE:"))
				Eventually(session).Should(Say(`\s+cf set-org-role USERNAME ORG ROLE \[--client\]`))
				Eventually(session).Should(Say("ROLES:"))
				Eventually(session).Should(Say("   'OrgManager' - Invite and manage users, select and change plans, and set spending limits"))
				Eventually(session).Should(Say("   'BillingManager' - Create and manage the billing account and payment info"))
				Eventually(session).Should(Say("   'OrgAuditor' - Read-only access to org info and reports"))
				Eventually(session).Should(Say("OPTIONS:"))
				Eventually(session).Should(Say(`--client\s+Treat USERNAME as the client-id of a \(non-user\) service account`))
				Eventually(session).Should(Say("SEE ALSO:"))
				Eventually(session).Should(Say("   org-users, set-space-role"))
				Eventually(session).Should(Exit(1))
			})
		})

		When("too many arguments are provided", func() {
			It("prints an error and help text", func() {
				session := helpers.CF("set-org-role", "some-user", "some-org", "OrgManager", "some-extra-argument")
				Eventually(session).Should(Say(`Incorrect Usage. Requires USERNAME, ORG, ROLE as arguments`))
				Eventually(session).Should(Say(`NAME:`))
				Eventually(session).Should(Say(`\s+set-org-role - Assign an org role to a user`))
				Eventually(session).Should(Say(`USAGE:`))
				Eventually(session).Should(Say(`\s+cf set-org-role USERNAME ORG ROLE \[--client\]`))
				Eventually(session).Should(Say(`ROLES:`))
				Eventually(session).Should(Say(`\s+'OrgManager' - Invite and manage users, select and change plans, and set spending limits`))
				Eventually(session).Should(Say(`\s+'BillingManager' - Create and manage the billing account and payment info`))
				Eventually(session).Should(Say(`\s+'OrgAuditor' - Read-only access to org info and reports`))
				Eventually(session).Should(Say("OPTIONS:"))
				Eventually(session).Should(Say(`--client\s+Treat USERNAME as the client-id of a \(non-user\) service account`))
				Eventually(session).Should(Exit(1))
			})
		})
	})

	When("the user is logged in", func() {
		var orgName string
		var username string

		BeforeEach(func() {
			helpers.LoginCF()
			orgName = ReadOnlyOrg
			username, _ = helpers.CreateUser()
		})

		When("the --client flag is passed", func() {
			When("the targeted user is actually a client", func() {
				var clientID string

				BeforeEach(func() {
					clientID, _ = helpers.SkipIfClientCredentialsNotSet()
				})

				It("sets the org role for the client", func() {
					session := helpers.CF("set-org-role", clientID, orgName, "OrgManager", "--client")
					Eventually(session).Should(Say("Assigning role OrgManager to user %s in org %s as admin...", clientID, orgName))
					Eventually(session).Should(Say("OK"))
					Eventually(session).Should(Exit(0))
				})

				When("the active user lacks permissions to look up clients", func() {
					BeforeEach(func() {
						helpers.SwitchToOrgRole(orgName, "OrgManager")
					})

					It("prints an appropriate error and exits 1", func() {
						session := helpers.CF("set-org-role", "notaclient", orgName, "OrgManager", "--client")
						Eventually(session).Should(Say("FAILED"))
						Eventually(session).Should(Say("Server error, status code: 403: Access is denied.  You do not have privileges to execute this command."))
						Eventually(session).Should(Exit(1))
					})
				})
			})

			When("the targeted client does not exist", func() {
				var badClientID string

				BeforeEach(func() {
					badClientID = "nonexistent-client"
				})

				It("fails with an appropriate error message", func() {
					session := helpers.CF("set-org-role", badClientID, orgName, "OrgManager", "--client")
					Eventually(session).Should(Say("FAILED"))
					Eventually(session).Should(Say("Client nonexistent-client not found"))
					Eventually(session).Should(Exit(1))
				})
			})
		})

		When("the org and user both exist", func() {
			When("the passed role is all lowercase", func() {
				It("sets the org role for the user", func() {
					session := helpers.CF("set-org-role", username, orgName, "orgauditor")
					Eventually(session).Should(Say("Assigning role OrgAuditor to user %s in org %s as admin...", username, orgName))
					Eventually(session).Should(Say("OK"))
					Eventually(session).Should(Exit(0))
				})
			})

			It("sets the org role for the user", func() {
				session := helpers.CF("set-org-role", username, orgName, "OrgAuditor")
				Eventually(session).Should(Say("Assigning role OrgAuditor to user %s in org %s as admin...", username, orgName))
				Eventually(session).Should(Say("OK"))
				Eventually(session).Should(Exit(0))
			})

			When("the logged in user has insufficient permissions", func() {
				BeforeEach(func() {
					helpers.SwitchToOrgRole(orgName, "OrgAuditor")
				})

				It("prints out the error message from CC API and exits 1", func() {
					session := helpers.CF("set-org-role", username, orgName, "OrgAuditor")
					Eventually(session).Should(Say("FAILED"))
					Eventually(session).Should(Say("Server error, status code: 403, error code: 10003, message: You are not authorized to perform the requested action"))
					Eventually(session).Should(Exit(1))
				})
			})

			When("the user already has the desired role", func() {
				BeforeEach(func() {
					session := helpers.CF("set-org-role", username, orgName, "OrgManager")
					Eventually(session).Should(Say("Assigning role OrgManager to user %s in org %s as admin...", username, orgName))
					Eventually(session).Should(Exit(0))
				})

				It("is idempotent", func() {
					session := helpers.CF("set-org-role", username, orgName, "OrgManager")
					Eventually(session).Should(Say("Assigning role OrgManager to user %s in org %s as admin...", username, orgName))
					Eventually(session).Should(Exit(0))
				})
			})

			When("the specified role is invalid", func() {
				It("prints a useful error, prints help text, and exits 1", func() {
					session := helpers.CF("set-org-role", username, orgName, "NotARealRole")
					Eventually(session.Err).Should(Say(`Incorrect Usage: ROLE must be "OrgManager", "BillingManager" and "OrgAuditor"`))
					Eventually(session).Should(Say(`NAME:`))
					Eventually(session).Should(Say(`\s+set-org-role - Assign an org role to a user`))
					Eventually(session).Should(Say(`USAGE:`))
					Eventually(session).Should(Say(`\s+set-org-role USERNAME ORG ROLE`))
					Eventually(session).Should(Say(`ROLES:`))
					Eventually(session).Should(Say(`\s+'OrgManager' - Invite and manage users, select and change plans, and set spending limits`))
					Eventually(session).Should(Say(`\s+'BillingManager' - Create and manage the billing account and payment info`))
					Eventually(session).Should(Say(`\s+'OrgAuditor' - Read-only access to org info and reports`))
					Eventually(session).Should(Say(`SEE ALSO:`))
					Eventually(session).Should(Say(`\s+org-users, set-space-role`))
					Eventually(session).Should(Exit(1))
				})
			})
		})

		When("the org does not exist", func() {
			It("prints an appropriate error and exits 1", func() {
				session := helpers.CF("set-org-role", username, "not-exists", "OrgAuditor")
				Eventually(session).Should(Say("FAILED"))
				Eventually(session).Should(Say("Organization not-exists not found"))
				Eventually(session).Should(Exit(1))
			})
		})

		When("the user does not exist", func() {
			It("prints an appropriate error and exits 1", func() {
				session := helpers.CF("set-org-role", "not-exists", orgName, "OrgAuditor")
				Eventually(session).Should(Say("Assigning role OrgAuditor to user not-exists in org %s as admin...", orgName))
				Eventually(session).Should(Say("FAILED"))
				Eventually(session).Should(Say("Server error, status code: 404, error code: 20003, message: The user could not be found: not-exists"))
				Eventually(session).Should(Exit(1))
			})
		})
	})

	When("the user is not logged in", func() {
		BeforeEach(func() {
			helpers.LogoutCF()
		})

		It("reports that the user is not logged in", func() {
			session := helpers.CF("set-org-role", "some-user", "some-org", "BillingManager")
			Eventually(session).Should(Say("FAILED"))
			Eventually(session).Should(Say("Not logged in. Use 'cf login' to log in."))
			Eventually(session).Should(Exit(1))
		})
	})
})
<commit_msg>Run set-org-role test in client credentials mode<commit_after>package isolated

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"

	"code.cloudfoundry.org/cli/integration/helpers"
)

var _ = Describe("set-org-role command", func() {
	Describe("help text and argument validation", func() {
		When("-h is passed", func() {
			It("prints the help text", func() {
				session := helpers.CF("set-org-role", "-h")
				Eventually(session).Should(Say(`NAME:`))
				Eventually(session).Should(Say(`\s+set-org-role - Assign an org role to a user`))
				Eventually(session).Should(Say(`USAGE:`))
				Eventually(session).Should(Say(`\s+cf set-org-role USERNAME ORG ROLE \[--client\]`))
				Eventually(session).Should(Say(`ROLES:`))
				Eventually(session).Should(Say(`\s+'OrgManager' - Invite and manage users, select and change plans, and set spending limits`))
				Eventually(session).Should(Say(`\s+'BillingManager' - Create and manage the billing account and payment info`))
				Eventually(session).Should(Say(`\s+'OrgAuditor' - Read-only access to org info and reports`))
				Eventually(session).Should(Say("OPTIONS:"))
				Eventually(session).Should(Say(`--client\s+Treat USERNAME as the client-id of a \(non-user\) service account`))
				Eventually(session).Should(Say(`SEE ALSO:`))
				Eventually(session).Should(Say(`\s+org-users, set-space-role`))
				Eventually(session).Should(Exit(0))
			})
		})

		When("not enough arguments are provided", func() {
			It("prints an error and help text", func() {
				session := helpers.CF("set-org-role", "foo", "bar")
				Eventually(session.Err).Should(Say("Incorrect Usage: the required argument `ROLE` was not provided"))
				Eventually(session).Should(Say("NAME:"))
				Eventually(session).Should(Say("   set-org-role - Assign an org role to a user"))
				Eventually(session).Should(Say("USAGE:"))
				Eventually(session).Should(Say(`\s+cf set-org-role USERNAME ORG ROLE \[--client\]`))
				Eventually(session).Should(Say("ROLES:"))
				Eventually(session).Should(Say("   'OrgManager' - Invite and manage users, select and change plans, and set spending limits"))
				Eventually(session).Should(Say("   'BillingManager' - Create and manage the billing account and payment info"))
				Eventually(session).Should(Say("   'OrgAuditor' - Read-only access to org info and reports"))
				Eventually(session).Should(Say("OPTIONS:"))
				Eventually(session).Should(Say(`--client\s+Treat USERNAME as the client-id of a \(non-user\) service account`))
				Eventually(session).Should(Say("SEE ALSO:"))
				Eventually(session).Should(Say("   org-users, set-space-role"))
				Eventually(session).Should(Exit(1))
			})
		})

		When("too many arguments are provided", func() {
			It("prints an error and help text", func() {
				session := helpers.CF("set-org-role", "some-user", "some-org", "OrgManager", "some-extra-argument")
				Eventually(session).Should(Say(`Incorrect Usage. Requires USERNAME, ORG, ROLE as arguments`))
				Eventually(session).Should(Say(`NAME:`))
				Eventually(session).Should(Say(`\s+set-org-role - Assign an org role to a user`))
				Eventually(session).Should(Say(`USAGE:`))
				Eventually(session).Should(Say(`\s+cf set-org-role USERNAME ORG ROLE \[--client\]`))
				Eventually(session).Should(Say(`ROLES:`))
				Eventually(session).Should(Say(`\s+'OrgManager' - Invite and manage users, select and change plans, and set spending limits`))
				Eventually(session).Should(Say(`\s+'BillingManager' - Create and manage the billing account and payment info`))
				Eventually(session).Should(Say(`\s+'OrgAuditor' - Read-only access to org info and reports`))
				Eventually(session).Should(Say("OPTIONS:"))
				Eventually(session).Should(Say(`--client\s+Treat USERNAME as the client-id of a \(non-user\) service account`))
				Eventually(session).Should(Exit(1))
			})
		})
	})

	When("the user is logged in", func() {
		var orgName string
		var username string
		var privilegedUsername string

		BeforeEach(func() {
			privilegedUsername = helpers.LoginCF()
			orgName = ReadOnlyOrg
			username, _ = helpers.CreateUser()
		})

		When("the --client flag is passed", func() {
			When("the targeted user is actually a client", func() {
				var clientID string

				BeforeEach(func() {
					clientID, _ = helpers.SkipIfClientCredentialsNotSet()
				})

				It("sets the org role for the client", func() {
					session := helpers.CF("set-org-role", clientID, orgName, "OrgManager", "--client")
					Eventually(session).Should(Say("Assigning role OrgManager to user %s in org %s as %s...", clientID, orgName, privilegedUsername))
					Eventually(session).Should(Say("OK"))
					Eventually(session).Should(Exit(0))
				})

				When("the active user lacks permissions to look up clients", func() {
					BeforeEach(func() {
						helpers.SwitchToOrgRole(orgName, "OrgManager")
					})

					It("prints an appropriate error and exits 1", func() {
						session := helpers.CF("set-org-role", "notaclient", orgName, "OrgManager", "--client")
						Eventually(session).Should(Say("FAILED"))
						Eventually(session).Should(Say("Server error, status code: 403: Access is denied.  You do not have privileges to execute this command."))
						Eventually(session).Should(Exit(1))
					})
				})
			})

			When("the targeted client does not exist", func() {
				var badClientID string

				BeforeEach(func() {
					badClientID = "nonexistent-client"
				})

				It("fails with an appropriate error message", func() {
					session := helpers.CF("set-org-role", badClientID, orgName, "OrgManager", "--client")
					Eventually(session).Should(Say("FAILED"))
					Eventually(session).Should(Say("Client nonexistent-client not found"))
					Eventually(session).Should(Exit(1))
				})
			})
		})

		When("the org and user both exist", func() {
			When("the passed role is all lowercase", func() {
				It("sets the org role for the user", func() {
					session := helpers.CF("set-org-role", username, orgName, "orgauditor")
					Eventually(session).Should(Say("Assigning role OrgAuditor to user %s in org %s as %s...", username, orgName, privilegedUsername))
					Eventually(session).Should(Say("OK"))
					Eventually(session).Should(Exit(0))
				})
			})

			It("sets the org role for the user", func() {
				session := helpers.CF("set-org-role", username, orgName, "OrgAuditor")
				Eventually(session).Should(Say("Assigning role OrgAuditor to user %s in org %s as %s...", username, orgName, privilegedUsername))
				Eventually(session).Should(Say("OK"))
				Eventually(session).Should(Exit(0))
			})

			When("the logged in user has insufficient permissions", func() {
				BeforeEach(func() {
					helpers.SwitchToOrgRole(orgName, "OrgAuditor")
				})

				It("prints out the error message from CC API and exits 1", func() {
					session := helpers.CF("set-org-role", username, orgName, "OrgAuditor")
					Eventually(session).Should(Say("FAILED"))
					Eventually(session).Should(Say("Server error, status code: 403, error code: 10003, message: You are not authorized to perform the requested action"))
					Eventually(session).Should(Exit(1))
				})
			})

			When("the user already has the desired role", func() {
				BeforeEach(func() {
					session := helpers.CF("set-org-role", username, orgName, "OrgManager")
					Eventually(session).Should(Say("Assigning role OrgManager to user %s in org %s as %s...", username, orgName, privilegedUsername))
					Eventually(session).Should(Exit(0))
				})

				It("is idempotent", func() {
					session := helpers.CF("set-org-role", username, orgName, "OrgManager")
					Eventually(session).Should(Say("Assigning role OrgManager to user %s in org %s as %s...", username, orgName, privilegedUsername))
					Eventually(session).Should(Exit(0))
				})
			})

			When("the specified role is invalid", func() {
				It("prints a useful error, prints help text, and exits 1", func() {
					session := helpers.CF("set-org-role", username, orgName, "NotARealRole")
					Eventually(session.Err).Should(Say(`Incorrect Usage: ROLE must be "OrgManager", "BillingManager" and "OrgAuditor"`))
					Eventually(session).Should(Say(`NAME:`))
					Eventually(session).Should(Say(`\s+set-org-role - Assign an org role to a user`))
					Eventually(session).Should(Say(`USAGE:`))
					Eventually(session).Should(Say(`\s+set-org-role USERNAME ORG ROLE`))
					Eventually(session).Should(Say(`ROLES:`))
					Eventually(session).Should(Say(`\s+'OrgManager' - Invite and manage users, select and change plans, and set spending limits`))
					Eventually(session).Should(Say(`\s+'BillingManager' - Create and manage the billing account and payment info`))
					Eventually(session).Should(Say(`\s+'OrgAuditor' - Read-only access to org info and reports`))
					Eventually(session).Should(Say(`SEE ALSO:`))
					Eventually(session).Should(Say(`\s+org-users, set-space-role`))
					Eventually(session).Should(Exit(1))
				})
			})
		})

		When("the org does not exist", func() {
			It("prints an appropriate error and exits 1", func() {
				session := helpers.CF("set-org-role", username, "not-exists", "OrgAuditor")
				Eventually(session).Should(Say("FAILED"))
				Eventually(session).Should(Say("Organization not-exists not found"))
				Eventually(session).Should(Exit(1))
			})
		})

		When("the user does not exist", func() {
			It("prints an appropriate error and exits 1", func() {
				session := helpers.CF("set-org-role", "not-exists", orgName, "OrgAuditor")
				Eventually(session).Should(Say("Assigning role OrgAuditor to user not-exists in org %s as %s...", orgName, privilegedUsername))
				Eventually(session).Should(Say("FAILED"))
				Eventually(session).Should(Say("Server error, status code: 404, error code: 20003, message: The user could not be found: not-exists"))
				Eventually(session).Should(Exit(1))
			})
		})
	})

	When("the user is not logged in", func() {
		BeforeEach(func() {
			helpers.LogoutCF()
		})

		It("reports that the user is not logged in", func() {
			session := helpers.CF("set-org-role", "some-user", "some-org", "BillingManager")
			Eventually(session).Should(Say("FAILED"))
			Eventually(session).Should(Say("Not logged in. Use 'cf login' to log in."))
			Eventually(session).Should(Exit(1))
		})
	})
})
<|endoftext|>


<commit_before>package s3

import (
	"net/url"
	"path"
	"strings"

	"restic/errors"
	"restic/options"
)

// Config contains all configuration necessary to connect to an s3 compatible
// server.
type Config struct {
	Endpoint      string
	UseHTTP       bool
	KeyID, Secret string
	Bucket        string
	Prefix        string
	Layout        string `option:"layout" help:"use this backend layout (default: auto-detect)"`

	Connections uint `option:"connections" help:"set a limit for the number of concurrent connections (default: 20)"`
}

// NewConfig returns a new Config with the default values filled in.
func NewConfig() Config {
	return Config{
		Connections: 5,
	}
}

func init() {
	options.Register("s3", Config{})
}

const defaultPrefix = "restic"

// ParseConfig parses the string s and extracts the s3 config. The two
// supported configuration formats are s3://host/bucketname/prefix and
// s3:host:bucketname/prefix. The host can also be a valid s3 region
// name. If no prefix is given the prefix "restic" will be used.
func ParseConfig(s string) (interface{}, error) {
	switch {
	case strings.HasPrefix(s, "s3:http"):
		// assume that a URL has been specified, parse it and
		// use the host as the endpoint and the path as the
		// bucket name and prefix
		url, err := url.Parse(s[3:])
		if err != nil {
			return nil, errors.Wrap(err, "url.Parse")
		}

		if url.Path == "" {
			return nil, errors.New("s3: bucket name not found")
		}

		path := strings.SplitN(url.Path[1:], "/", 2)
		return createConfig(url.Host, path, url.Scheme == "http")
	case strings.HasPrefix(s, "s3://"):
		s = s[5:]
	case strings.HasPrefix(s, "s3:"):
		s = s[3:]
	default:
		return nil, errors.New("s3: invalid format")
	}
	// use the first entry of the path as the endpoint and the
	// remainder as bucket name and prefix
	path := strings.SplitN(s, "/", 3)
	return createConfig(path[0], path[1:], false)
}

func createConfig(endpoint string, p []string, useHTTP bool) (interface{}, error) {
	var prefix string
	switch {
	case len(p) < 1:
		return nil, errors.New("s3: invalid format, host/region or bucket name not found")
	case len(p) == 1 || p[1] == "":
		prefix = defaultPrefix
	default:
		prefix = path.Clean(p[1])
	}
	cfg := NewConfig()
	cfg.Endpoint = endpoint
	cfg.UseHTTP = useHTTP
	cfg.Bucket = p[0]
	cfg.Prefix = prefix
	return cfg, nil
}
<commit_msg>s3: Correct comment on the `connections` option<commit_after>package s3

import (
	"net/url"
	"path"
	"strings"

	"restic/errors"
	"restic/options"
)

// Config contains all configuration necessary to connect to an s3 compatible
// server.
type Config struct {
	Endpoint      string
	UseHTTP       bool
	KeyID, Secret string
	Bucket        string
	Prefix        string
	Layout        string `option:"layout" help:"use this backend layout (default: auto-detect)"`

	Connections uint `option:"connections" help:"set a limit for the number of concurrent connections (default: 5)"`
}

// NewConfig returns a new Config with the default values filled in.
func NewConfig() Config {
	return Config{
		Connections: 5,
	}
}

func init() {
	options.Register("s3", Config{})
}

const defaultPrefix = "restic"

// ParseConfig parses the string s and extracts the s3 config. The two
// supported configuration formats are s3://host/bucketname/prefix and
// s3:host:bucketname/prefix. The host can also be a valid s3 region
// name. If no prefix is given the prefix "restic" will be used.
func ParseConfig(s string) (interface{}, error) {
	switch {
	case strings.HasPrefix(s, "s3:http"):
		// assume that a URL has been specified, parse it and
		// use the host as the endpoint and the path as the
		// bucket name and prefix
		url, err := url.Parse(s[3:])
		if err != nil {
			return nil, errors.Wrap(err, "url.Parse")
		}

		if url.Path == "" {
			return nil, errors.New("s3: bucket name not found")
		}

		path := strings.SplitN(url.Path[1:], "/", 2)
		return createConfig(url.Host, path, url.Scheme == "http")
	case strings.HasPrefix(s, "s3://"):
		s = s[5:]
	case strings.HasPrefix(s, "s3:"):
		s = s[3:]
	default:
		return nil, errors.New("s3: invalid format")
	}
	// use the first entry of the path as the endpoint and the
	// remainder as bucket name and prefix
	path := strings.SplitN(s, "/", 3)
	return createConfig(path[0], path[1:], false)
}

func createConfig(endpoint string, p []string, useHTTP bool) (interface{}, error) {
	var prefix string
	switch {
	case len(p) < 1:
		return nil, errors.New("s3: invalid format, host/region or bucket name not found")
	case len(p) == 1 || p[1] == "":
		prefix = defaultPrefix
	default:
		prefix = path.Clean(p[1])
	}
	cfg := NewConfig()
	cfg.Endpoint = endpoint
	cfg.UseHTTP = useHTTP
	cfg.Bucket = p[0]
	cfg.Prefix = prefix
	return cfg, nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 - Max Ekman <max@looplab.se>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package redis

import (
	"os"
	"testing"

	eh "github.com/looplab/eventhorizon"
	"github.com/looplab/eventhorizon/eventbus/testutil"
)

func TestEventBus(t *testing.T) {
	// Support Wercker testing with MongoDB.
	host := os.Getenv("REDIS_PORT_6379_TCP_ADDR")
	port := os.Getenv("REDIS_PORT_6379_TCP_PORT")

	url := ":6379"
	if host != "" && port != "" {
		url = host + ":" + port
	}

	bus, err := NewEventBus("test", url, "")
	if err != nil {
		t.Fatal("there should be no error:", err)
	}
	if bus == nil {
		t.Fatal("there should be a bus")
	}
	defer bus.Close()

	// Another bus to test the observer.
	bus2, err := NewEventBus("test", url, "")
	if err != nil {
		t.Fatal("there should be no error:", err)
	}
	defer bus2.Close()

	// Wait for subscriptions to be ready.
	<-bus.ready
	<-bus2.ready

	testutil.EventBusCommonTests(t, bus, bus2)
}

func TestEventBusAsync(t *testing.T) {
	// Support Wercker testing with MongoDB.
	host := os.Getenv("REDIS_PORT_6379_TCP_ADDR")
	port := os.Getenv("REDIS_PORT_6379_TCP_PORT")

	url := ":6379"
	if host != "" && port != "" {
		url = host + ":" + port
	}

	bus, err := NewEventBus("test", url, "")
	if err != nil {
		t.Fatal("there should be no error:", err)
	}
	if bus == nil {
		t.Fatal("there should be a bus")
	}
	defer bus.Close()
	bus.SetHandlingStrategy(eh.AsyncEventHandlingStrategy)

	// Another bus to test the observer.
	bus2, err := NewEventBus("test", url, "")
	if err != nil {
		t.Fatal("there should be no error:", err)
	}
	defer bus2.Close()
	bus2.SetHandlingStrategy(eh.AsyncEventHandlingStrategy)

	// Wait for subscriptions to be ready.
	<-bus.ready
	<-bus2.ready

	testutil.EventBusCommonTests(t, bus, bus2)
}
<commit_msg>Clean up Redis event bus test<commit_after>// Copyright (c) 2014 - Max Ekman <max@looplab.se>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package redis

import (
	"os"
	"testing"

	eh "github.com/looplab/eventhorizon"
	"github.com/looplab/eventhorizon/eventbus/testutil"
)

func TestEventBus(t *testing.T) {
	// Support Wercker testing with MongoDB.
	host := os.Getenv("REDIS_PORT_6379_TCP_ADDR")
	port := os.Getenv("REDIS_PORT_6379_TCP_PORT")

	url := ":6379"
	if host != "" && port != "" {
		url = host + ":" + port
	}

	bus1, err := NewEventBus("test", url, "")
	if err != nil {
		t.Fatal("there should be no error:", err)
	}
	defer bus1.Close()

	// Another bus to test the observer.
	bus2, err := NewEventBus("test", url, "")
	if err != nil {
		t.Fatal("there should be no error:", err)
	}
	defer bus2.Close()

	// Wait for subscriptions to be ready.
	<-bus1.ready
	<-bus2.ready

	testutil.EventBusCommonTests(t, bus1, bus2)
}

func TestEventBusAsync(t *testing.T) {
	// Support Wercker testing with MongoDB.
	host := os.Getenv("REDIS_PORT_6379_TCP_ADDR")
	port := os.Getenv("REDIS_PORT_6379_TCP_PORT")

	url := ":6379"
	if host != "" && port != "" {
		url = host + ":" + port
	}

	bus1, err := NewEventBus("test", url, "")
	if err != nil {
		t.Fatal("there should be no error:", err)
	}
	defer bus1.Close()
	bus1.SetHandlingStrategy(eh.AsyncEventHandlingStrategy)

	// Another bus to test the observer.
	bus2, err := NewEventBus("test", url, "")
	if err != nil {
		t.Fatal("there should be no error:", err)
	}
	defer bus2.Close()
	bus2.SetHandlingStrategy(eh.AsyncEventHandlingStrategy)

	// Wait for subscriptions to be ready.
	<-bus1.ready
	<-bus2.ready

	testutil.EventBusCommonTests(t, bus1, bus2)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/gopherjs/gopherjs/js"
	"github.com/lngramos/three"
)

var (
	scene    three.Scene
	camera   three.PerspectiveCamera
	renderer three.WebGLRenderer
	mesh     three.Mesh
)

func main() {
	document := js.Global.Get("document")
	windowWidth := js.Global.Get("innerWidth").Float()
	windowHeight := js.Global.Get("innerHeight").Float()
	devicePixelRatio := js.Global.Get("devicePixelRatio").Float()

	camera = three.NewPerspectiveCamera(70, windowWidth/windowHeight, 1, 1000)
	camera.Position.Set(0, 0, 400)

	scene = three.NewScene()

	renderer = three.NewWebGLRenderer()
	renderer.SetPixelRatio(devicePixelRatio)
	renderer.SetSize(windowWidth, windowHeight, true)
	document.Get("body").Call("appendChild", renderer.Get("domElement"))

	// Create cube
	geometry := three.NewBoxGeometry(200, 200, 200)
	material := three.NewMeshBasicMaterial(three.MeshBasicMaterialParameters{Color: three.NewColor(255, 0, 0)})
	mesh = three.NewMesh(geometry, material)
	scene.Add(mesh)

	renderer.Render(scene, camera)
	// animate()
}

func animate() {
	js.Global.Call("requestAnimationFrame", animate)

	// cube.SetRotationFromAxisAngle("x", cube.Rotation.X+0.01)
	// cube.SetRotationFromAxisAngle("y", cube.Rotation.Y+0.01)
	// cube.Rotation.X += 0.01
	// cube.Rotation.Y += 0.02
	// cube.RotateX()

	renderer.Render(scene, camera)
}
<commit_msg>Animate the example<commit_after>package main

import (
	"github.com/gopherjs/gopherjs/js"
	"github.com/lngramos/three"
)

var (
	scene    three.Scene
	camera   three.PerspectiveCamera
	renderer three.WebGLRenderer
	mesh     three.Mesh
)

func main() {
	document := js.Global.Get("document")
	windowWidth := js.Global.Get("innerWidth").Float()
	windowHeight := js.Global.Get("innerHeight").Float()
	devicePixelRatio := js.Global.Get("devicePixelRatio").Float()

	camera = three.NewPerspectiveCamera(70, windowWidth/windowHeight, 1, 1000)
	camera.Position.Set(0, 0, 400)

	scene = three.NewScene()

	renderer = three.NewWebGLRenderer()
	renderer.SetPixelRatio(devicePixelRatio)
	renderer.SetSize(windowWidth, windowHeight, true)
	document.Get("body").Call("appendChild", renderer.Get("domElement"))

	// Create cube
	geometry := three.NewBoxGeometry(100, 100, 100)
	material := three.NewMeshBasicMaterial(three.MeshBasicMaterialParameters{Color: three.NewColor(255, 0, 0)})
	mesh = three.NewMesh(geometry, material)

	scene.Add(mesh)

	animate()
}

func animate() {
	js.Global.Call("requestAnimationFrame", animate)

	pos := mesh.Object.Get("rotation")
	pos.Set("x", pos.Get("x").Float()+float64(0.01))
	pos.Set("y", pos.Get("y").Float()+float64(0.01))

	renderer.Render(scene, camera)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"net"
	"os"

	osc "github.com/kward/go-osc"
)

func main() {
	addr := "0.0.0.0:8000"
	server := &osc.Server{}
	conn, err := net.ListenPacket("udp", addr)
	if err != nil {
		fmt.Println("Couldn't listen: ", err)
	}
	defer conn.Close()

	fmt.Println("### Welcome to go-osc receiver demo")
	fmt.Println("Press \"q\" to exit")

	go func() {
		fmt.Println("Start listening on", addr)

		for {
			packet, err := server.ReceivePacket(conn)
			if err != nil {
				fmt.Println("Server error: " + err.Error())
				os.Exit(1)
			}

			if packet != nil {
				switch packet.(type) {
				default:
					fmt.Println("Unknown packet type!")

				case *osc.Message:
					fmt.Printf("-- OSC Message: ")
					osc.PrintMessage(packet.(*osc.Message))

				case *osc.Bundle:
					fmt.Println("-- OSC Bundle:")
					bundle := packet.(*osc.Bundle)
					for i, message := range bundle.Messages {
						fmt.Printf("  -- OSC Message #%d: ", i+1)
						osc.PrintMessage(message)
					}
				}
			}
		}
	}()

	reader := bufio.NewReader(os.Stdin)

	for {
		c, err := reader.ReadByte()
		if err != nil {
			os.Exit(0)
		}

		if c == 'q' {
			os.Exit(0)
		}
	}
}
<commit_msg>added missing context arg to server.ReceivePacket()<commit_after>package main

import (
	"bufio"
	"fmt"
	"net"
	"os"

	osc "github.com/kward/go-osc"
	"golang.org/x/net/context"
)

func main() {
	addr := "0.0.0.0:8000"
	server := &osc.Server{}
	conn, err := net.ListenPacket("udp", addr)
	if err != nil {
		fmt.Println("Couldn't listen: ", err)
	}
	defer conn.Close()

	fmt.Println("### Welcome to go-osc receiver demo")
	fmt.Println("Press \"q\" to exit")

	go func() {
		fmt.Println("Start listening on", addr)

		for {
			packet, err := server.ReceivePacket(context.Background(), conn)
			if err != nil {
				fmt.Println("Server error: " + err.Error())
				os.Exit(1)
			}

			if packet != nil {
				switch packet.(type) {
				default:
					fmt.Println("Unknown packet type!")

				case *osc.Message:
					fmt.Printf("-- OSC Message: ")
					osc.PrintMessage(packet.(*osc.Message))

				case *osc.Bundle:
					fmt.Println("-- OSC Bundle:")
					bundle := packet.(*osc.Bundle)
					for i, message := range bundle.Messages {
						fmt.Printf("  -- OSC Message #%d: ", i+1)
						osc.PrintMessage(message)
					}
				}
			}
		}
	}()

	reader := bufio.NewReader(os.Stdin)

	for {
		c, err := reader.ReadByte()
		if err != nil {
			os.Exit(0)
		}

		if c == 'q' {
			os.Exit(0)
		}
	}
}
<|endoftext|>


<commit_before>package goat

import (
	"bencode"
	"encoding/binary"
	"encoding/hex"
	"math/rand"
	"net"
	"strconv"
	"time"
)

// Generate an AnnounceLog struct from a query map
func MapToAnnounceLog(query map[string]string, resChan chan []byte) AnnounceLog {
	var announce AnnounceLog

	// Required parameters

	// info_hash
	infoHash := make([]byte, 64)
	hex.Encode(infoHash, []byte(query["info_hash"]))
	announce.InfoHash = string(infoHash)

	// peer_id
	peerId := make([]byte, 64)
	hex.Encode(peerId, []byte(query["peer_id"]))
	announce.PeerId = string(peerId)

	// ip
	announce.Ip = query["ip"]

	// port
	port, err := strconv.Atoi(query["port"])
	if err != nil {
		TrackerError(resChan, "parameter port is not a valid integer")
	}
	announce.Port = port

	// uploaded
	uploaded, err := strconv.Atoi(query["uploaded"])
	if err != nil {
		TrackerError(resChan, "parameter uploaded is not a valid integer")
	}
	announce.Uploaded = uploaded

	// downloaded
	downloaded, err := strconv.Atoi(query["downloaded"])
	if err != nil {
		TrackerError(resChan, "parameter downloaded is not a valid integer")
	}
	announce.Downloaded = downloaded

	// left
	left, err := strconv.Atoi(query["left"])
	if err != nil {
		TrackerError(resChan, "parameter left is not a valid integer")
	}
	announce.Left = left

	// Optional parameters

	// event
	if event, ok := query["event"]; ok {
		announce.Event = event
	}

	// Current UNIX timestamp
	announce.Time = time.Now().Unix()

	// Return the created announce
	return announce
}

// Generate a random announce interval in the specified range
func RandRange(min int, max int) int {
	rand.Seed(time.Now().Unix())
	return min + rand.Intn(max - min)
}

// Generate a fake announce response
func FakeAnnounceResponse(numwant int) []byte {
	// For now, we completely ignore numwant
	_ = numwant

	res := map[string][]byte{
		// complete, downloaded, incomplete: used to report client download statistics
		// min interval, interval: used to tell clients how often to announce
		// TODO: these may not be necessary, or may cause problems
		// Need to do further research
		/*
		"complete":     bencode.EncInt(0),
		"downloaded":   bencode.EncInt(0),
		"incomplete":   bencode.EncInt(0),
		*/
		"interval":     bencode.EncInt(RandRange(3200, 4000)),
		"min interval": bencode.EncInt(1800),
		"peers":        bencode.EncBytes(CompactPeerList()),
	}

	return bencode.EncDictMap(res)
}

// Save for later: Generate a compact peer list in binary format
func CompactPeerList() []byte {
	// Empty byte buffer
	buf := []byte("")

	// Add a bunch of fake peers to list
	for i := 0; i < 1; i++ {
		// Compact peers into binary format: ip ip ip ip port port
		ip := [4]byte{}
		binary.BigEndian.PutUint32(ip[:], binary.BigEndian.Uint32(net.ParseIP("255.255.255.255").To4()))
		port := [2]byte{}
		binary.BigEndian.PutUint16(port[:], 8080)

		// Append to end of buffer
		buf = append(buf[:], append(ip[:], port[:]...)...)
	}

	return buf
}
<commit_msg>Fix hex conversion, do int validation elsewhere<commit_after>package goat

import (
	"bencode"
	"encoding/binary"
	"encoding/hex"
	"math/rand"
	"net"
	"strconv"
	"time"
)

// Generate an AnnounceLog struct from a query map
func MapToAnnounceLog(query map[string]string) AnnounceLog {
	var announce AnnounceLog

	// Required parameters

	// info_hash
	announce.InfoHash = hex.EncodeToString([]byte(query["info_hash"]))

	// peer_id
	announce.PeerId = hex.EncodeToString([]byte(query["peer_id"]))

	// ip
	announce.Ip = query["ip"]

	// Note: integers previously validated in connHandler.go

	// port
	port, _ := strconv.Atoi(query["port"])
	announce.Port = port

	// uploaded
	uploaded, _ := strconv.Atoi(query["uploaded"])
	announce.Uploaded = uploaded

	// downloaded
	downloaded, _ := strconv.Atoi(query["downloaded"])
	announce.Downloaded = downloaded

	// left
	left, _ := strconv.Atoi(query["left"])
	announce.Left = left

	// Optional parameters

	// event
	if event, ok := query["event"]; ok {
		announce.Event = event
	}

	// Current UNIX timestamp
	announce.Time = time.Now().Unix()

	// Return the created announce
	return announce
}

// Generate a random announce interval in the specified range
func RandRange(min int, max int) int {
	rand.Seed(time.Now().Unix())
	return min + rand.Intn(max - min)
}

// Generate a fake announce response
func FakeAnnounceResponse(numwant int) []byte {
	// For now, we completely ignore numwant
	_ = numwant

	res := map[string][]byte{
		// complete, downloaded, incomplete: used to report client download statistics
		// min interval, interval: used to tell clients how often to announce
		// TODO: these may not be necessary, or may cause problems
		// Need to do further research
		/*
		"complete":     bencode.EncInt(0),
		"downloaded":   bencode.EncInt(0),
		"incomplete":   bencode.EncInt(0),
		*/
		"interval":     bencode.EncInt(RandRange(3200, 4000)),
		"min interval": bencode.EncInt(1800),
		"peers":        bencode.EncBytes(CompactPeerList()),
	}

	return bencode.EncDictMap(res)
}

// Save for later: Generate a compact peer list in binary format
func CompactPeerList() []byte {
	// Empty byte buffer
	buf := []byte("")

	// Add a bunch of fake peers to list
	for i := 0; i < 1; i++ {
		// Compact peers into binary format: ip ip ip ip port port
		ip := [4]byte{}
		binary.BigEndian.PutUint32(ip[:], binary.BigEndian.Uint32(net.ParseIP("255.255.255.255").To4()))
		port := [2]byte{}
		binary.BigEndian.PutUint16(port[:], 8080)

		// Append to end of buffer
		buf = append(buf[:], append(ip[:], port[:]...)...)
	}

	return buf
}
<|endoftext|>


<commit_before>/*
 Copyright 2018 Padduck, LLC
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 	http://www.apache.org/licenses/LICENSE-2.0
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

package api

import (
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/gorm"
	"github.com/pufferpanel/pufferpanel/v2"
	"github.com/pufferpanel/pufferpanel/v2/panel/models"
	"github.com/pufferpanel/pufferpanel/v2/panel/services"
	"github.com/pufferpanel/pufferpanel/v2/panel/web/handlers"
	"github.com/pufferpanel/pufferpanel/v2/response"
	"github.com/pufferpanel/pufferpanel/v2/scope"
	"github.com/spf13/cast"
	"net/http"
)

func registerUsers(g *gin.RouterGroup) {
	g.Handle("GET", "", handlers.OAuth2Handler(scope.UsersView, false), searchUsers)
	g.Handle("POST", "", handlers.OAuth2Handler(scope.UsersEdit, false), createUser)
	g.Handle("OPTIONS", "", response.CreateOptions("GET", "POST"))

	g.Handle("GET", "/:id", handlers.OAuth2Handler(scope.UsersView, false), getUser)
	g.Handle("POST", "/:id", handlers.OAuth2Handler(scope.UsersEdit, false), updateUser)
	g.Handle("DELETE", "/:id", handlers.OAuth2Handler(scope.UsersEdit, false), deleteUser)
	g.Handle("OPTIONS", "/:id", response.CreateOptions("GET", "POST", "DELETE"))

	g.Handle("GET", "/:id/perms", handlers.OAuth2Handler(scope.UsersView, false), response.NotImplemented)
	g.Handle("PUT", "/:id/perms", handlers.OAuth2Handler(scope.UsersEdit, false), response.NotImplemented)
	g.Handle("OPTIONS", "/:id/perms", response.CreateOptions("PUT", "GET"))
}

func searchUsers(c *gin.Context) {
	var err error
	db := handlers.GetDatabase(c)
	us := &services.User{DB: db}

	search := newUserSearch()
	err = c.ShouldBind(search)
	if response.HandleError(c, err, http.StatusBadRequest) {
		return
	}

	if search.PageLimit > MaxPageSize {
		search.PageLimit = MaxPageSize
	}

	var results *models.Users
	var total uint
	if results, total, err = us.Search(search.Username, search.Email, search.PageLimit, search.Page); response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	c.JSON(http.StatusOK, &models.UserSearchResponse{
		Users: models.FromUsers(results),
		Metadata: &response.Metadata{Paging: &response.Paging{
			Page:    search.Page,
			Size:    search.PageLimit,
			MaxSize: MaxPageSize,
			Total:   total,
		}},
	})
}

func createUser(c *gin.Context) {
	var err error
	db := handlers.GetDatabase(c)
	us := &services.User{DB: db}

	var viewModel models.UserView
	if err = c.BindJSON(&viewModel); response.HandleError(c, err, http.StatusBadRequest) {
		return
	}

	if err = viewModel.Valid(false); response.HandleError(c, err, http.StatusBadRequest) {
		return
	}

	if viewModel.Password == "" {
		response.HandleError(c, pufferpanel.ErrFieldRequired("password"), http.StatusBadRequest)
		return
	}

	user := &models.User{}
	viewModel.CopyToModel(user)

	if err = us.Create(user); response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	resultModel := models.FromUser(user)

	c.JSON(http.StatusOK, resultModel)
}

func getUser(c *gin.Context) {
	db := handlers.GetDatabase(c)
	us := &services.User{DB: db}

	var err error
	var id uint
	if id, err = cast.ToUintE(c.Param("id")); err != nil {
		response.HandleError(c, err, http.StatusBadRequest)
		return
	}

	user, err := us.GetById(id)
	if err != nil && gorm.IsRecordNotFoundError(err) {
		c.AbortWithStatus(http.StatusNotFound)
		return
	} else if response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	c.JSON(http.StatusOK, models.FromUser(user))
}

func updateUser(c *gin.Context) {
	db := handlers.GetDatabase(c)
	us := &services.User{DB: db}

	var err error
	var id uint
	if id, err = cast.ToUintE(c.Param("id")); err != nil {
		response.HandleError(c, err, http.StatusBadRequest)
		return
	}

	var viewModel models.UserView
	if err := c.BindJSON(&viewModel); response.HandleError(c, err, http.StatusBadRequest) {
		return
	}

	if err := viewModel.Valid(true); response.HandleError(c, err, http.StatusBadRequest) {
		return
	}

	user, err := us.GetById(id)
	if err != nil && gorm.IsRecordNotFoundError(err) {
		c.AbortWithStatus(http.StatusNotFound)
		return
	} else if response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	viewModel.CopyToModel(user)

	if err = us.Update(user); response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	c.Status(http.StatusNoContent)
}

func deleteUser(c *gin.Context) {
	db := handlers.GetDatabase(c)
	us := &services.User{DB: db}

	var err error
	var id uint
	if id, err = cast.ToUintE(c.Param("id")); err != nil {
		response.HandleError(c, err, http.StatusBadRequest)
		return
	}

	user, err := us.GetById(id)
	if err != nil && gorm.IsRecordNotFoundError(err) {
		c.AbortWithStatus(http.StatusNotFound)
		return
	} else if response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	if err = us.Delete(user); response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	c.Status(http.StatusNoContent)
}

func newUserSearch() *models.UserSearch {
	return &models.UserSearch{
		Username:  "*",
		Email:     "*",
		PageLimit: DefaultPageSize,
		Page:      1,
	}
}
<commit_msg>Add perm management<commit_after>/*
 Copyright 2018 Padduck, LLC
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 	http://www.apache.org/licenses/LICENSE-2.0
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

package api

import (
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/gorm"
	"github.com/pufferpanel/pufferpanel/v2"
	"github.com/pufferpanel/pufferpanel/v2/panel/models"
	"github.com/pufferpanel/pufferpanel/v2/panel/services"
	"github.com/pufferpanel/pufferpanel/v2/panel/web/handlers"
	"github.com/pufferpanel/pufferpanel/v2/response"
	"github.com/pufferpanel/pufferpanel/v2/scope"
	"github.com/spf13/cast"
	"net/http"
)

func registerUsers(g *gin.RouterGroup) {
	g.Handle("GET", "", handlers.OAuth2Handler(scope.UsersView, false), searchUsers)
	g.Handle("POST", "", handlers.OAuth2Handler(scope.UsersEdit, false), createUser)
	g.Handle("OPTIONS", "", response.CreateOptions("GET", "POST"))

	g.Handle("GET", "/:id", handlers.OAuth2Handler(scope.UsersView, false), getUser)
	g.Handle("POST", "/:id", handlers.OAuth2Handler(scope.UsersEdit, false), updateUser)
	g.Handle("DELETE", "/:id", handlers.OAuth2Handler(scope.UsersEdit, false), deleteUser)
	g.Handle("OPTIONS", "/:id", response.CreateOptions("GET", "POST", "DELETE"))

	g.Handle("GET", "/:id/perms", handlers.OAuth2Handler(scope.UsersView, false), getUserPerms)
	g.Handle("PUT", "/:id/perms", handlers.OAuth2Handler(scope.UsersEdit, false), setUserPerms)
	g.Handle("OPTIONS", "/:id/perms", response.CreateOptions("PUT", "GET"))
}

func searchUsers(c *gin.Context) {
	var err error
	db := handlers.GetDatabase(c)
	us := &services.User{DB: db}

	search := newUserSearch()
	err = c.ShouldBind(search)
	if response.HandleError(c, err, http.StatusBadRequest) {
		return
	}

	if search.PageLimit > MaxPageSize {
		search.PageLimit = MaxPageSize
	}

	var results *models.Users
	var total uint
	if results, total, err = us.Search(search.Username, search.Email, search.PageLimit, search.Page); response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	c.JSON(http.StatusOK, &models.UserSearchResponse{
		Users: models.FromUsers(results),
		Metadata: &response.Metadata{Paging: &response.Paging{
			Page:    search.Page,
			Size:    search.PageLimit,
			MaxSize: MaxPageSize,
			Total:   total,
		}},
	})
}

func createUser(c *gin.Context) {
	var err error
	db := handlers.GetDatabase(c)
	us := &services.User{DB: db}

	var viewModel models.UserView
	if err = c.BindJSON(&viewModel); response.HandleError(c, err, http.StatusBadRequest) {
		return
	}

	if err = viewModel.Valid(false); response.HandleError(c, err, http.StatusBadRequest) {
		return
	}

	if viewModel.Password == "" {
		response.HandleError(c, pufferpanel.ErrFieldRequired("password"), http.StatusBadRequest)
		return
	}

	user := &models.User{}
	viewModel.CopyToModel(user)

	if err = us.Create(user); response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	resultModel := models.FromUser(user)

	c.JSON(http.StatusOK, resultModel)
}

func getUser(c *gin.Context) {
	db := handlers.GetDatabase(c)
	us := &services.User{DB: db}

	var err error
	var id uint
	if id, err = cast.ToUintE(c.Param("id")); err != nil {
		response.HandleError(c, err, http.StatusBadRequest)
		return
	}

	user, err := us.GetById(id)
	if err != nil && gorm.IsRecordNotFoundError(err) {
		c.AbortWithStatus(http.StatusNotFound)
		return
	} else if response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	c.JSON(http.StatusOK, models.FromUser(user))
}

func updateUser(c *gin.Context) {
	db := handlers.GetDatabase(c)
	us := &services.User{DB: db}

	var err error
	var id uint
	if id, err = cast.ToUintE(c.Param("id")); err != nil {
		response.HandleError(c, err, http.StatusBadRequest)
		return
	}

	var viewModel models.UserView
	if err := c.BindJSON(&viewModel); response.HandleError(c, err, http.StatusBadRequest) {
		return
	}

	if err := viewModel.Valid(true); response.HandleError(c, err, http.StatusBadRequest) {
		return
	}

	user, err := us.GetById(id)
	if err != nil && gorm.IsRecordNotFoundError(err) {
		c.AbortWithStatus(http.StatusNotFound)
		return
	} else if response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	viewModel.CopyToModel(user)

	if err = us.Update(user); response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	c.Status(http.StatusNoContent)
}

func deleteUser(c *gin.Context) {
	db := handlers.GetDatabase(c)
	us := &services.User{DB: db}

	var err error
	var id uint
	if id, err = cast.ToUintE(c.Param("id")); err != nil {
		response.HandleError(c, err, http.StatusBadRequest)
		return
	}

	user, err := us.GetById(id)
	if err != nil && gorm.IsRecordNotFoundError(err) {
		c.AbortWithStatus(http.StatusNotFound)
		return
	} else if response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	if err = us.Delete(user); response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	c.Status(http.StatusNoContent)
}

func getUserPerms(c *gin.Context) {
	db := handlers.GetDatabase(c)
	us := &services.User{DB: db}
	ps := &services.Permission{DB: db}

	var err error
	var id uint
	if id, err = cast.ToUintE(c.Param("id")); err != nil {
		response.HandleError(c, err, http.StatusBadRequest)
		return
	}

	user, err := us.GetById(id)
	if err != nil && gorm.IsRecordNotFoundError(err) {
		c.AbortWithStatus(http.StatusNotFound)
		return
	} else if response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	perms, err := ps.GetForUserAndServer(user.ID, nil)
	if response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	c.JSON(http.StatusOK, models.FromPermission(perms))
}

func setUserPerms(c *gin.Context) {
	db := handlers.GetDatabase(c)
	us := &services.User{DB: db}
	ps := &services.Permission{DB: db}

	var err error
	var id uint
	if id, err = cast.ToUintE(c.Param("id")); err != nil {
		response.HandleError(c, err, http.StatusBadRequest)
		return
	}

	viewModel := &models.PermissionView{}
	err = c.BindJSON(viewModel)
	if response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	user, err := us.GetById(id)
	if err != nil && gorm.IsRecordNotFoundError(err) {
		c.AbortWithStatus(http.StatusNotFound)
		return
	} else if response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	perms, err := ps.GetForUserAndServer(user.ID, nil)
	if response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	viewModel.CopyTo(perms, true)

	err = ps.UpdatePermissions(perms)
	if response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	c.Status(http.StatusNoContent)
}

func newUserSearch() *models.UserSearch {
	return &models.UserSearch{
		Username:  "*",
		Email:     "*",
		PageLimit: DefaultPageSize,
		Page:      1,
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

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

package mungers

import (
	"fmt"

	"k8s.io/contrib/mungegithub/features"
	"k8s.io/contrib/mungegithub/github"

	"github.com/golang/glog"
	githubapi "github.com/google/go-github/github"
	"github.com/spf13/cobra"
	"regexp"
	"strings"
)

const (
	releaseNoteLabeler = "release-note-label"

	releaseNoteLabelNeeded    = "release-note-label-needed"
	releaseNote               = "release-note"
	releaseNoteNone           = "release-note-none"
	releaseNoteActionRequired = "release-note-action-required"
	releaseNoteExperimental   = "release-note-experimental"

	releaseNoteFormat = `Adding ` + doNotMergeLabel + ` because the release note process has not been followed.
One of the following labels is required %q, %q, %q or %q.
Please see: https://github.com/kubernetes/kubernetes/blob/master/docs/devel/pull-requests.md#release-notes.`
	parentReleaseNoteFormat = `The 'parent' PR of a cherry-pick PR must have one of the %q or %q labels, or this PR must follow the standard/parent release note labeling requirement. (release-note-experimental must be explicit for cherry-picks)`

	noReleaseNoteComment = "none"
	actionRequiredNote   = "action required"
)

var (
	releaseNoteBody       = fmt.Sprintf(releaseNoteFormat, releaseNote, releaseNoteActionRequired, releaseNoteExperimental, releaseNoteNone)
	parentReleaseNoteBody = fmt.Sprintf(parentReleaseNoteFormat, releaseNote, releaseNoteActionRequired)
)

// ReleaseNoteLabel will add the doNotMergeLabel to a PR which has not
// set one of the appropriete 'release-note-*' labels but has LGTM
type ReleaseNoteLabel struct {
	config *github.Config
}

func init() {
	r := &ReleaseNoteLabel{}
	RegisterMungerOrDie(r)
	RegisterStaleComments(r)
}

// Name is the name usable in --pr-mungers
func (r *ReleaseNoteLabel) Name() string { return releaseNoteLabeler }

// RequiredFeatures is a slice of 'features' that must be provided
func (r *ReleaseNoteLabel) RequiredFeatures() []string { return []string{} }

// Initialize will initialize the munger
func (r *ReleaseNoteLabel) Initialize(config *github.Config, features *features.Features) error {
	r.config = config
	return nil
}

// EachLoop is called at the start of every munge loop
func (r *ReleaseNoteLabel) EachLoop() error { return nil }

// AddFlags will add any request flags to the cobra `cmd`
func (r *ReleaseNoteLabel) AddFlags(cmd *cobra.Command, config *github.Config) {}

func (r *ReleaseNoteLabel) prMustFollowRelNoteProcess(obj *github.MungeObject) bool {
	if obj.IsForBranch("master") {
		return true
	}

	parents := getCherrypickParentPRs(obj, r.config)
	// if it has no parents it needs to follow the release note process
	if len(parents) == 0 {
		return true
	}

	for _, parent := range parents {
		// If the parent didn't set a release note, the CP must
		if !parent.HasLabel(releaseNote) &&
			!parent.HasLabel(releaseNoteActionRequired) {
			if !obj.HasLabel(releaseNoteLabelNeeded) {
				obj.WriteComment(parentReleaseNoteBody)
			}
			return true
		}
	}
	// All of the parents set the releaseNote or releaseNoteActionRequired label,
	// so this cherrypick PR needs to do nothing.
	return false
}

func (r *ReleaseNoteLabel) ensureNoRelNoteNeededLabel(obj *github.MungeObject) {
	if obj.HasLabel(releaseNoteLabelNeeded) {
		obj.RemoveLabel(releaseNoteLabelNeeded)
	}
}

// Munge is the workhorse the will actually make updates to the PR
func (r *ReleaseNoteLabel) Munge(obj *github.MungeObject) {
	if !obj.IsPR() {
		return
	}

	if releaseNoteAlreadyAdded(obj) {
		r.ensureNoRelNoteNeededLabel(obj)
		return
	}

	if !r.prMustFollowRelNoteProcess(obj) {
		r.ensureNoRelNoteNeededLabel(obj)
		return
	}

	labelToAdd := determineReleaseNoteLabel(obj)
	if labelToAdd == releaseNoteLabelNeeded {
		if !obj.HasLabel(releaseNoteLabelNeeded) {
			obj.AddLabel(releaseNoteLabelNeeded)
		}
		if !obj.HasLabel(doNotMergeLabel) {
			obj.AddLabel(doNotMergeLabel)
		}
	} else {
		//going to apply some other release-note-label
		if obj.HasLabel(releaseNoteLabelNeeded) {
			obj.RemoveLabel(releaseNoteLabelNeeded)
		}
		obj.AddLabel(labelToAdd)
		return
	}

	if !obj.HasLabel(lgtmLabel) {
		return
	}

	if obj.HasLabel(doNotMergeLabel) {
		return
	}

	obj.WriteComment(releaseNoteBody)
	obj.AddLabel(doNotMergeLabel)
}

// determineReleaseNoteLabel returns the label to be added if
// correctly implemented in the PR template.  returns nil otherwise
func determineReleaseNoteLabel(obj *github.MungeObject) string {
	potentialMatch := getReleaseNote(*obj.Issue.Body)
	return chooseLabel(potentialMatch)
}

// getReleaseNote returns the release note from a PR body
// assumes that the PR body followed the PR template
func getReleaseNote(body string) string {
	noteMatcher := regexp.MustCompile("Release note.*```(.+)```")
	potentialMatch := noteMatcher.FindStringSubmatch(body)
	glog.Infof("Found %v as the release note", potentialMatch)
	if potentialMatch == nil {
		glog.Infof("The release note section was probably deleted")
		return ""
	}
	return potentialMatch[1]
}

func chooseLabel(composedReleaseNote string) string {
	composedReleaseNote = strings.ToLower(strings.Trim(composedReleaseNote, " "))

	if composedReleaseNote == "" {
		return releaseNoteLabelNeeded
	}
	if composedReleaseNote == noReleaseNoteComment {
		return releaseNoteNone
	}
	if strings.Contains(composedReleaseNote, actionRequiredNote) {
		return releaseNoteActionRequired
	}
	return releaseNote
}

func releaseNoteAlreadyAdded(obj *github.MungeObject) bool {
	return obj.HasLabel(releaseNote) ||
		obj.HasLabel(releaseNoteActionRequired) ||
		obj.HasLabel(releaseNoteExperimental) ||
		obj.HasLabel(releaseNoteNone)
}

func (r *ReleaseNoteLabel) isStaleComment(obj *github.MungeObject, comment *githubapi.IssueComment) bool {
	if !mergeBotComment(comment) {
		return false
	}
	if *comment.Body != releaseNoteBody && *comment.Body != parentReleaseNoteFormat {
		return false
	}
	if !r.prMustFollowRelNoteProcess(obj) {
		glog.V(6).Infof("Found stale ReleaseNoteLabel comment")
		return true
	}
	stale := releaseNoteAlreadyAdded(obj)
	if stale {
		glog.V(6).Infof("Found stale ReleaseNoteLabel comment")
	}
	return stale
}

// StaleComments returns a slice of stale comments
func (r *ReleaseNoteLabel) StaleComments(obj *github.MungeObject, comments []*githubapi.IssueComment) []*githubapi.IssueComment {
	return forEachCommentTest(obj, comments, r.isStaleComment)
}
<commit_msg>fixing misapplication of do not merge label<commit_after>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

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

package mungers

import (
	"fmt"

	"k8s.io/contrib/mungegithub/features"
	"k8s.io/contrib/mungegithub/github"

	"github.com/golang/glog"
	githubapi "github.com/google/go-github/github"
	"github.com/spf13/cobra"
	"regexp"
	"strings"
)

const (
	releaseNoteLabeler = "release-note-label"

	releaseNoteLabelNeeded    = "release-note-label-needed"
	releaseNote               = "release-note"
	releaseNoteNone           = "release-note-none"
	releaseNoteActionRequired = "release-note-action-required"
	releaseNoteExperimental   = "release-note-experimental"

	releaseNoteFormat = `Adding ` + doNotMergeLabel + ` because the release note process has not been followed.
One of the following labels is required %q, %q, %q or %q.
Please see: https://github.com/kubernetes/kubernetes/blob/master/docs/devel/pull-requests.md#release-notes.`
	parentReleaseNoteFormat = `The 'parent' PR of a cherry-pick PR must have one of the %q or %q labels, or this PR must follow the standard/parent release note labeling requirement. (release-note-experimental must be explicit for cherry-picks)`

	noReleaseNoteComment = "none"
	actionRequiredNote   = "action required"
)

var (
	releaseNoteBody       = fmt.Sprintf(releaseNoteFormat, releaseNote, releaseNoteActionRequired, releaseNoteExperimental, releaseNoteNone)
	parentReleaseNoteBody = fmt.Sprintf(parentReleaseNoteFormat, releaseNote, releaseNoteActionRequired)
)

// ReleaseNoteLabel will add the doNotMergeLabel to a PR which has not
// set one of the appropriete 'release-note-*' labels but has LGTM
type ReleaseNoteLabel struct {
	config *github.Config
}

func init() {
	r := &ReleaseNoteLabel{}
	RegisterMungerOrDie(r)
	RegisterStaleComments(r)
}

// Name is the name usable in --pr-mungers
func (r *ReleaseNoteLabel) Name() string { return releaseNoteLabeler }

// RequiredFeatures is a slice of 'features' that must be provided
func (r *ReleaseNoteLabel) RequiredFeatures() []string { return []string{} }

// Initialize will initialize the munger
func (r *ReleaseNoteLabel) Initialize(config *github.Config, features *features.Features) error {
	r.config = config
	return nil
}

// EachLoop is called at the start of every munge loop
func (r *ReleaseNoteLabel) EachLoop() error { return nil }

// AddFlags will add any request flags to the cobra `cmd`
func (r *ReleaseNoteLabel) AddFlags(cmd *cobra.Command, config *github.Config) {}

func (r *ReleaseNoteLabel) prMustFollowRelNoteProcess(obj *github.MungeObject) bool {
	if obj.IsForBranch("master") {
		return true
	}

	parents := getCherrypickParentPRs(obj, r.config)
	// if it has no parents it needs to follow the release note process
	if len(parents) == 0 {
		return true
	}

	for _, parent := range parents {
		// If the parent didn't set a release note, the CP must
		if !parent.HasLabel(releaseNote) &&
			!parent.HasLabel(releaseNoteActionRequired) {
			if !obj.HasLabel(releaseNoteLabelNeeded) {
				obj.WriteComment(parentReleaseNoteBody)
			}
			return true
		}
	}
	// All of the parents set the releaseNote or releaseNoteActionRequired label,
	// so this cherrypick PR needs to do nothing.
	return false
}

func (r *ReleaseNoteLabel) ensureNoRelNoteNeededLabel(obj *github.MungeObject) {
	if obj.HasLabel(releaseNoteLabelNeeded) {
		obj.RemoveLabel(releaseNoteLabelNeeded)
	}
}

// Munge is the workhorse the will actually make updates to the PR
func (r *ReleaseNoteLabel) Munge(obj *github.MungeObject) {
	if !obj.IsPR() {
		return
	}

	if releaseNoteAlreadyAdded(obj) {
		r.ensureNoRelNoteNeededLabel(obj)
		return
	}

	if !r.prMustFollowRelNoteProcess(obj) {
		r.ensureNoRelNoteNeededLabel(obj)
		return
	}

	labelToAdd := determineReleaseNoteLabel(obj)
	if labelToAdd != releaseNoteLabelNeeded {
		//going to apply some other release-note-label
		if obj.HasLabel(releaseNoteLabelNeeded) {
			obj.RemoveLabel(releaseNoteLabelNeeded)
		}
		obj.AddLabel(labelToAdd)
		return
	}

	if !obj.HasLabel(releaseNoteLabelNeeded) {
		obj.AddLabel(releaseNoteLabelNeeded)
	}

	if !obj.HasLabel(lgtmLabel) {
		return
	}

	if obj.HasLabel(doNotMergeLabel) {
		return
	}

	obj.WriteComment(releaseNoteBody)
	obj.AddLabel(doNotMergeLabel)
}

// determineReleaseNoteLabel returns the label to be added if
// correctly implemented in the PR template.  returns nil otherwise
func determineReleaseNoteLabel(obj *github.MungeObject) string {
	potentialMatch := getReleaseNote(*obj.Issue.Body)
	return chooseLabel(potentialMatch)
}

// getReleaseNote returns the release note from a PR body
// assumes that the PR body followed the PR template
func getReleaseNote(body string) string {
	noteMatcher := regexp.MustCompile("Release note.*```(.+)```")
	potentialMatch := noteMatcher.FindStringSubmatch(body)
	glog.Infof("Found %v as the release note", potentialMatch)
	if potentialMatch == nil {
		glog.Infof("The release note section was probably deleted")
		return ""
	}
	return potentialMatch[1]
}

func chooseLabel(composedReleaseNote string) string {
	composedReleaseNote = strings.ToLower(strings.Trim(composedReleaseNote, " "))

	if composedReleaseNote == "" {
		return releaseNoteLabelNeeded
	}
	if composedReleaseNote == noReleaseNoteComment {
		return releaseNoteNone
	}
	if strings.Contains(composedReleaseNote, actionRequiredNote) {
		return releaseNoteActionRequired
	}
	return releaseNote
}

func releaseNoteAlreadyAdded(obj *github.MungeObject) bool {
	return obj.HasLabel(releaseNote) ||
		obj.HasLabel(releaseNoteActionRequired) ||
		obj.HasLabel(releaseNoteExperimental) ||
		obj.HasLabel(releaseNoteNone)
}

func (r *ReleaseNoteLabel) isStaleComment(obj *github.MungeObject, comment *githubapi.IssueComment) bool {
	if !mergeBotComment(comment) {
		return false
	}
	if *comment.Body != releaseNoteBody && *comment.Body != parentReleaseNoteFormat {
		return false
	}
	if !r.prMustFollowRelNoteProcess(obj) {
		glog.V(6).Infof("Found stale ReleaseNoteLabel comment")
		return true
	}
	stale := releaseNoteAlreadyAdded(obj)
	if stale {
		glog.V(6).Infof("Found stale ReleaseNoteLabel comment")
	}
	return stale
}

// StaleComments returns a slice of stale comments
func (r *ReleaseNoteLabel) StaleComments(obj *github.MungeObject, comments []*githubapi.IssueComment) []*githubapi.IssueComment {
	return forEachCommentTest(obj, comments, r.isStaleComment)
}
<|endoftext|>


<commit_before>// Package einhorn allows you to communicate with the einhorn master from a Go
// worker.
package einhorn

import (
	"encoding/json"
	"errors"
	"net"
	"os"
	"strconv"
)

// CountListeners returns the number of listener fd's passed by the master.
func CountListeners() uint {
	count, err := strconv.ParseUint(os.Getenv("EINHORN_FD_COUNT"), 10, 32)
	if err != nil {
		return 0
	}
	return uint(count)
}

// GetListener returns the passed listener with the specified index.
func GetListener(index uint) (net.Listener, error) {
	if CountListeners() < (index + 1) {
		return nil, errors.New("Too few EINHORN_FDs passed")
	}
	name := "EINHORN_FD_" + strconv.Itoa(int(index))

	fileno, err := strconv.Atoi(os.Getenv(name))
	if err != nil {
		return nil, errors.New("Could not parse fd: " + err.Error())
	}

	file := os.NewFile(uintptr(fileno), name)
	listener, err := net.FileListener(file)
	if err != nil {
		return nil, errors.New("Could not create listener from fd: " + err.Error())
	}

	return listener, nil
}

// Ack sends an ack to the einhorn master.
func Ack() error {
	return sendToMaster(workerMessage{Command: "worker:ack", Pid: os.Getpid()})
}

type workerMessage struct {
	Command string `json:"comand"`
	Pid     int
}

func sendToMaster(msg workerMessage) error {
	sockPath := os.Getenv("EINHORN_SOCK_PATH")
	controlConn, err := net.Dial("unix", sockPath)
	if err != nil {
		return errors.New("Could not connect to einhorn master: " + err.Error())
	}

	serialized, err := json.Marshal(msg)
	if err != nil {
		return errors.New("Could not serialize message: " + err.Error())
	}

	_, err = controlConn.Write(serialized)
	if err != nil {
		return errors.New("Could not write to einhorn master: " + err.Error())
	}

	_, err = controlConn.Write([]byte("\n"))
	if err != nil {
		return errors.New("Could not write to einhorn master: " + err.Error())
	}

	err = controlConn.Close()
	if err != nil {
		return errors.New("Could not close connection to einhorn master: " + err.Error())
	}

	return nil
}
<commit_msg>Defer closing the control connection.<commit_after>// Package einhorn allows you to communicate with the einhorn master from a Go
// worker.
package einhorn

import (
	"encoding/json"
	"errors"
	"net"
	"os"
	"strconv"
)

// CountListeners returns the number of listener fd's passed by the master.
func CountListeners() uint {
	count, err := strconv.ParseUint(os.Getenv("EINHORN_FD_COUNT"), 10, 32)
	if err != nil {
		return 0
	}
	return uint(count)
}

// GetListener returns the passed listener with the specified index.
func GetListener(index uint) (net.Listener, error) {
	if CountListeners() < (index + 1) {
		return nil, errors.New("Too few EINHORN_FDs passed")
	}
	name := "EINHORN_FD_" + strconv.Itoa(int(index))

	fileno, err := strconv.Atoi(os.Getenv(name))
	if err != nil {
		return nil, errors.New("Could not parse fd: " + err.Error())
	}

	file := os.NewFile(uintptr(fileno), name)
	listener, err := net.FileListener(file)
	if err != nil {
		return nil, errors.New("Could not create listener from fd: " + err.Error())
	}

	return listener, nil
}

// Ack sends an ack to the einhorn master.
func Ack() error {
	return sendToMaster(workerMessage{Command: "worker:ack", Pid: os.Getpid()})
}

type workerMessage struct {
	Command string `json:"comand"`
	Pid     int
}

func sendToMaster(msg workerMessage) error {
	sockPath := os.Getenv("EINHORN_SOCK_PATH")
	controlConn, err := net.Dial("unix", sockPath)
	if err != nil {
		return errors.New("Could not connect to einhorn master: " + err.Error())
	}
	defer controlConn.Close()

	serialized, err := json.Marshal(msg)
	if err != nil {
		return errors.New("Could not serialize message: " + err.Error())
	}

	_, err = controlConn.Write(serialized)
	if err != nil {
		return errors.New("Could not write to einhorn master: " + err.Error())
	}

	_, err = controlConn.Write([]byte("\n"))
	if err != nil {
		return errors.New("Could not write to einhorn master: " + err.Error())
	}

	return nil
}
<|endoftext|>


<commit_before>package autonat

import (
	inet "github.com/libp2p/go-libp2p-net"
	peer "github.com/libp2p/go-libp2p-peer"
	ma "github.com/multiformats/go-multiaddr"
)

var _ inet.Notifiee = (*AutoNATState)(nil)

func (as *AutoNATState) Listen(net inet.Network, a ma.Multiaddr)      {}
func (as *AutoNATState) ListenClose(net inet.Network, a ma.Multiaddr) {}
func (as *AutoNATState) OpenedStream(net inet.Network, s inet.Stream) {}
func (as *AutoNATState) ClosedStream(net inet.Network, s inet.Stream) {}

func (as *AutoNATState) Connected(net inet.Network, c inet.Conn) {
	go func(p peer.ID) {
		s, err := as.host.NewStream(as.ctx, p, AutoNATProto)
		if err != nil {
			return
		}
		s.Close()

		log.Infof("Discovered AutoNAT peer %s", p.Pretty())
		as.mx.Lock()
		as.peers[p] = true
		as.mx.Unlock()
	}(c.RemotePeer())
}

func (as *AutoNATState) Disconnected(net inet.Network, c inet.Conn) {
	as.mx.Lock()
	as.peers[c.RemotePeer()] = false
	as.mx.Unlock()
}
<commit_msg>we only track autonat peers<commit_after>package autonat

import (
	inet "github.com/libp2p/go-libp2p-net"
	peer "github.com/libp2p/go-libp2p-peer"
	ma "github.com/multiformats/go-multiaddr"
)

var _ inet.Notifiee = (*AutoNATState)(nil)

func (as *AutoNATState) Listen(net inet.Network, a ma.Multiaddr)      {}
func (as *AutoNATState) ListenClose(net inet.Network, a ma.Multiaddr) {}
func (as *AutoNATState) OpenedStream(net inet.Network, s inet.Stream) {}
func (as *AutoNATState) ClosedStream(net inet.Network, s inet.Stream) {}

func (as *AutoNATState) Connected(net inet.Network, c inet.Conn) {
	go func(p peer.ID) {
		s, err := as.host.NewStream(as.ctx, p, AutoNATProto)
		if err != nil {
			return
		}
		s.Close()

		log.Infof("Discovered AutoNAT peer %s", p.Pretty())
		as.mx.Lock()
		as.peers[p] = true
		as.mx.Unlock()
	}(c.RemotePeer())
}

func (as *AutoNATState) Disconnected(net inet.Network, c inet.Conn) {
	as.mx.Lock()
	p := c.RemotePeer()
	_, ok := as.peers[p]
	if ok {
		as.peers[p] = false
	}
	as.mx.Unlock()
}
<|endoftext|>


<commit_before>package vm

import (
  "fmt"
  "math"
  "github.com/glhrmfrts/elo-lang/elo/ast"
)

type (
  CompileError struct {
    Line    int
    File    string
    Message string
  }

  // holds registers for a expression
  exprdata struct {
    propagate bool
    rega      int // rega is default for write
    regb      int // regb is default for read
  }

  // lexical scope of a name
  scope int

  // lexical context of a block, (function, loop, branch...)
  blockcontext int

  // information of a name in the program
  nameinfo struct {
    isConst bool
    reg     int
    scope   scope
  }

  // lexical block structure for compiler
  compilerblock struct {
    context    blockcontext
    registerId int
    names      map[string]*nameinfo
    proto      *FuncProto
    parent     *compilerblock
  }

  compiler struct {
    lastLine int
    filename string
    mainFunc *FuncProto
    block    *compilerblock
  }
)

const (
  kScopeLocal scope = iota
  kScopeUpval
  kScopeGlobal
)

const (
  kContextFunc blockcontext = iota
  kContextLoop
  kContextBranch
)

func (err *CompileError) Error() string {
  return fmt.Sprintf("%s:%d: error: %s", err.File, err.Line, err.Message)
}

func newCompilerBlock(proto *FuncProto) *compilerblock {
  return &compilerblock{
    proto: proto,
  }
}

func (c *compiler) error(line int, msg string) {
  panic(&CompileError{Line: line, File: c.filename, Message: msg})
}

func (c *compiler) emitInstruction(instr uint32, line int) {
  f := c.block.proto
  f.Code = append(f.Code, instr)
  f.NumCode++

  if line != c.lastLine {
    f.Lines = append(f.Lines, LineInfo{f.NumCode - 1, uint16(line)})
    f.NumLines++
    c.lastLine = line
  }
}

func (c *compiler) emitAB(op Opcode, a, b, line int) {
  c.emitInstruction(opNewAB(op, a, b), line)
}

func (cc *compiler) emitABC(op Opcode, a, b, c, line int) {
  cc.emitInstruction(opNewABC(op, a, b, c), line)
}

func (c *compiler) emitABx(op Opcode, a, b, line int) {
  c.emitInstruction(opNewABx(op, a, b), line)
}

func (c *compiler) genRegisterId() int {
  id := c.block.registerId
  c.block.registerId++
  fmt.Printf("genRegisterId: %d\n", id)
  return id
}

// Add a constant to the current prototype's constant pool
// and return it's index
func (c *compiler) addConst(value Value) int {
  f := c.block.proto
  valueType := value.Type()
  for i, c := range f.Consts {
    if c.Type() == valueType && c == value {
      return i
    }
  }
  if f.NumConsts > funcMaxConsts - 1 {
    c.error(0, "too many constants") // should never happen
  }
  f.Consts = append(f.Consts, value)
  f.NumConsts++
  return int(f.NumConsts - 1)
}

func (c *compiler) nameInfo(name string) *nameinfo {
  var closures int
  block := c.block
  for block != nil {
    info, ok := block.names[name]
    if ok {
      if closures > 0 {
        info.scope = kScopeUpval
      }
      return info
    }
    if block.context == kContextFunc {
      closures++
    }
    block = block.parent
  }

  // assume a name is global if it can't be found
  return &nameinfo{false, 0, kScopeGlobal}
}

// try to "constant fold" an expression
// TODO: work with constant names
func (c *compiler) constFold(node ast.Node) (Value, bool) {
  switch t := node.(type) {
  case *ast.Number:
    return Number(t.Value), true
  case *ast.Bool:
    return Bool(t.Value), true
  case *ast.String:
    return String(t.Value), true
  case *ast.UnaryExpr:
    if t.Op == ast.T_MINUS {
      val, ok := c.constFold(t.Right)
      if ok && val.Type() == VALUE_NUMBER {
        f64, _ := val.assertFloat64()
        return Number(-f64), true
      }
      return nil, false
    } else {
      // 'not' operator
      val, ok := c.constFold(t.Right)
      if ok && val.Type() == VALUE_BOOL {
        bool_, _ := val.assertBool()
        return Bool(!bool_), true
      }
      return nil, false
    }
  case *ast.BinaryExpr:
    left, leftOk := c.constFold(t.Left)
    right, rightOk := c.constFold(t.Right)
    if leftOk && rightOk {
      var ret Value
      if left.Type() != right.Type() {
        return nil, false
      }
      lf64, ok := left.assertFloat64()
      rf64, _ := right.assertFloat64()
      if !ok {
        goto boolOps
      }

      // first check all arithmetic/relational operations
      switch t.Op {
      case ast.T_PLUS:
        ret = Number(lf64 + rf64)
      case ast.T_MINUS:
        ret = Number(lf64 - rf64)
      case ast.T_TIMES:
        ret = Number(lf64 * rf64)
      case ast.T_DIV:
        ret = Number(lf64 / rf64)
      case ast.T_TIMESTIMES:
        ret = Number(math.Pow(lf64, rf64))
      case ast.T_LT:
        ret = Bool(lf64 < rf64)
      case ast.T_LTEQ:
        ret = Bool(lf64 <= rf64)
      case ast.T_GT:
        ret = Bool(lf64 > rf64)
      case ast.T_GTEQ:
        ret = Bool(lf64 >= rf64)
      case ast.T_EQEQ:
        ret = Bool(lf64 == rf64)
      }
      if ret != nil {
        return ret, true
      }

    boolOps:
      // not arithmetic/relational, maybe logic?
      lb, ok := left.assertBool()
      rb, _ := right.assertBool()
      if !ok {
        goto stringOps
      }

      switch t.Op {
      case ast.T_AMPAMP:
        return Bool(lb && rb), true
      case ast.T_PIPEPIPE:
        return Bool(lb || rb), true
      }

    stringOps:
      ls, ok := left.assertString()
      rs, _ := right.assertString()
      if !ok {
        return nil, false
      }

      switch t.Op {
      case ast.T_EQEQ:
        return Bool(ls == rs), true
      case ast.T_BANGEQ:
        return Bool(ls != rs), true
      }
    }
  }
  return nil, false
}

func (c *compiler) VisitNil(node *ast.Nil, data interface{}) {
  var rega, regb int
  expr, ok := data.(*exprdata)
  if ok {
    rega, regb = expr.rega, expr.regb
  } else {
    rega = c.genRegisterId()
    regb = rega
  }
  c.emitAB(OP_LOADNIL, rega, regb, node.NodeInfo.Line)
}

func (c *compiler) VisitBool(node *ast.Bool, data interface{}) {
  var reg int
  value := Bool(node.Value)
  expr, ok := data.(*exprdata)
  if ok && expr.propagate {
    expr.regb = kConstOffset + c.addConst(value)
    return
  } else if ok {
    reg = expr.rega
  } else {
    reg = c.genRegisterId()
  }
  c.emitABx(OP_LOADCONST, reg, c.addConst(value), node.NodeInfo.Line)
}

func (c *compiler) VisitNumber(node *ast.Number, data interface{}) {
  var reg int
  value := Number(node.Value)
  expr, ok := data.(*exprdata)
  if ok && expr.propagate {
    expr.regb = kConstOffset + c.addConst(value)
    return
  } else if ok {
    reg = expr.rega
  } else {
    reg = c.genRegisterId()
  }
  c.emitABx(OP_LOADCONST, reg, c.addConst(value), node.NodeInfo.Line)
}

func (c *compiler) VisitString(node *ast.String, data interface{}) {
  var reg int
  var value Value
  expr, ok := data.(*exprdata)
  if !ok {
    reg = c.genRegisterId()
  } else {
    reg = expr.rega
  }
  value = String(node.Value)
  c.emitABx(OP_LOADCONST, reg, c.addConst(value), node.NodeInfo.Line)
}

func (c *compiler) VisitId(node *ast.Id, data interface{}) {
  /*var reg int
  expr, ok := data.(*exprdata)
  if !ok {
    reg = c.genRegisterId()
  } else {
    reg = expr.rega
  }
  info := c.nameInfo(node.Value)
  switch info.scope {
  case kScopeLocal:
    c.emitAB(OP_MOVE, reg, info.reg, node.NodeInfo.Line)
  case kScopeUpval:
    //c.emitAB(OP_LOADUPVAL, reg, c.addUpval(node.Value), node.NodeInfo.Line)
    break
  case kScopeGlobal:
    c.emitAB(OP_LOADGLOBAL, reg, c.addConst(node.Value), node.NodeInfo.Line)
  }*/
}

func (c *compiler) VisitArray(node *ast.Array, data interface{}) {

}

func (c *compiler) VisitObjectField(node *ast.ObjectField, data interface{}) {

}

func (c *compiler) VisitObject(node *ast.Object, data interface{}) {

}

func (c *compiler) VisitFunction(node *ast.Function, data interface{}) {

}

func (c *compiler) VisitSelector(node *ast.Selector, data interface{}) {

}

func (c *compiler) VisitSubscript(node *ast.Subscript, data interface{}) {

}

func (c *compiler) VisitSlice(node *ast.Slice, data interface{}) {

}

func (c *compiler) VisitKwArg(node *ast.KwArg, data interface{}) {

}

func (c *compiler) VisitVarArg(node *ast.VarArg, data interface{}) {

}

func (c *compiler) VisitCallExpr(node *ast.CallExpr, data interface{}) {

}

func (c *compiler) VisitUnaryExpr(node *ast.UnaryExpr, data interface{}) {
  var reg int
  expr, exprok := data.(*exprdata)
  if exprok {
    reg = expr.rega
  } else {
    reg = c.genRegisterId()
  }
  value, ok := c.constFold(node)
  if ok {
    if exprok && expr.propagate {
      expr.regb = kConstOffset + c.addConst(value)
      return
    }
    c.emitABx(OP_LOADCONST, reg, c.addConst(value), node.NodeInfo.Line)
  } else {
    var op Opcode
    switch node.Op {
    case ast.T_MINUS:
      op = OP_NEGATE
    case ast.T_NOT, ast.T_BANG:
      op = OP_NOT
    }
    exprdata := exprdata{true, 0, 0}
    node.Right.Accept(c, &exprdata)
    c.emitABx(op, reg, exprdata.regb, node.NodeInfo.Line)
  }
}

func (c *compiler) VisitBinaryExpr(node *ast.BinaryExpr, data interface{}) {
  var reg int
  expr, exprok := data.(*exprdata)
  if exprok {
    reg = expr.rega
  } else {
    reg = c.genRegisterId()
  }
  value, ok := c.constFold(node)
  if ok {
    if exprok && expr.propagate {
      expr.regb = kConstOffset + c.addConst(value)
      return
    }
    c.emitABx(OP_LOADCONST, reg, c.addConst(value), node.NodeInfo.Line)
  } else {
    var op Opcode
    switch node.Op {
    case ast.T_PLUS:
      op = OP_ADD
    case ast.T_MINUS:
      op = OP_SUB
    case ast.T_TIMES:
      op = OP_MUL
    case ast.T_DIV:
      op = OP_DIV
    }
    exprdata := exprdata{true, 0, 0}
    node.Left.Accept(c, &exprdata)
    left := exprdata.regb
    node.Right.Accept(c, &exprdata)
    right := exprdata.regb
    c.emitABC(op, reg, left, right, node.NodeInfo.Line)
    if exprok && expr.propagate {
      expr.regb = reg
    }
  }
}

func (c *compiler) VisitTernaryExpr(node *ast.TernaryExpr, data interface{}) {

}

func (c *compiler) VisitDeclaration(node *ast.Declaration, data interface{}) {

}

func (c *compiler) VisitAssignment(node *ast.Assignment, data interface{}) {

}

func (c *compiler) VisitBranchStmt(node *ast.BranchStmt, data interface{}) {

}

func (c *compiler) VisitReturnStmt(node *ast.ReturnStmt, data interface{}) {

}

func (c *compiler) VisitIfStmt(node *ast.IfStmt, data interface{}) {

}

func (c *compiler) VisitForIteratorStmt(node *ast.ForIteratorStmt, data interface{}) {

}

func (c *compiler) VisitForStmt(node *ast.ForStmt, data interface{}) {

}

func (c *compiler) VisitBlock(node *ast.Block, data interface{}) {
  for _, stmt := range node.Nodes {
    stmt.Accept(c, nil)

    if !ast.IsStmt(stmt) {
      c.block.registerId -= 1
    }
  }
}

func Compile(root ast.Node, filename string) (res *FuncProto, err error) {
  defer func() {
    if r := recover(); r != nil {
      if cerr, ok := r.(*CompileError); ok {
        err = cerr
      } else {
        panic(r)
      }
    }
  }()

  var c compiler
  c.filename = filename
  c.mainFunc = newFuncProto(filename)
  c.block = newCompilerBlock(c.mainFunc)

  root.Accept(&c, nil)

  res = c.mainFunc
  return
}<commit_msg>propagate unary expression<commit_after>package vm

import (
  "fmt"
  "math"
  "github.com/glhrmfrts/elo-lang/elo/ast"
)

type (
  CompileError struct {
    Line    int
    File    string
    Message string
  }

  // holds registers for a expression
  exprdata struct {
    propagate bool
    rega      int // rega is default for write
    regb      int // regb is default for read
  }

  // lexical scope of a name
  scope int

  // lexical context of a block, (function, loop, branch...)
  blockcontext int

  // information of a name in the program
  nameinfo struct {
    isConst bool
    reg     int
    scope   scope
  }

  // lexical block structure for compiler
  compilerblock struct {
    context    blockcontext
    registerId int
    names      map[string]*nameinfo
    proto      *FuncProto
    parent     *compilerblock
  }

  compiler struct {
    lastLine int
    filename string
    mainFunc *FuncProto
    block    *compilerblock
  }
)

// names lexical scopes
const (
  kScopeLocal scope = iota
  kScopeUpval
  kScopeGlobal
)

// blocks context
const (
  kContextFunc blockcontext = iota
  kContextLoop
  kContextBranch
)

func (err *CompileError) Error() string {
  return fmt.Sprintf("%s:%d: error: %s", err.File, err.Line, err.Message)
}

func newCompilerBlock(proto *FuncProto) *compilerblock {
  return &compilerblock{
    proto: proto,
  }
}

func (c *compiler) error(line int, msg string) {
  panic(&CompileError{Line: line, File: c.filename, Message: msg})
}

func (c *compiler) emitInstruction(instr uint32, line int) {
  f := c.block.proto
  f.Code = append(f.Code, instr)
  f.NumCode++

  if line != c.lastLine {
    f.Lines = append(f.Lines, LineInfo{f.NumCode - 1, uint16(line)})
    f.NumLines++
    c.lastLine = line
  }
}

func (c *compiler) emitAB(op Opcode, a, b, line int) {
  c.emitInstruction(opNewAB(op, a, b), line)
}

func (cc *compiler) emitABC(op Opcode, a, b, c, line int) {
  cc.emitInstruction(opNewABC(op, a, b, c), line)
}

func (c *compiler) emitABx(op Opcode, a, b, line int) {
  c.emitInstruction(opNewABx(op, a, b), line)
}

func (c *compiler) genRegisterId() int {
  id := c.block.registerId
  c.block.registerId++
  fmt.Printf("genRegisterId: %d\n", id)
  return id
}

// Add a constant to the current prototype's constant pool
// and return it's index
func (c *compiler) addConst(value Value) int {
  f := c.block.proto
  valueType := value.Type()
  for i, c := range f.Consts {
    if c.Type() == valueType && c == value {
      return i
    }
  }
  if f.NumConsts > funcMaxConsts - 1 {
    c.error(0, "too many constants") // should never happen
  }
  f.Consts = append(f.Consts, value)
  f.NumConsts++
  return int(f.NumConsts - 1)
}

func (c *compiler) nameInfo(name string) *nameinfo {
  var closures int
  block := c.block
  for block != nil {
    info, ok := block.names[name]
    if ok {
      if closures > 0 {
        info.scope = kScopeUpval
      }
      return info
    }
    if block.context == kContextFunc {
      closures++
    }
    block = block.parent
  }

  // assume a name is global if it can't be found
  return &nameinfo{false, 0, kScopeGlobal}
}

// try to "constant fold" an expression
// TODO: work with constant names
func (c *compiler) constFold(node ast.Node) (Value, bool) {
  switch t := node.(type) {
  case *ast.Number:
    return Number(t.Value), true
  case *ast.Bool:
    return Bool(t.Value), true
  case *ast.String:
    return String(t.Value), true
  case *ast.UnaryExpr:
    if t.Op == ast.T_MINUS {
      val, ok := c.constFold(t.Right)
      if ok && val.Type() == VALUE_NUMBER {
        f64, _ := val.assertFloat64()
        return Number(-f64), true
      }
      return nil, false
    } else {
      // 'not' operator
      val, ok := c.constFold(t.Right)
      if ok && val.Type() == VALUE_BOOL {
        bool_, _ := val.assertBool()
        return Bool(!bool_), true
      }
      return nil, false
    }
  case *ast.BinaryExpr:
    left, leftOk := c.constFold(t.Left)
    right, rightOk := c.constFold(t.Right)
    if leftOk && rightOk {
      var ret Value
      if left.Type() != right.Type() {
        return nil, false
      }
      lf64, ok := left.assertFloat64()
      rf64, _ := right.assertFloat64()
      if !ok {
        goto boolOps
      }

      // first check all arithmetic/relational operations
      switch t.Op {
      case ast.T_PLUS:
        ret = Number(lf64 + rf64)
      case ast.T_MINUS:
        ret = Number(lf64 - rf64)
      case ast.T_TIMES:
        ret = Number(lf64 * rf64)
      case ast.T_DIV:
        ret = Number(lf64 / rf64)
      case ast.T_TIMESTIMES:
        ret = Number(math.Pow(lf64, rf64))
      case ast.T_LT:
        ret = Bool(lf64 < rf64)
      case ast.T_LTEQ:
        ret = Bool(lf64 <= rf64)
      case ast.T_GT:
        ret = Bool(lf64 > rf64)
      case ast.T_GTEQ:
        ret = Bool(lf64 >= rf64)
      case ast.T_EQEQ:
        ret = Bool(lf64 == rf64)
      }
      if ret != nil {
        return ret, true
      }

    boolOps:
      // not arithmetic/relational, maybe logic?
      lb, ok := left.assertBool()
      rb, _ := right.assertBool()
      if !ok {
        goto stringOps
      }

      switch t.Op {
      case ast.T_AMPAMP:
        return Bool(lb && rb), true
      case ast.T_PIPEPIPE:
        return Bool(lb || rb), true
      }

    stringOps:
      ls, ok := left.assertString()
      rs, _ := right.assertString()
      if !ok {
        return nil, false
      }

      switch t.Op {
      case ast.T_EQEQ:
        return Bool(ls == rs), true
      case ast.T_BANGEQ:
        return Bool(ls != rs), true
      }
    }
  }
  return nil, false
}

func (c *compiler) VisitNil(node *ast.Nil, data interface{}) {
  var rega, regb int
  expr, ok := data.(*exprdata)
  if ok {
    rega, regb = expr.rega, expr.regb
  } else {
    rega = c.genRegisterId()
    regb = rega
  }
  c.emitAB(OP_LOADNIL, rega, regb, node.NodeInfo.Line)
}

func (c *compiler) VisitBool(node *ast.Bool, data interface{}) {
  var reg int
  value := Bool(node.Value)
  expr, ok := data.(*exprdata)
  if ok && expr.propagate {
    expr.regb = kConstOffset + c.addConst(value)
    return
  } else if ok {
    reg = expr.rega
  } else {
    reg = c.genRegisterId()
  }
  c.emitABx(OP_LOADCONST, reg, c.addConst(value), node.NodeInfo.Line)
}

func (c *compiler) VisitNumber(node *ast.Number, data interface{}) {
  var reg int
  value := Number(node.Value)
  expr, ok := data.(*exprdata)
  if ok && expr.propagate {
    expr.regb = kConstOffset + c.addConst(value)
    return
  } else if ok {
    reg = expr.rega
  } else {
    reg = c.genRegisterId()
  }
  c.emitABx(OP_LOADCONST, reg, c.addConst(value), node.NodeInfo.Line)
}

func (c *compiler) VisitString(node *ast.String, data interface{}) {
  var reg int
  var value Value
  expr, ok := data.(*exprdata)
  if !ok {
    reg = c.genRegisterId()
  } else {
    reg = expr.rega
  }
  value = String(node.Value)
  c.emitABx(OP_LOADCONST, reg, c.addConst(value), node.NodeInfo.Line)
}

func (c *compiler) VisitId(node *ast.Id, data interface{}) {
  /*var reg int
  expr, ok := data.(*exprdata)
  if !ok {
    reg = c.genRegisterId()
  } else {
    reg = expr.rega
  }
  info := c.nameInfo(node.Value)
  switch info.scope {
  case kScopeLocal:
    c.emitAB(OP_MOVE, reg, info.reg, node.NodeInfo.Line)
  case kScopeUpval:
    //c.emitAB(OP_LOADUPVAL, reg, c.addUpval(node.Value), node.NodeInfo.Line)
    break
  case kScopeGlobal:
    c.emitAB(OP_LOADGLOBAL, reg, c.addConst(node.Value), node.NodeInfo.Line)
  }*/
}

func (c *compiler) VisitArray(node *ast.Array, data interface{}) {

}

func (c *compiler) VisitObjectField(node *ast.ObjectField, data interface{}) {

}

func (c *compiler) VisitObject(node *ast.Object, data interface{}) {

}

func (c *compiler) VisitFunction(node *ast.Function, data interface{}) {

}

func (c *compiler) VisitSelector(node *ast.Selector, data interface{}) {

}

func (c *compiler) VisitSubscript(node *ast.Subscript, data interface{}) {

}

func (c *compiler) VisitSlice(node *ast.Slice, data interface{}) {

}

func (c *compiler) VisitKwArg(node *ast.KwArg, data interface{}) {

}

func (c *compiler) VisitVarArg(node *ast.VarArg, data interface{}) {

}

func (c *compiler) VisitCallExpr(node *ast.CallExpr, data interface{}) {

}

func (c *compiler) VisitUnaryExpr(node *ast.UnaryExpr, data interface{}) {
  var reg int
  expr, exprok := data.(*exprdata)
  if exprok {
    reg = expr.rega
  } else {
    reg = c.genRegisterId()
  }
  value, ok := c.constFold(node)
  if ok {
    if exprok && expr.propagate {
      expr.regb = kConstOffset + c.addConst(value)
      return
    }
    c.emitABx(OP_LOADCONST, reg, c.addConst(value), node.NodeInfo.Line)
  } else {
    var op Opcode
    switch node.Op {
    case ast.T_MINUS:
      op = OP_NEGATE
    case ast.T_NOT, ast.T_BANG:
      op = OP_NOT
    }
    exprdata := exprdata{true, 0, 0}
    node.Right.Accept(c, &exprdata)
    c.emitABx(op, reg, exprdata.regb, node.NodeInfo.Line)
    if exprok && expr.propagate {
      expr.regb = reg
    }
  }
}

func (c *compiler) VisitBinaryExpr(node *ast.BinaryExpr, data interface{}) {
  var reg int
  expr, exprok := data.(*exprdata)
  if exprok {
    reg = expr.rega
  } else {
    reg = c.genRegisterId()
  }
  value, ok := c.constFold(node)
  if ok {
    if exprok && expr.propagate {
      expr.regb = kConstOffset + c.addConst(value)
      return
    }
    c.emitABx(OP_LOADCONST, reg, c.addConst(value), node.NodeInfo.Line)
  } else {
    var op Opcode
    switch node.Op {
    case ast.T_PLUS:
      op = OP_ADD
    case ast.T_MINUS:
      op = OP_SUB
    case ast.T_TIMES:
      op = OP_MUL
    case ast.T_DIV:
      op = OP_DIV
    }
    exprdata := exprdata{true, 0, 0}
    node.Left.Accept(c, &exprdata)
    left := exprdata.regb
    node.Right.Accept(c, &exprdata)
    right := exprdata.regb
    c.emitABC(op, reg, left, right, node.NodeInfo.Line)
    if exprok && expr.propagate {
      expr.regb = reg
    }
  }
}

func (c *compiler) VisitTernaryExpr(node *ast.TernaryExpr, data interface{}) {

}

func (c *compiler) VisitDeclaration(node *ast.Declaration, data interface{}) {

}

func (c *compiler) VisitAssignment(node *ast.Assignment, data interface{}) {

}

func (c *compiler) VisitBranchStmt(node *ast.BranchStmt, data interface{}) {

}

func (c *compiler) VisitReturnStmt(node *ast.ReturnStmt, data interface{}) {

}

func (c *compiler) VisitIfStmt(node *ast.IfStmt, data interface{}) {

}

func (c *compiler) VisitForIteratorStmt(node *ast.ForIteratorStmt, data interface{}) {

}

func (c *compiler) VisitForStmt(node *ast.ForStmt, data interface{}) {

}

func (c *compiler) VisitBlock(node *ast.Block, data interface{}) {
  for _, stmt := range node.Nodes {
    stmt.Accept(c, nil)

    if !ast.IsStmt(stmt) {
      c.block.registerId -= 1
    }
  }
}

func Compile(root ast.Node, filename string) (res *FuncProto, err error) {
  defer func() {
    if r := recover(); r != nil {
      if cerr, ok := r.(*CompileError); ok {
        err = cerr
      } else {
        panic(r)
      }
    }
  }()

  var c compiler
  c.filename = filename
  c.mainFunc = newFuncProto(filename)
  c.block = newCompilerBlock(c.mainFunc)

  root.Accept(&c, nil)

  res = c.mainFunc
  return
}<|endoftext|>