<commit_before>package main

import (
	"fmt"
	"net/url"
	"os/exec"
)

var cmdInfo = &Command{
	Run:   runInfo,
	Usage: "info",
	Short: "show app info",
	Long:  `Info shows general information about the current app.`,
}

func runInfo(cmd *Command, args []string) {
	var info struct {
		Name   string
		Owner  string `json:"owner_email"`
		Stack  string
		GitURL string `json:"git_url"`
		WebURL string `json:"web_url"`
	}
	APIReq("GET", "/apps/"+app()).Do(&info)
	fmt.Printf("Name:     %s\n", info.Name)
	fmt.Printf("Owner:    %s\n", info.Owner)
	fmt.Printf("Stack:    %s\n", info.Stack)
	fmt.Printf("Git URL:  %s\n", info.GitURL)
	fmt.Printf("Web URL:  %s\n", info.WebURL)
}

var cmdOpen = &Command{
	Run:   runOpen,
	Usage: "open",
	Short: "open app",
	Long:  `Open opens the app in a web browser. (Assumes cedar.)`,
}

func runOpen(cmd *Command, args []string) {
	u := "https://" + app() + ".herokuapp.com/"
	command := "open"
	if _, err := exec.LookPath("xdg-open"); err == nil {
		command = "xdg-open"
	}
	exec.Command(command, u).Start()
}

var cmdList = &Command{
	Run:   runList,
	Usage: "list",
	Short: "list apps",
	Long:  `List lists all accessible apps.`,
}

func runList(cmd *Command, args []string) {
	var apps []struct{ Name string }
	APIReq("GET", "/apps").Do(&apps)
	for _, app := range apps {
		fmt.Printf("%s\n", app.Name)
	}
}

var cmdCreate = &Command{
	Run:   runCreate,
	Usage: "create [name]",
	Short: "create an app",
	Long:  `Create creates a new heroku app.`,
}

func runCreate(cmd *Command, args []string) {
	var info struct {
		Name   string
		Stack  string
		GitURL string `json:"git_url"`
	}

	v := make(url.Values)
	if len(args) > 0 {
		v.Set("app[name]", args[0])
	}
	if len(args) > 1 {
		v.Set("app[stack]", args[1])
	}

	r := APIReq("POST", "/apps")
	r.SetBodyForm(v)
	r.Do(&info)
	exec.Command("git", "remote", "add", "heroku", info.GitURL).Run()
	fmt.Println(info.Name)
}

var cmdDestroy = &Command{
	Run:   runDestroy,
	Usage: "destroy <name>",
	Short: "destroy an app",
	Long:  `Destroy destroys a heroku app.`,
}

func runDestroy(cmd *Command, args []string) {
	APIReq("DELETE", "/apps/"+args[0]).Do(nil)
	for _, remote := range gitRemotes(gitURL(args[0])) {
		exec.Command("git", "remote", "rm", remote).Run()
	}
}
<commit_msg>always use cedar<commit_after>package main

import (
	"fmt"
	"net/url"
	"os/exec"
)

var cmdInfo = &Command{
	Run:   runInfo,
	Usage: "info",
	Short: "show app info",
	Long:  `Info shows general information about the current app.`,
}

func runInfo(cmd *Command, args []string) {
	var info struct {
		Name   string
		Owner  string `json:"owner_email"`
		Stack  string
		GitURL string `json:"git_url"`
		WebURL string `json:"web_url"`
	}
	APIReq("GET", "/apps/"+app()).Do(&info)
	fmt.Printf("Name:     %s\n", info.Name)
	fmt.Printf("Owner:    %s\n", info.Owner)
	fmt.Printf("Stack:    %s\n", info.Stack)
	fmt.Printf("Git URL:  %s\n", info.GitURL)
	fmt.Printf("Web URL:  %s\n", info.WebURL)
}

var cmdOpen = &Command{
	Run:   runOpen,
	Usage: "open",
	Short: "open app",
	Long:  `Open opens the app in a web browser. (Assumes cedar.)`,
}

func runOpen(cmd *Command, args []string) {
	u := "https://" + app() + ".herokuapp.com/"
	command := "open"
	if _, err := exec.LookPath("xdg-open"); err == nil {
		command = "xdg-open"
	}
	exec.Command(command, u).Start()
}

var cmdList = &Command{
	Run:   runList,
	Usage: "list",
	Short: "list apps",
	Long:  `List lists all accessible apps.`,
}

func runList(cmd *Command, args []string) {
	var apps []struct{ Name string }
	APIReq("GET", "/apps").Do(&apps)
	for _, app := range apps {
		fmt.Printf("%s\n", app.Name)
	}
}

var cmdCreate = &Command{
	Run:   runCreate,
	Usage: "create [name]",
	Short: "create an app",
	Long:  `Create creates a new heroku app.`,
}

func runCreate(cmd *Command, args []string) {
	var info struct {
		Name   string
		Stack  string
		GitURL string `json:"git_url"`
	}

	v := make(url.Values)
	v.Set("app[stack]", "cedar")
	if len(args) > 0 {
		v.Set("app[name]", args[0])
	}

	r := APIReq("POST", "/apps")
	r.SetBodyForm(v)
	r.Do(&info)
	exec.Command("git", "remote", "add", "heroku", info.GitURL).Run()
	fmt.Println(info.Name)
}

var cmdDestroy = &Command{
	Run:   runDestroy,
	Usage: "destroy <name>",
	Short: "destroy an app",
	Long:  `Destroy destroys a heroku app.`,
}

func runDestroy(cmd *Command, args []string) {
	APIReq("DELETE", "/apps/"+args[0]).Do(nil)
	for _, remote := range gitRemotes(gitURL(args[0])) {
		exec.Command("git", "remote", "rm", remote).Run()
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Doctl Authors All rights reserved.
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 doctl

const (
	// ArgAccessToken is the access token to be used for the operations
	ArgAccessToken = "access-token"
	// ArgContext is the name of the auth context to use
	ArgContext = "context"
	// ArgActionID is an action id argument.
	ArgActionID = "action-id"
	// ArgActionAfter is an action after argument.
	ArgActionAfter = "after"
	// ArgActionBefore is an action before argument.
	ArgActionBefore = "before"
	// ArgActionResourceType is an action resource type argument.
	ArgActionResourceType = "resource-type"
	// ArgActionRegion is an action region argument.
	ArgActionRegion = "region"
	// ArgActionStatus is an action status argument.
	ArgActionStatus = "status"
	// ArgActionType is an action type argument.
	ArgActionType = "action-type"
	// ArgClusterName is a cluster name argument.
	ArgClusterName = "cluster-name"
	// ArgClusterVersionSlug is a cluster version argument.
	ArgClusterVersionSlug = "version"
	// ArgClusterNodePool are a cluster's node pools arguments.
	ArgClusterNodePool = "node-pool"
	// ArgClusterTag is a cluster's tags arguments.
	ArgClusterTag = "tag"
	// ArgClusterUpdateKubeconfig updates the local kubeconfig.
	ArgClusterUpdateKubeconfig = "update-kubeconfig"
	// ArgNodePoolName is a cluster's node pool name argument.
	ArgNodePoolName = "name"
	// ArgNodePoolCount is a cluster's node pool count argument.
	ArgNodePoolCount = "count"
	// ArgNodePoolNodeIDs is a cluster's node pool nodes argument.
	ArgNodePoolNodeIDs = "node-ids"
	// ArgCommandWait is a wait for a resource to be created argument.
	ArgCommandWait = "wait"
	// ArgDropletID is a droplet id argument.
	ArgDropletID = "droplet-id"
	// ArgDropletIDs is a list of droplet IDs.
	ArgDropletIDs = "droplet-ids"
	// ArgKernelID is a ekrnel id argument.
	ArgKernelID = "kernel-id"
	// ArgImage is an image argument.
	ArgImage = "image"
	// ArgImageID is an image id argument.
	ArgImageID = "image-id"
	// ArgImagePublic is a public image argument.
	ArgImagePublic = "public"
	// ArgImageSlug is an image slug argment.
	ArgImageSlug = "image-slug"
	// ArgIPAddress is an IP address argument.
	ArgIPAddress = "ip-address"
	// ArgDropletName is a droplet name argument.
	ArgDropletName = "droplet-name"
	// ArgResizeDisk is a resize disk argument.
	ArgResizeDisk = "resize-disk"
	// ArgSnapshotName is a snapshot name argument.
	ArgSnapshotName = "snapshot-name"
	// ArgSnapshotDesc is the description for volume snapshot.
	ArgSnapshotDesc = "snapshot-desc"
	// ArgResourceType is the resource type for snapshot.
	ArgResourceType = "resource"
	// ArgBackups is an enable backups argument.
	ArgBackups = "enable-backups"
	// ArgIPv6 is an enable IPv6 argument.
	ArgIPv6 = "enable-ipv6"
	// ArgPrivateNetworking is an enable private networking argument.
	ArgPrivateNetworking = "enable-private-networking"
	// ArgMonitoring is an enable monitoring argument.
	ArgMonitoring = "enable-monitoring"
	// ArgRecordData is a record data argument.
	ArgRecordData = "record-data"
	// ArgRecordID is a record id argument.
	ArgRecordID = "record-id"
	// ArgRecordName is a record name argument.
	ArgRecordName = "record-name"
	// ArgRecordPort is a record port argument.
	ArgRecordPort = "record-port"
	// ArgRecordPriority is a record priority argument.
	ArgRecordPriority = "record-priority"
	// ArgRecordType is a record type argument.
	ArgRecordType = "record-type"
	// ArgRecordTTL is a record ttl argument.
	ArgRecordTTL = "record-ttl"
	// ArgRecordWeight is a record weight argument.
	ArgRecordWeight = "record-weight"
	// ArgRecordFlags is a record flags argument.
	ArgRecordFlags = "record-flags"
	// ArgRecordTag is a record tag argument.
	ArgRecordTag = "record-tag"
	// ArgRegionSlug is a region slug argument.
	ArgRegionSlug = "region"
	// ArgSizeSlug is a size slug argument.
	ArgSizeSlug = "size"
	// ArgsSSHKeyPath is a ssh argument.
	ArgsSSHKeyPath = "ssh-key-path"
	// ArgSSHKeys is a ssh key argument.
	ArgSSHKeys = "ssh-keys"
	// ArgsSSHPort is a ssh argument.
	ArgsSSHPort = "ssh-port"
	// ArgsSSHAgentForwarding is a ssh argument.
	ArgsSSHAgentForwarding = "ssh-agent-forwarding"
	// ArgsSSHPrivateIP is a ssh argument.
	ArgsSSHPrivateIP = "ssh-private-ip"
	// ArgSSHCommand is a ssh argument.
	ArgSSHCommand = "ssh-command"
	// ArgUserData is a user data argument.
	ArgUserData = "user-data"
	// ArgUserDataFile is a user data file location argument.
	ArgUserDataFile = "user-data-file"
	// ArgImageName name is an image name argument.
	ArgImageName = "image-name"
	// ArgKey is a key argument.
	ArgKey = "key"
	// ArgKeyName is a key name argument.
	ArgKeyName = "key-name"
	// ArgKeyPublicKey is a public key argument.
	ArgKeyPublicKey = "public-key"
	// ArgKeyPublicKeyFile is a public key file argument.
	ArgKeyPublicKeyFile = "public-key-file"
	// ArgSSHUser is a SSH user argument.
	ArgSSHUser = "ssh-user"
	// ArgFormat is columns to include in output argment.
	ArgFormat = "format"
	// ArgNoHeader hides the output header.
	ArgNoHeader = "no-header"
	// ArgPollTime is how long before the next poll argument.
	ArgPollTime = "poll-timeout"
	// ArgTagName is a tag name
	ArgTagName = "tag-name"
	// ArgTagNames is a slice of possible tag names
	ArgTagNames = "tag-names"
	//ArgTemplate is template format
	ArgTemplate = "template"
	// ArgVersion is the version of the command to use
	ArgVersion = "version"
	// ArgVerbose enables verbose output
	ArgVerbose = "verbose"

	// ArgOutput is an output type argument.
	ArgOutput = "output"

	// ArgVolumeSize is the size of a volume.
	ArgVolumeSize = "size"
	// ArgVolumeDesc is the description of a volume.
	ArgVolumeDesc = "desc"
	// ArgVolumeRegion is the region of a volume.
	ArgVolumeRegion = "region"
	// ArgVolumeFilesystemType is the filesystem type for a volume.
	ArgVolumeFilesystemType = "fs-type"
	// ArgVolumeFilesystemLabel is the filesystem label for a volume.
	ArgVolumeFilesystemLabel = "fs-label"
	// ArgVolumeList is the IDs of many volumes.
	ArgVolumeList = "volumes"

	// ArgCDNTTL is a cdn ttl argument
	ArgCDNTTL = "ttl"
	// ArgCDNDomain is a cdn custom domain argument
	ArgCDNDomain = "domain"
	// ArgCDNCertificateID is a certificate id to use with a custom domain
	ArgCDNCertificateID = "certificate-id"
	// ArgCDNFiles is a cdn files argument
	ArgCDNFiles = "files"

	// ArgCertificateName is a name of the certificate.
	ArgCertificateName = "name"
	// ArgCertificateDNSNames is a list of DNS names.
	ArgCertificateDNSNames = "dns-names"
	// ArgPrivateKeyPath is a path to a private key for the certificate.
	ArgPrivateKeyPath = "private-key-path"
	// ArgLeafCertificatePath is a path to a certificate leaf.
	ArgLeafCertificatePath = "leaf-certificate-path"
	// ArgCertificateChainPath is a path to a certificate chain.
	ArgCertificateChainPath = "certificate-chain-path"
	// ArgCertificateType is a certificate type.
	ArgCertificateType = "type"

	// ArgLoadBalancerName is a name of the load balancer.
	ArgLoadBalancerName = "name"
	// ArgLoadBalancerAlgorithm is a load balancing algorithm.
	ArgLoadBalancerAlgorithm = "algorithm"
	// ArgRedirectHttpoHttps is a flag that indicates whether HTTP requests to the load balancer on port 80 should be redirected to HTTPS on port 443.
	ArgRedirectHttpToHttps = "redirect-http-to-https"
	// ArgStickySessions is a list of sticky sessions settings for the load balancer.
	ArgStickySessions = "sticky-sessions"
	// ArgHealthCheck is a list of health check settings for the load balancer.
	ArgHealthCheck = "health-check"
	// ArgForwardingRules is a list of forwarding rules for the load balancer.
	ArgForwardingRules = "forwarding-rules"

	// ArgFirewallName is a name of the firewall.
	ArgFirewallName = "name"
	// ArgInboundRules is a list of inbound rules for the firewall.
	ArgInboundRules = "inbound-rules"
	// ArgOutboundRules is a list of outbound rules for the firewall.
	ArgOutboundRules = "outbound-rules"

	// ArgProjectName is the name of a project.
	ArgProjectName = "name"
	// ArgProjectDescription is the description of a project.
	ArgProjectDescription = "description"
	// ArgProjectPurpose is the purpose of a project.
	ArgProjectPurpose = "purpose"
	// ArgProjectEnvironment is the environment of a project. Should be one of 'Development', 'Staging', 'Production'.
	ArgProjectEnvironment = "environment"
	// ArgProjectIsDefault is used to change the default project.
	ArgProjectIsDefault = "is_default"
	// ArgProjectResource is a flag for your resource URNs
	ArgProjectResource = "resource"

	// ArgForce forces confirmation on actions
	ArgForce = "force"
)
<commit_msg>correct typo in comment<commit_after>/*
Copyright 2018 The Doctl Authors All rights reserved.
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 doctl

const (
	// ArgAccessToken is the access token to be used for the operations
	ArgAccessToken = "access-token"
	// ArgContext is the name of the auth context to use
	ArgContext = "context"
	// ArgActionID is an action id argument.
	ArgActionID = "action-id"
	// ArgActionAfter is an action after argument.
	ArgActionAfter = "after"
	// ArgActionBefore is an action before argument.
	ArgActionBefore = "before"
	// ArgActionResourceType is an action resource type argument.
	ArgActionResourceType = "resource-type"
	// ArgActionRegion is an action region argument.
	ArgActionRegion = "region"
	// ArgActionStatus is an action status argument.
	ArgActionStatus = "status"
	// ArgActionType is an action type argument.
	ArgActionType = "action-type"
	// ArgClusterName is a cluster name argument.
	ArgClusterName = "cluster-name"
	// ArgClusterVersionSlug is a cluster version argument.
	ArgClusterVersionSlug = "version"
	// ArgClusterNodePool are a cluster's node pools arguments.
	ArgClusterNodePool = "node-pool"
	// ArgClusterTag is a cluster's tags arguments.
	ArgClusterTag = "tag"
	// ArgClusterUpdateKubeconfig updates the local kubeconfig.
	ArgClusterUpdateKubeconfig = "update-kubeconfig"
	// ArgNodePoolName is a cluster's node pool name argument.
	ArgNodePoolName = "name"
	// ArgNodePoolCount is a cluster's node pool count argument.
	ArgNodePoolCount = "count"
	// ArgNodePoolNodeIDs is a cluster's node pool nodes argument.
	ArgNodePoolNodeIDs = "node-ids"
	// ArgCommandWait is a wait for a resource to be created argument.
	ArgCommandWait = "wait"
	// ArgDropletID is a droplet id argument.
	ArgDropletID = "droplet-id"
	// ArgDropletIDs is a list of droplet IDs.
	ArgDropletIDs = "droplet-ids"
	// ArgKernelID is a ekrnel id argument.
	ArgKernelID = "kernel-id"
	// ArgImage is an image argument.
	ArgImage = "image"
	// ArgImageID is an image id argument.
	ArgImageID = "image-id"
	// ArgImagePublic is a public image argument.
	ArgImagePublic = "public"
	// ArgImageSlug is an image slug argment.
	ArgImageSlug = "image-slug"
	// ArgIPAddress is an IP address argument.
	ArgIPAddress = "ip-address"
	// ArgDropletName is a droplet name argument.
	ArgDropletName = "droplet-name"
	// ArgResizeDisk is a resize disk argument.
	ArgResizeDisk = "resize-disk"
	// ArgSnapshotName is a snapshot name argument.
	ArgSnapshotName = "snapshot-name"
	// ArgSnapshotDesc is the description for volume snapshot.
	ArgSnapshotDesc = "snapshot-desc"
	// ArgResourceType is the resource type for snapshot.
	ArgResourceType = "resource"
	// ArgBackups is an enable backups argument.
	ArgBackups = "enable-backups"
	// ArgIPv6 is an enable IPv6 argument.
	ArgIPv6 = "enable-ipv6"
	// ArgPrivateNetworking is an enable private networking argument.
	ArgPrivateNetworking = "enable-private-networking"
	// ArgMonitoring is an enable monitoring argument.
	ArgMonitoring = "enable-monitoring"
	// ArgRecordData is a record data argument.
	ArgRecordData = "record-data"
	// ArgRecordID is a record id argument.
	ArgRecordID = "record-id"
	// ArgRecordName is a record name argument.
	ArgRecordName = "record-name"
	// ArgRecordPort is a record port argument.
	ArgRecordPort = "record-port"
	// ArgRecordPriority is a record priority argument.
	ArgRecordPriority = "record-priority"
	// ArgRecordType is a record type argument.
	ArgRecordType = "record-type"
	// ArgRecordTTL is a record ttl argument.
	ArgRecordTTL = "record-ttl"
	// ArgRecordWeight is a record weight argument.
	ArgRecordWeight = "record-weight"
	// ArgRecordFlags is a record flags argument.
	ArgRecordFlags = "record-flags"
	// ArgRecordTag is a record tag argument.
	ArgRecordTag = "record-tag"
	// ArgRegionSlug is a region slug argument.
	ArgRegionSlug = "region"
	// ArgSizeSlug is a size slug argument.
	ArgSizeSlug = "size"
	// ArgsSSHKeyPath is a ssh argument.
	ArgsSSHKeyPath = "ssh-key-path"
	// ArgSSHKeys is a ssh key argument.
	ArgSSHKeys = "ssh-keys"
	// ArgsSSHPort is a ssh argument.
	ArgsSSHPort = "ssh-port"
	// ArgsSSHAgentForwarding is a ssh argument.
	ArgsSSHAgentForwarding = "ssh-agent-forwarding"
	// ArgsSSHPrivateIP is a ssh argument.
	ArgsSSHPrivateIP = "ssh-private-ip"
	// ArgSSHCommand is a ssh argument.
	ArgSSHCommand = "ssh-command"
	// ArgUserData is a user data argument.
	ArgUserData = "user-data"
	// ArgUserDataFile is a user data file location argument.
	ArgUserDataFile = "user-data-file"
	// ArgImageName name is an image name argument.
	ArgImageName = "image-name"
	// ArgKey is a key argument.
	ArgKey = "key"
	// ArgKeyName is a key name argument.
	ArgKeyName = "key-name"
	// ArgKeyPublicKey is a public key argument.
	ArgKeyPublicKey = "public-key"
	// ArgKeyPublicKeyFile is a public key file argument.
	ArgKeyPublicKeyFile = "public-key-file"
	// ArgSSHUser is a SSH user argument.
	ArgSSHUser = "ssh-user"
	// ArgFormat is columns to include in output argment.
	ArgFormat = "format"
	// ArgNoHeader hides the output header.
	ArgNoHeader = "no-header"
	// ArgPollTime is how long before the next poll argument.
	ArgPollTime = "poll-timeout"
	// ArgTagName is a tag name
	ArgTagName = "tag-name"
	// ArgTagNames is a slice of possible tag names
	ArgTagNames = "tag-names"
	//ArgTemplate is template format
	ArgTemplate = "template"
	// ArgVersion is the version of the command to use
	ArgVersion = "version"
	// ArgVerbose enables verbose output
	ArgVerbose = "verbose"

	// ArgOutput is an output type argument.
	ArgOutput = "output"

	// ArgVolumeSize is the size of a volume.
	ArgVolumeSize = "size"
	// ArgVolumeDesc is the description of a volume.
	ArgVolumeDesc = "desc"
	// ArgVolumeRegion is the region of a volume.
	ArgVolumeRegion = "region"
	// ArgVolumeFilesystemType is the filesystem type for a volume.
	ArgVolumeFilesystemType = "fs-type"
	// ArgVolumeFilesystemLabel is the filesystem label for a volume.
	ArgVolumeFilesystemLabel = "fs-label"
	// ArgVolumeList is the IDs of many volumes.
	ArgVolumeList = "volumes"

	// ArgCDNTTL is a cdn ttl argument
	ArgCDNTTL = "ttl"
	// ArgCDNDomain is a cdn custom domain argument
	ArgCDNDomain = "domain"
	// ArgCDNCertificateID is a certificate id to use with a custom domain
	ArgCDNCertificateID = "certificate-id"
	// ArgCDNFiles is a cdn files argument
	ArgCDNFiles = "files"

	// ArgCertificateName is a name of the certificate.
	ArgCertificateName = "name"
	// ArgCertificateDNSNames is a list of DNS names.
	ArgCertificateDNSNames = "dns-names"
	// ArgPrivateKeyPath is a path to a private key for the certificate.
	ArgPrivateKeyPath = "private-key-path"
	// ArgLeafCertificatePath is a path to a certificate leaf.
	ArgLeafCertificatePath = "leaf-certificate-path"
	// ArgCertificateChainPath is a path to a certificate chain.
	ArgCertificateChainPath = "certificate-chain-path"
	// ArgCertificateType is a certificate type.
	ArgCertificateType = "type"

	// ArgLoadBalancerName is a name of the load balancer.
	ArgLoadBalancerName = "name"
	// ArgLoadBalancerAlgorithm is a load balancing algorithm.
	ArgLoadBalancerAlgorithm = "algorithm"
	// ArgRedirectHttpToHttps is a flag that indicates whether HTTP requests to the load balancer on port 80 should be redirected to HTTPS on port 443.
	ArgRedirectHttpToHttps = "redirect-http-to-https"
	// ArgStickySessions is a list of sticky sessions settings for the load balancer.
	ArgStickySessions = "sticky-sessions"
	// ArgHealthCheck is a list of health check settings for the load balancer.
	ArgHealthCheck = "health-check"
	// ArgForwardingRules is a list of forwarding rules for the load balancer.
	ArgForwardingRules = "forwarding-rules"

	// ArgFirewallName is a name of the firewall.
	ArgFirewallName = "name"
	// ArgInboundRules is a list of inbound rules for the firewall.
	ArgInboundRules = "inbound-rules"
	// ArgOutboundRules is a list of outbound rules for the firewall.
	ArgOutboundRules = "outbound-rules"

	// ArgProjectName is the name of a project.
	ArgProjectName = "name"
	// ArgProjectDescription is the description of a project.
	ArgProjectDescription = "description"
	// ArgProjectPurpose is the purpose of a project.
	ArgProjectPurpose = "purpose"
	// ArgProjectEnvironment is the environment of a project. Should be one of 'Development', 'Staging', 'Production'.
	ArgProjectEnvironment = "environment"
	// ArgProjectIsDefault is used to change the default project.
	ArgProjectIsDefault = "is_default"
	// ArgProjectResource is a flag for your resource URNs
	ArgProjectResource = "resource"

	// ArgForce forces confirmation on actions
	ArgForce = "force"
)
<|endoftext|>


<commit_before>package main

import(
  "fmt"
  "io"
  "io/ioutil"
  "crypto/sha1"
  "os"
  "os/exec"
  "path/filepath"
  "bytes"
  "runtime"
  "strings"
  "github.com/kr/s3/s3util"
)

const VERSION = "0.1.0"

func fileExists(path string) bool {
  _, err := os.Stat(path)
  return err == nil
}

func open(s string) (io.ReadCloser, error) {
  if isURL(s) {
    return s3util.Open(s, nil)
  }
  return os.Open(s)
}

func create(s string) (io.WriteCloser, error) {
  if isURL(s) {
    return s3util.Create(s, nil, nil)
  }
  return os.Create(s)
}

func isURL(s string) bool {
  return strings.HasPrefix(s, "http://") || strings.HasPrefix(s, "https://")
}

func s3url(filename string) string {
  format := "https://s3.amazonaws.com/%s/%s"
  url := fmt.Sprintf(format, os.Getenv("S3_BUCKET"), filename)

  return url
}

func sh(command string) (string, error) {
  var output bytes.Buffer

  cmd := exec.Command("bash", "-c", command)

  cmd.Stdout = &output
  cmd.Stderr = &output

  err := cmd.Run()
  return output.String(), err
}

func calculateChecksum(buffer string) string {
  h := sha1.New()
  io.WriteString(h, buffer)
  return fmt.Sprintf("%x", h.Sum(nil))
}

func transferArchive(file string, url string) {
  s3util.DefaultConfig.AccessKey = os.Getenv("S3_ACCESS_KEY")
  s3util.DefaultConfig.SecretKey = os.Getenv("S3_SECRET_KEY")

  r, err := open(file)
  if err != nil {
    fmt.Fprintln(os.Stderr, err)
    os.Exit(1)
  }

  w, err := create(url)
  if err != nil {
    fmt.Fprintln(os.Stderr, err)
    os.Exit(1)
  }

  _, err = io.Copy(w, r)
  if err != nil {
    fmt.Fprintln(os.Stderr, err)
    os.Exit(1)
  }

  err = w.Close()
  if err != nil {
    fmt.Fprintln(os.Stderr, err)
    os.Exit(1)
  }
}

func extractArchive(filename string, path string) bool {
  cmd_mkdir   := fmt.Sprintf("cd %s && mkdir .bundle", path)
  cmd_move    := fmt.Sprintf("mv %s %s/.bundle/bundle_cache.tar.gz", filename, path)
  cmd_extract := fmt.Sprintf("cd %s/.bundle && tar -xzf ./bundle_cache.tar.gz", path)
  cmd_remove  := fmt.Sprintf("rm %s/.bundle/bundle_cache.tar.gz", path)

  if _, err := sh(cmd_mkdir) ; err != nil {
    fmt.Println("Bundle directory '.bundle' already exists")
    return false
  }

  if _, err := sh(cmd_move) ; err != nil {
    fmt.Println("Unable to move file")
    return false
  }

  if out, err := sh(cmd_extract) ; err != nil {
    fmt.Println("Unable to extract:", out)
    return false
  }

  if _, err := sh(cmd_remove) ; err != nil {
    fmt.Println("Unable to remove archive")
    return false
  }

  return true
}

func envDefined(name string) bool {
  result := os.Getenv(name)
  return len(result) > 0
}

func checkS3Credentials() {
  required := [3]string { "S3_ACCESS_KEY", "S3_SECRET_KEY", "S3_BUCKET" }

  for _, v := range required {
    if !envDefined(v) {
      fmt.Printf("Please define %s environment variable\n", v)
      os.Exit(2)
    }
  }
}

func printUsage() {
  fmt.Println("Usage: bundle_cache [download|upload]")
  os.Exit(2)
}

func upload(bundle_path string, archive_path string, archive_url string) {
  if !fileExists(bundle_path) {
    fmt.Println("Bundle path does not exist")
    os.Exit(1)
  }

  cmd := fmt.Sprintf("cd %s && tar -czf %s .", bundle_path, archive_path)

  fmt.Println("Archiving...")
  if out, err := sh(cmd); err != nil {
    fmt.Println("Failed to make archive:", out)
    os.Exit(1)
  }

  fmt.Println("Archived bundle at", archive_path)
  transferArchive(archive_path, archive_url)

  os.Exit(0)
}

func download(path string, bundle_path string, archive_path string, archive_url string) {
  if fileExists(bundle_path) {
    fmt.Println("Bundle path already exists")
    os.Exit(1)
  }

  fmt.Println("Downloading", archive_url)
  transferArchive(archive_url, archive_path)

  fmt.Println("Extracting...")
  extractArchive(archive_path, path)

  os.Exit(0)
}

func main() {
  args := os.Args[1:]

  if len(args) != 1 {
    printUsage()
  }

  action := args[0]

  /* Check if S3 credentials are set */
  checkS3Credentials()

  /* Get all path information */
  path, _       := os.Getwd()
  name          := filepath.Base(path)
  bundle_path   := fmt.Sprintf("%s/.bundle", path)
  lockfile_path := fmt.Sprintf("%s/Gemfile.lock", path)

  /* Check if lockfile exists */
  if !fileExists(lockfile_path) {
    fmt.Println("Gemfile.lock does not exist")
    os.Exit(1)
  }

  /* Read contents of lockfile */
  lockfile, err := ioutil.ReadFile(lockfile_path)
  if err != nil {
    fmt.Println("Unable to read Gemfile.lock")
    os.Exit(1)
  }

  /* Calculate SHA1 checksum for Gemfile.lock */
  checksum := calculateChecksum(string(lockfile))

  /* Make archive save filename */
  archive_name := fmt.Sprintf("%s_%s_%s.tar.gz", name, checksum, runtime.GOARCH)
  archive_path := fmt.Sprintf("/tmp/%s", archive_name)
  archive_url  := fmt.Sprintf("https://s3.amazonaws.com/bundle_cache/%s", archive_name)

  /* Check if archive already exists */
  if fileExists(archive_path) {
    if os.Remove(archive_path) != nil {
      fmt.Println("Failed to remove existing archive")
      os.Exit(1)
    }
  }

  if action == "upload" || action == "up" {
    upload(bundle_path, archive_path, archive_url)
  }

  if action == "download" || action == "down" {
    download(path, bundle_path, archive_path, archive_url)
  }

  printUsage()
}
<commit_msg>Use s3 bucket name defined in S3_BUCKET<commit_after>package main

import(
  "fmt"
  "io"
  "io/ioutil"
  "crypto/sha1"
  "os"
  "os/exec"
  "path/filepath"
  "bytes"
  "runtime"
  "strings"
  "github.com/kr/s3/s3util"
)

const VERSION = "0.1.0"

func fileExists(path string) bool {
  _, err := os.Stat(path)
  return err == nil
}

func open(s string) (io.ReadCloser, error) {
  if isURL(s) {
    return s3util.Open(s, nil)
  }
  return os.Open(s)
}

func create(s string) (io.WriteCloser, error) {
  if isURL(s) {
    return s3util.Create(s, nil, nil)
  }
  return os.Create(s)
}

func isURL(s string) bool {
  return strings.HasPrefix(s, "http://") || strings.HasPrefix(s, "https://")
}

func s3url(filename string) string {
  format := "https://s3.amazonaws.com/%s/%s"
  url := fmt.Sprintf(format, os.Getenv("S3_BUCKET"), filename)

  return url
}

func sh(command string) (string, error) {
  var output bytes.Buffer

  cmd := exec.Command("bash", "-c", command)

  cmd.Stdout = &output
  cmd.Stderr = &output

  err := cmd.Run()
  return output.String(), err
}

func calculateChecksum(buffer string) string {
  h := sha1.New()
  io.WriteString(h, buffer)
  return fmt.Sprintf("%x", h.Sum(nil))
}

func transferArchive(file string, url string) {
  s3util.DefaultConfig.AccessKey = os.Getenv("S3_ACCESS_KEY")
  s3util.DefaultConfig.SecretKey = os.Getenv("S3_SECRET_KEY")

  r, err := open(file)
  if err != nil {
    fmt.Fprintln(os.Stderr, err)
    os.Exit(1)
  }

  w, err := create(url)
  if err != nil {
    fmt.Fprintln(os.Stderr, err)
    os.Exit(1)
  }

  _, err = io.Copy(w, r)
  if err != nil {
    fmt.Fprintln(os.Stderr, err)
    os.Exit(1)
  }

  err = w.Close()
  if err != nil {
    fmt.Fprintln(os.Stderr, err)
    os.Exit(1)
  }
}

func extractArchive(filename string, path string) bool {
  cmd_mkdir   := fmt.Sprintf("cd %s && mkdir .bundle", path)
  cmd_move    := fmt.Sprintf("mv %s %s/.bundle/bundle_cache.tar.gz", filename, path)
  cmd_extract := fmt.Sprintf("cd %s/.bundle && tar -xzf ./bundle_cache.tar.gz", path)
  cmd_remove  := fmt.Sprintf("rm %s/.bundle/bundle_cache.tar.gz", path)

  if _, err := sh(cmd_mkdir) ; err != nil {
    fmt.Println("Bundle directory '.bundle' already exists")
    return false
  }

  if _, err := sh(cmd_move) ; err != nil {
    fmt.Println("Unable to move file")
    return false
  }

  if out, err := sh(cmd_extract) ; err != nil {
    fmt.Println("Unable to extract:", out)
    return false
  }

  if _, err := sh(cmd_remove) ; err != nil {
    fmt.Println("Unable to remove archive")
    return false
  }

  return true
}

func envDefined(name string) bool {
  result := os.Getenv(name)
  return len(result) > 0
}

func checkS3Credentials() {
  required := [3]string { "S3_ACCESS_KEY", "S3_SECRET_KEY", "S3_BUCKET" }

  for _, v := range required {
    if !envDefined(v) {
      fmt.Printf("Please define %s environment variable\n", v)
      os.Exit(2)
    }
  }
}

func printUsage() {
  fmt.Println("Usage: bundle_cache [download|upload]")
  os.Exit(2)
}

func upload(bundle_path string, archive_path string, archive_url string) {
  if !fileExists(bundle_path) {
    fmt.Println("Bundle path does not exist")
    os.Exit(1)
  }

  cmd := fmt.Sprintf("cd %s && tar -czf %s .", bundle_path, archive_path)

  fmt.Println("Archiving...")
  if out, err := sh(cmd); err != nil {
    fmt.Println("Failed to make archive:", out)
    os.Exit(1)
  }

  fmt.Println("Archived bundle at", archive_path)
  transferArchive(archive_path, archive_url)

  os.Exit(0)
}

func download(path string, bundle_path string, archive_path string, archive_url string) {
  if fileExists(bundle_path) {
    fmt.Println("Bundle path already exists")
    os.Exit(1)
  }

  fmt.Println("Downloading", archive_url)
  transferArchive(archive_url, archive_path)

  fmt.Println("Extracting...")
  extractArchive(archive_path, path)

  os.Exit(0)
}

func main() {
  args := os.Args[1:]

  if len(args) != 1 {
    printUsage()
  }

  action := args[0]

  /* Check if S3 credentials are set */
  checkS3Credentials()

  /* Get all path information */
  path, _       := os.Getwd()
  name          := filepath.Base(path)
  bundle_path   := fmt.Sprintf("%s/.bundle", path)
  lockfile_path := fmt.Sprintf("%s/Gemfile.lock", path)

  /* Check if lockfile exists */
  if !fileExists(lockfile_path) {
    fmt.Println("Gemfile.lock does not exist")
    os.Exit(1)
  }

  /* Read contents of lockfile */
  lockfile, err := ioutil.ReadFile(lockfile_path)
  if err != nil {
    fmt.Println("Unable to read Gemfile.lock")
    os.Exit(1)
  }

  /* Calculate SHA1 checksum for Gemfile.lock */
  checksum := calculateChecksum(string(lockfile))

  /* Make archive save filename */
  archive_name := fmt.Sprintf("%s_%s_%s.tar.gz", name, checksum, runtime.GOARCH)
  archive_path := fmt.Sprintf("/tmp/%s", archive_name)
  archive_url  := s3url(archive_name)

  /* Check if archive already exists */
  if fileExists(archive_path) {
    if os.Remove(archive_path) != nil {
      fmt.Println("Failed to remove existing archive")
      os.Exit(1)
    }
  }

  if action == "upload" || action == "up" {
    upload(bundle_path, archive_path, archive_url)
  }

  if action == "download" || action == "down" {
    download(path, bundle_path, archive_path, archive_url)
  }

  printUsage()
}
<|endoftext|>


<commit_before>// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
//	http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file 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 handlers deals with the agent introspection api.
package handlers

import (
	"context"
	"encoding/json"
	"net/http"
	"strconv"
	"time"

	"github.com/aws/amazon-ecs-agent/agent/config"
	"github.com/aws/amazon-ecs-agent/agent/engine"
	handlersutils "github.com/aws/amazon-ecs-agent/agent/handlers/utils"
	v1 "github.com/aws/amazon-ecs-agent/agent/handlers/v1"
	"github.com/aws/amazon-ecs-agent/agent/utils/retry"
	"github.com/cihub/seelog"
)

type rootResponse struct {
	AvailableCommands []string
}

func introspectionServerSetup(containerInstanceArn *string, taskEngine handlersutils.DockerStateResolver, cfg *config.Config) *http.Server {
	paths := []string{v1.AgentMetadataPath, v1.TaskContainerMetadataPath, v1.LicensePath}
	availableCommands := &rootResponse{paths}
	// Autogenerated list of the above serverFunctions paths
	availableCommandResponse, err := json.Marshal(&availableCommands)
	if err != nil {
		seelog.Errorf("Error marshaling JSON in introspection server setup: %s", err)
	}

	defaultHandler := func(w http.ResponseWriter, r *http.Request) {
		w.Write(availableCommandResponse)
	}

	serverMux := http.NewServeMux()
	serverMux.HandleFunc("/", defaultHandler)

	v1HandlersSetup(serverMux, containerInstanceArn, taskEngine, cfg)

	// Log all requests and then pass through to serverMux
	loggingServeMux := http.NewServeMux()
	loggingServeMux.Handle("/", LoggingHandler{serverMux})

	server := &http.Server{
		Addr:         ":" + strconv.Itoa(config.AgentIntrospectionPort),
		Handler:      loggingServeMux,
		ReadTimeout:  readTimeout,
		WriteTimeout: writeTimeout,
	}

	return server
}

// v1HandlersSetup adds all handlers except CredentialsHandler in v1 package to the server mux.
func v1HandlersSetup(serverMux *http.ServeMux,
	containerInstanceArn *string,
	taskEngine handlersutils.DockerStateResolver,
	cfg *config.Config) {
	serverMux.HandleFunc(v1.AgentMetadataPath, v1.AgentMetadataHandler(containerInstanceArn, cfg))
	serverMux.HandleFunc(v1.TaskContainerMetadataPath, v1.TaskContainerMetadataHandler(taskEngine))
	serverMux.HandleFunc(v1.LicensePath, v1.LicenseHandler)
}

// ServeIntrospectionHTTPEndpoint serves information about this agent/containerInstance and tasks
// running on it. "V1" here indicates the hostname version of this server instead
// of the handler versions, i.e. "V1" server can include "V1" and "V2" handlers.
func ServeIntrospectionHTTPEndpoint(ctx context.Context, containerInstanceArn *string, taskEngine engine.TaskEngine, cfg *config.Config) {
	// Is this the right level to type assert, assuming we'd abstract multiple taskengines here?
	// Revisit if we ever add another type..
	dockerTaskEngine := taskEngine.(*engine.DockerTaskEngine)

	server := introspectionServerSetup(containerInstanceArn, dockerTaskEngine, cfg)

	go func() {
		<-ctx.Done()
		if err := server.Shutdown(context.Background()); err != nil {
			// Error from closing listeners, or context timeout:
			seelog.Infof("HTTP server Shutdown: %v", err)
		}
	}()

	for {
		retry.RetryWithBackoff(retry.NewExponentialBackoff(time.Second, time.Minute, 0.2, 2), func() error {
			if err := server.ListenAndServe(); err != http.ErrServerClosed {
				seelog.Errorf("Error running introspection endpoint: %v", err)
				return err
			}
			// server was cleanly closed via context
			return nil
		})
	}
}
<commit_msg>bind introspection to localhost<commit_after>// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
//	http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file 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 handlers deals with the agent introspection api.
package handlers

import (
	"context"
	"encoding/json"
	"net/http"
	"strconv"
	"time"

	"github.com/aws/amazon-ecs-agent/agent/config"
	"github.com/aws/amazon-ecs-agent/agent/engine"
	handlersutils "github.com/aws/amazon-ecs-agent/agent/handlers/utils"
	v1 "github.com/aws/amazon-ecs-agent/agent/handlers/v1"
	"github.com/aws/amazon-ecs-agent/agent/utils/retry"
	"github.com/cihub/seelog"
)

type rootResponse struct {
	AvailableCommands []string
}

func introspectionServerSetup(containerInstanceArn *string, taskEngine handlersutils.DockerStateResolver, cfg *config.Config) *http.Server {
	paths := []string{v1.AgentMetadataPath, v1.TaskContainerMetadataPath, v1.LicensePath}
	availableCommands := &rootResponse{paths}
	// Autogenerated list of the above serverFunctions paths
	availableCommandResponse, err := json.Marshal(&availableCommands)
	if err != nil {
		seelog.Errorf("Error marshaling JSON in introspection server setup: %s", err)
	}

	defaultHandler := func(w http.ResponseWriter, r *http.Request) {
		w.Write(availableCommandResponse)
	}

	serverMux := http.NewServeMux()
	serverMux.HandleFunc("/", defaultHandler)

	v1HandlersSetup(serverMux, containerInstanceArn, taskEngine, cfg)

	// Log all requests and then pass through to serverMux
	loggingServeMux := http.NewServeMux()
	loggingServeMux.Handle("/", LoggingHandler{serverMux})

	server := &http.Server{
		Addr:         "127.0.0.1:" + strconv.Itoa(config.AgentIntrospectionPort),
		Handler:      loggingServeMux,
		ReadTimeout:  readTimeout,
		WriteTimeout: writeTimeout,
	}

	return server
}

// v1HandlersSetup adds all handlers except CredentialsHandler in v1 package to the server mux.
func v1HandlersSetup(serverMux *http.ServeMux,
	containerInstanceArn *string,
	taskEngine handlersutils.DockerStateResolver,
	cfg *config.Config) {
	serverMux.HandleFunc(v1.AgentMetadataPath, v1.AgentMetadataHandler(containerInstanceArn, cfg))
	serverMux.HandleFunc(v1.TaskContainerMetadataPath, v1.TaskContainerMetadataHandler(taskEngine))
	serverMux.HandleFunc(v1.LicensePath, v1.LicenseHandler)
}

// ServeIntrospectionHTTPEndpoint serves information about this agent/containerInstance and tasks
// running on it. "V1" here indicates the hostname version of this server instead
// of the handler versions, i.e. "V1" server can include "V1" and "V2" handlers.
func ServeIntrospectionHTTPEndpoint(ctx context.Context, containerInstanceArn *string, taskEngine engine.TaskEngine, cfg *config.Config) {
	// Is this the right level to type assert, assuming we'd abstract multiple taskengines here?
	// Revisit if we ever add another type..
	dockerTaskEngine := taskEngine.(*engine.DockerTaskEngine)

	server := introspectionServerSetup(containerInstanceArn, dockerTaskEngine, cfg)

	go func() {
		<-ctx.Done()
		if err := server.Shutdown(context.Background()); err != nil {
			// Error from closing listeners, or context timeout:
			seelog.Infof("HTTP server Shutdown: %v", err)
		}
	}()

	for {
		retry.RetryWithBackoff(retry.NewExponentialBackoff(time.Second, time.Minute, 0.2, 2), func() error {
			if err := server.ListenAndServe(); err != http.ErrServerClosed {
				seelog.Errorf("Error running introspection endpoint: %v", err)
				return err
			}
			// server was cleanly closed via context
			return nil
		})
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2021 Tigera, Inc. All rights reserved.
//
// 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 utils

import (
	"bufio"
	"bytes"
	"context"
	"fmt"
	"os"
	"os/exec"
	"strings"
	"syscall"

	"github.com/kelseyhightower/envconfig"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	log "github.com/sirupsen/logrus"

	"github.com/projectcalico/libcalico-go/lib/apiconfig"
	client "github.com/projectcalico/libcalico-go/lib/clientv3"
	"github.com/projectcalico/libcalico-go/lib/options"
	"github.com/projectcalico/libcalico-go/lib/selector"

	"github.com/projectcalico/felix/calc"
	"github.com/projectcalico/felix/ipsets"
	"github.com/projectcalico/felix/rules"
)

type EnvConfig struct {
	FelixImage   string `default:"calico/felix:latest"`
	EtcdImage    string `default:"quay.io/coreos/etcd"`
	K8sImage     string `default:"gcr.io/google_containers/hyperkube-amd64:v1.17.4"`
	TyphaImage   string `default:"calico/typha:latest"` // Note: this is overridden in the Makefile!
	BusyboxImage string `default:"busybox:latest"`
}

var Config EnvConfig

func init() {
	err := envconfig.Process("fv", &Config)
	if err != nil {
		panic(err)
	}
	log.WithField("config", Config).Info("Loaded config")
}

var Ctx = context.Background()

var NoOptions = options.SetOptions{}

func Run(command string, args ...string) {
	_ = run(nil, true, command, args...)
}

func RunWithInput(input []byte, command string, args ...string) {
	_ = run(input, true, command, args...)
}

func RunMayFail(command string, args ...string) error {
	return run(nil, false, command, args...)
}

var currentTestOutput = []string{}

var LastRunOutput string

func run(input []byte, checkNoError bool, command string, args ...string) error {
	cmd := Command(command, args...)
	if input != nil {
		cmd.Stdin = bytes.NewReader(input)
	}
	outputBytes, err := cmd.CombinedOutput()
	currentTestOutput = append(currentTestOutput, fmt.Sprintf("Command: %v %v\n", command, args))
	currentTestOutput = append(currentTestOutput, string(outputBytes))
	LastRunOutput = string(outputBytes)
	if err != nil {
		log.WithFields(log.Fields{
			"command": command,
			"args":    args,
			"output":  string(outputBytes)}).WithError(err).Warning("Command failed")
	}
	if checkNoError {
		Expect(err).NotTo(HaveOccurred(), fmt.Sprintf("Command failed\nCommand: %v args: %v\nOutput:\n\n%v",
			command, args, string(outputBytes)))
	}
	if err != nil {
		return fmt.Errorf("Command failed\nCommand: %v args: %v\nOutput:\n\n%v\n\nOrig error: %w",
			command, args, string(outputBytes), err)
	}
	return nil
}

func AddToTestOutput(args ...string) {
	currentTestOutput = append(currentTestOutput, args...)
}

var _ = BeforeEach(func() {
	currentTestOutput = []string{}
})

var _ = AfterEach(func() {
	if CurrentGinkgoTestDescription().Failed {
		os.Stdout.WriteString(fmt.Sprintf("\n===== begin output from failed test %s =====\n",
			CurrentGinkgoTestDescription().FullTestText))
		for _, output := range currentTestOutput {
			os.Stdout.WriteString(output)
		}
		os.Stdout.WriteString("===== end output from failed test =====\n\n")
	}
})

func GetCommandOutput(command string, args ...string) (string, error) {
	cmd := Command(command, args...)
	log.Infof("Running '%s %s'", cmd.Path, strings.Join(cmd.Args, " "))
	output, err := cmd.CombinedOutput()
	return string(output), err
}

func RunCommand(command string, args ...string) error {
	output, err := GetCommandOutput(command, args...)
	log.Infof("output: %v", output)
	return err
}

func Command(name string, args ...string) *exec.Cmd {
	log.WithFields(log.Fields{
		"command":     name,
		"commandArgs": args,
	}).Info("Creating Command.")

	return exec.Command(name, args...)
}

func LogOutput(cmd *exec.Cmd, name string) error {
	outPipe, err := cmd.StdoutPipe()
	if err != nil {
		return fmt.Errorf("Getting StdoutPipe failed for %s: %v", name, err)
	}
	errPipe, err := cmd.StderrPipe()
	if err != nil {
		return fmt.Errorf("Getting StderrPipe failed for %s: %v", name, err)
	}
	stdoutReader := bufio.NewReader(outPipe)
	stderrReader := bufio.NewReader(errPipe)
	go func() {
		for {
			line, err := stdoutReader.ReadString('\n')
			if err != nil {
				log.WithError(err).Infof("End of %s stdout", name)
				return
			}
			log.Infof("%s stdout: %s", name, strings.TrimSpace(string(line)))
		}
	}()
	go func() {
		for {
			line, err := stderrReader.ReadString('\n')
			if err != nil {
				log.WithError(err).Infof("End of %s stderr", name)
				return
			}
			log.Infof("%s stderr: %s", name, strings.TrimSpace(string(line)))
		}
	}()
	return nil
}

func GetEtcdClient(etcdIP string) client.Interface {
	client, err := client.New(apiconfig.CalicoAPIConfig{
		Spec: apiconfig.CalicoAPIConfigSpec{
			DatastoreType: apiconfig.EtcdV3,
			EtcdConfig: apiconfig.EtcdConfig{
				EtcdEndpoints: "http://" + etcdIP + ":2379",
			},
		},
	})
	Expect(err).NotTo(HaveOccurred())
	return client
}

func IPSetIDForSelector(rawSelector string) string {
	sel, err := selector.Parse(rawSelector)
	Expect(err).ToNot(HaveOccurred())

	ipSetData := calc.IPSetData{
		Selector: sel,
	}
	setID := ipSetData.UniqueID()
	return setID
}

func IPSetNameForSelector(ipVersion int, rawSelector string) string {
	setID := IPSetIDForSelector(rawSelector)
	var ipFamily ipsets.IPFamily
	if ipVersion == 4 {
		ipFamily = ipsets.IPFamilyV4
	} else {
		ipFamily = ipsets.IPFamilyV6
	}
	ipVerConf := ipsets.NewIPVersionConfig(
		ipFamily,
		rules.IPSetNamePrefix,
		nil,
		nil,
	)

	return ipVerConf.NameForMainIPSet(setID)
}

// HasSyscallConn represents objects that can return a syscall.RawConn
type HasSyscallConn interface {
	SyscallConn() (syscall.RawConn, error)
}

// ConnMTU returns the MTU of the connection for _connected_ connections. That
// excludes unconnected udp which requires different approach for each peer.
func ConnMTU(hsc HasSyscallConn) (int, error) {
	c, err := hsc.SyscallConn()
	if err != nil {
		return 0, err
	}

	mtu := 0
	var sysErr error
	err = c.Control(func(fd uintptr) {
		mtu, sysErr = syscall.GetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_MTU)
	})

	if err != nil {
		return 0, err
	}

	if sysErr != nil {
		return 0, sysErr
	}

	return mtu, nil
}
<commit_msg>FV: Add utility for updating FelixConfiguration<commit_after>// Copyright (c) 2017-2021 Tigera, Inc. All rights reserved.
//
// 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 utils

import (
	"bufio"
	"bytes"
	"context"
	"fmt"
	"os"
	"os/exec"
	"strings"
	"syscall"
	"time"

	"github.com/kelseyhightower/envconfig"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	log "github.com/sirupsen/logrus"

	"github.com/projectcalico/libcalico-go/lib/apiconfig"
	api "github.com/projectcalico/libcalico-go/lib/apis/v3"
	client "github.com/projectcalico/libcalico-go/lib/clientv3"
	cerrors "github.com/projectcalico/libcalico-go/lib/errors"
	"github.com/projectcalico/libcalico-go/lib/options"
	"github.com/projectcalico/libcalico-go/lib/selector"

	"github.com/projectcalico/felix/calc"
	"github.com/projectcalico/felix/ipsets"
	"github.com/projectcalico/felix/rules"
)

type EnvConfig struct {
	FelixImage   string `default:"calico/felix:latest"`
	EtcdImage    string `default:"quay.io/coreos/etcd"`
	K8sImage     string `default:"gcr.io/google_containers/hyperkube-amd64:v1.17.4"`
	TyphaImage   string `default:"calico/typha:latest"` // Note: this is overridden in the Makefile!
	BusyboxImage string `default:"busybox:latest"`
}

var Config EnvConfig

func init() {
	err := envconfig.Process("fv", &Config)
	if err != nil {
		panic(err)
	}
	log.WithField("config", Config).Info("Loaded config")
}

var Ctx = context.Background()

var NoOptions = options.SetOptions{}

func Run(command string, args ...string) {
	_ = run(nil, true, command, args...)
}

func RunWithInput(input []byte, command string, args ...string) {
	_ = run(input, true, command, args...)
}

func RunMayFail(command string, args ...string) error {
	return run(nil, false, command, args...)
}

var currentTestOutput = []string{}

var LastRunOutput string

func run(input []byte, checkNoError bool, command string, args ...string) error {
	cmd := Command(command, args...)
	if input != nil {
		cmd.Stdin = bytes.NewReader(input)
	}
	outputBytes, err := cmd.CombinedOutput()
	currentTestOutput = append(currentTestOutput, fmt.Sprintf("Command: %v %v\n", command, args))
	currentTestOutput = append(currentTestOutput, string(outputBytes))
	LastRunOutput = string(outputBytes)
	if err != nil {
		log.WithFields(log.Fields{
			"command": command,
			"args":    args,
			"output":  string(outputBytes)}).WithError(err).Warning("Command failed")
	}
	if checkNoError {
		Expect(err).NotTo(HaveOccurred(), fmt.Sprintf("Command failed\nCommand: %v args: %v\nOutput:\n\n%v",
			command, args, string(outputBytes)))
	}
	if err != nil {
		return fmt.Errorf("Command failed\nCommand: %v args: %v\nOutput:\n\n%v\n\nOrig error: %w",
			command, args, string(outputBytes), err)
	}
	return nil
}

func AddToTestOutput(args ...string) {
	currentTestOutput = append(currentTestOutput, args...)
}

var _ = BeforeEach(func() {
	currentTestOutput = []string{}
})

var _ = AfterEach(func() {
	if CurrentGinkgoTestDescription().Failed {
		os.Stdout.WriteString(fmt.Sprintf("\n===== begin output from failed test %s =====\n",
			CurrentGinkgoTestDescription().FullTestText))
		for _, output := range currentTestOutput {
			os.Stdout.WriteString(output)
		}
		os.Stdout.WriteString("===== end output from failed test =====\n\n")
	}
})

func GetCommandOutput(command string, args ...string) (string, error) {
	cmd := Command(command, args...)
	log.Infof("Running '%s %s'", cmd.Path, strings.Join(cmd.Args, " "))
	output, err := cmd.CombinedOutput()
	return string(output), err
}

func RunCommand(command string, args ...string) error {
	output, err := GetCommandOutput(command, args...)
	log.Infof("output: %v", output)
	return err
}

func Command(name string, args ...string) *exec.Cmd {
	log.WithFields(log.Fields{
		"command":     name,
		"commandArgs": args,
	}).Info("Creating Command.")

	return exec.Command(name, args...)
}

func LogOutput(cmd *exec.Cmd, name string) error {
	outPipe, err := cmd.StdoutPipe()
	if err != nil {
		return fmt.Errorf("Getting StdoutPipe failed for %s: %v", name, err)
	}
	errPipe, err := cmd.StderrPipe()
	if err != nil {
		return fmt.Errorf("Getting StderrPipe failed for %s: %v", name, err)
	}
	stdoutReader := bufio.NewReader(outPipe)
	stderrReader := bufio.NewReader(errPipe)
	go func() {
		for {
			line, err := stdoutReader.ReadString('\n')
			if err != nil {
				log.WithError(err).Infof("End of %s stdout", name)
				return
			}
			log.Infof("%s stdout: %s", name, strings.TrimSpace(string(line)))
		}
	}()
	go func() {
		for {
			line, err := stderrReader.ReadString('\n')
			if err != nil {
				log.WithError(err).Infof("End of %s stderr", name)
				return
			}
			log.Infof("%s stderr: %s", name, strings.TrimSpace(string(line)))
		}
	}()
	return nil
}

func GetEtcdClient(etcdIP string) client.Interface {
	client, err := client.New(apiconfig.CalicoAPIConfig{
		Spec: apiconfig.CalicoAPIConfigSpec{
			DatastoreType: apiconfig.EtcdV3,
			EtcdConfig: apiconfig.EtcdConfig{
				EtcdEndpoints: "http://" + etcdIP + ":2379",
			},
		},
	})
	Expect(err).NotTo(HaveOccurred())
	return client
}

func IPSetIDForSelector(rawSelector string) string {
	sel, err := selector.Parse(rawSelector)
	Expect(err).ToNot(HaveOccurred())

	ipSetData := calc.IPSetData{
		Selector: sel,
	}
	setID := ipSetData.UniqueID()
	return setID
}

func IPSetNameForSelector(ipVersion int, rawSelector string) string {
	setID := IPSetIDForSelector(rawSelector)
	var ipFamily ipsets.IPFamily
	if ipVersion == 4 {
		ipFamily = ipsets.IPFamilyV4
	} else {
		ipFamily = ipsets.IPFamilyV6
	}
	ipVerConf := ipsets.NewIPVersionConfig(
		ipFamily,
		rules.IPSetNamePrefix,
		nil,
		nil,
	)

	return ipVerConf.NameForMainIPSet(setID)
}

// HasSyscallConn represents objects that can return a syscall.RawConn
type HasSyscallConn interface {
	SyscallConn() (syscall.RawConn, error)
}

// ConnMTU returns the MTU of the connection for _connected_ connections. That
// excludes unconnected udp which requires different approach for each peer.
func ConnMTU(hsc HasSyscallConn) (int, error) {
	c, err := hsc.SyscallConn()
	if err != nil {
		return 0, err
	}

	mtu := 0
	var sysErr error
	err = c.Control(func(fd uintptr) {
		mtu, sysErr = syscall.GetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_MTU)
	})

	if err != nil {
		return 0, err
	}

	if sysErr != nil {
		return 0, sysErr
	}

	return mtu, nil
}

func UpdateFelixConfig(client client.Interface, deltaFn func(*api.FelixConfiguration)) {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	cfg, err := client.FelixConfigurations().Get(ctx, "default", options.GetOptions{})
	if _, doesNotExist := err.(cerrors.ErrorResourceDoesNotExist); doesNotExist {
		cfg = api.NewFelixConfiguration()
		cfg.Name = "default"
		deltaFn(cfg)
		_, err = client.FelixConfigurations().Create(ctx, cfg, options.SetOptions{})
		Expect(err).NotTo(HaveOccurred())
	} else {
		Expect(err).NotTo(HaveOccurred())
		deltaFn(cfg)
		_, err = client.FelixConfigurations().Update(ctx, cfg, options.SetOptions{})
		Expect(err).NotTo(HaveOccurred())
	}
}
<|endoftext|>


<commit_before>package game

import (
	"errors"
	"fmt"

	"github.com/ghthor/engine/rpg2d/coord"
	"github.com/ghthor/engine/rpg2d/entity"
	"github.com/ghthor/engine/rpg2d/quad"
	"github.com/ghthor/engine/sim/stime"
)

type narrowPhase struct {
	actorIndex actorIndex

	// Reset at the beginning of every ResolveCollisions call
	solved []quad.Collision
	// Generated at the beginning of every ResolveCollisions call
	collisionIndex quad.CollisionIndex
}

func newNarrowPhase(actorIndex actorIndex) narrowPhase {
	return narrowPhase{actorIndex, make([]quad.Collision, 0, 10), nil}
}

func (phase narrowPhase) hasSolved(c quad.Collision) bool {
	for _, solved := range phase.solved {
		if c.IsSameAs(solved) {
			return true
		}
	}

	return false
}

func (phase narrowPhase) ResolveCollisions(cg *quad.CollisionGroup, now stime.Time) ([]entity.Entity, []entity.Entity) {
	// Reset the resolved slice
	phase.solved = phase.solved[:0]

	// Generate a collision index for the collision group
	phase.collisionIndex = cg.CollisionIndex()

	// A map to store entities that still remain in the world
	remaining := make(map[int64]entity.Entity, len(cg.Entities))
	remainingSlice := func() []entity.Entity {
		// Build a slice from the `remaining` map
		s := make([]entity.Entity, 0, len(remaining))
		for _, e := range remaining {
			s = append(s, e)
		}
		return s
	}

	for _, c := range cg.Collisions {
		if phase.hasSolved(c) {
			continue
		}

		var entities []entity.Entity

		// Resolve type of entity in collision.A
		switch e := c.A.(type) {
		case actorEntity:
			// Resolve the type of entity in collision.B
			entities = phase.resolveActorEntity(phase.actorIndex[e.Id()], c.B, c)
		}

		// As collisions are solved they return entities
		// that have been created or modified and we store
		// them in a map by their Id. Multiple collisions
		// may modify and entity, therefor we only will
		// one version of the entity back to engine when
		// we return.
		for _, e := range entities {
			remaining[e.Id()] = e
		}
	}

	return remainingSlice(), nil
}

func (phase *narrowPhase) resolveActorEntity(a *actor, with entity.Entity, collision quad.Collision) []entity.Entity {
	switch e := with.(type) {
	case actorEntity:
		b := phase.actorIndex[e.Id()]

		return phase.solveActorActor(&solverActorActor{}, a, b, collision)
	}

	return nil
}

func newActorActorCollision(a, b *actor) (*actor, *actor, coord.Collision) {
	var collision coord.Collision

	switch {
	case a.pathAction == nil && b.pathAction != nil:
		a, b = b, a
		fallthrough
	case a.pathAction != nil && b.pathAction == nil:
		collision = coord.NewCellCollision(*a.pathAction, b.Cell())

		// A or B may have had a previous collision resolved that
		// caused this collision to not be possible anymore.
		// Returning nil here will short circut the switch
		// in the resolveActorActorCollision method and
		// avoid a typecast.
		if collision.Type() == coord.CT_NONE {
			return a, b, nil
		}

	case a.pathAction != nil && b.pathAction != nil:
		pathCollision := coord.NewPathCollision(*a.pathAction, *b.pathAction)

		// coord.NewPathCollision can flip the,
		// A and B paths to simplify the number
		// of cases. This normalizes our A and B
		// with the path collision.
		if *a.pathAction != pathCollision.A {
			a, b = b, a
		}

		collision = pathCollision
	case a.pathAction == nil && b.pathAction == nil:
		// This case handles actors being on the same square.
		// There isn't a coord.CollisionType for this case.
		// Maybe there should be?
		return a, b, nil

	default:
		panic(fmt.Sprintf("impossible collision between {%v} {%v}", a, b))
	}
	return a, b, collision
}

type node struct {
	actor  *actor
	entity entity.Entity
}

func followGraph(a, b *actor, collision quad.Collision) node {
	// normalize a, b to collision.[A, B]
	if a.Id() != collision.A.Id() {
		a, b = b, a
	}

	var actor *actor
	var entity entity.Entity

	switch {
	case a.pathAction.Orig == b.pathAction.Dest:
		entity = collision.A
		actor = a

	case b.pathAction.Orig == a.pathAction.Dest:
		entity = collision.B
		actor = b

	default:
		panic(fmt.Sprintf("unexpected graph state %v between %v & %v", collision, a, b))
	}

	return node{actor, entity}
}

func currentNode(a, b *actor, collision quad.Collision) *actor {
	switch {
	case a.pathAction.Orig == b.pathAction.Dest:
		return b

	case b.pathAction.Orig == a.pathAction.Dest:
		return a

	default:
		panic(fmt.Sprintf("unexpected graph state %v between %v & %v", collision, a, b))
	}
}

func otherEntityIn(a *actor, collision quad.Collision) entity.Entity {
	var e entity.Entity

	// figure out is prioritized actor is A or B in the collision
	switch {
	case a.Id() != collision.A.Id():
		e = collision.A

	case a.Id() != collision.B.Id():
		e = collision.B

	default:
		panic(fmt.Sprintf("unexpected graph state %v actor %v", collision, a))
	}

	return e
}

type solverActorActor struct {
	visited []*actor
}

func (s solverActorActor) hasVisited(actor *actor) bool {
	for _, a := range s.visited {
		if actor == a {
			return true
		}
	}

	return false
}

func (phase *narrowPhase) solveActorActor(solver *solverActorActor, a, b *actor, collision quad.Collision) []entity.Entity {

	// When this functions returns the
	// collision will have been solved
	defer func() {
		phase.solved = append(phase.solved, collision)
	}()

	var entities []entity.Entity

attemptSolve:
	a, b, coordCollision := newActorActorCollision(a, b)
	if coordCollision == nil {
		goto resolved
	}

	switch coordCollision.Type() {
	case coord.CT_NONE:
		// This may not be entirely accurate.
		// We should walk through the collision index
		// of our partner too see if they should resolve
		// some of there collisions first. They may
		// appear to be moving to us right now, but
		// have a collision that when solved will
		// render them motionless, thus we would become
		// motionless as well.
		e, err := phase.solveDependencies(solver, a, b, collision)

		switch err {
		case errCycleDetected:
			// Detected a cycle, we can't move
			currentNode(a, b, collision).revertMoveAction()
			goto resolved

		case errNoDependencies:
			// All dependencies have been solved
			// We can move
			goto resolved

		case nil:
		}

		if len(e) > 0 {
			entities = append(entities, e...)
		}

		// Try solving again
		goto attemptSolve

	case coord.CT_CELL_DEST:
		a.revertMoveAction()
		goto resolved

	case coord.CT_SWAP:
		a.revertMoveAction()
		b.revertMoveAction()
		goto resolved

	case coord.CT_A_INTO_B_FROM_SIDE:
		// This may not be entirely accurate.
		// We should walk through the collision index
		// of our partner too see if they should resolve
		// some of there collisions first. They may
		// appear to be moving to us right now, but
		// have a collision that when solved will
		// render them motionless, thus we would become
		// motionless as well.
		e, err := phase.solveDependencies(solver, a, b, collision)

		switch err {
		case nil:
			if len(e) > 0 {
				entities = append(entities, e...)
			}

			// Try solving again
			goto attemptSolve

		case errCycleDetected:
			a.revertMoveAction()
			goto resolved

		case errNoDependencies:
		}

		// If we ever hit this point it means we've
		// resolved all the collisions this one
		// depends on and therefor it can be resolved.
		if a.pathAction.End() >= b.pathAction.End() {
			goto resolved
		}

		fallthrough

	case coord.CT_A_INTO_B:
		a.revertMoveAction()
		goto resolved

	case coord.CT_HEAD_TO_HEAD:
		fallthrough

	case coord.CT_FROM_SIDE:
		if a.pathAction.Start() < b.pathAction.Start() {
			// A has already won the destination
			b.revertMoveAction()
			goto resolved

		} else if a.pathAction.Start() > b.pathAction.Start() {
			// B has already won the destination
			a.revertMoveAction()
			goto resolved
		}
		// Start values are equal

		if a.pathAction.End() < b.pathAction.End() {
			// A is moving faster and wins the destination
			b.revertMoveAction()
			goto resolved

		} else if a.pathAction.End() > b.pathAction.End() {
			// B is moving faster and wins the destination
			a.revertMoveAction()
			goto resolved
		}
		// End values are equal

		// Movement direction priority goes in this order
		// N -> E -> S -> W
		if a.facing < b.facing {
			// A's movement direction has a higher priority
			b.revertMoveAction()
			goto resolved

		} else {
			// B's movement direction has a higher priority
			a.revertMoveAction()
			goto resolved
		}
	}

resolved:
	return append(entities, a.Entity(), b.Entity())
}

var errNoDependencies = errors.New("no dependencies")
var errCycleDetected = errors.New("cycle detected")

func (phase *narrowPhase) solveDependencies(solver *solverActorActor, a, b *actor, collision quad.Collision) ([]entity.Entity, error) {
	node := followGraph(a, b, collision)

	// Mark what actors have been visited
	if a != node.actor {
		solver.visited = append(solver.visited, a)
	} else {
		solver.visited = append(solver.visited, b)
	}

	// If the next node only has one collision
	// then there are no dependencies and the
	// collision can be solved
	if len(phase.collisionIndex[node.entity]) == 1 {
		return nil, errNoDependencies
	}

	// Walk through the directed graph of collisions and solve
	// all the collisions that the collision depends on.
	for _, c := range phase.collisionIndex[node.entity] {
		// Ignore the collision that caused us to
		// recursively solve dependencies
		if c.IsSameAs(collision) {
			continue
		}

		// Avoid solving a collision that's already been solving.
		if phase.hasSolved(c) {
			continue
		}

		e := otherEntityIn(node.actor, c)

		switch e := e.(type) {
		case actorEntity:
			actor := phase.actorIndex[e.Id()]

			// Detect cycles
			if solver.hasVisited(actor) {
				return nil, errCycleDetected
			}

			return phase.solveActorActor(solver, node.actor, actor, c), nil
		}

	}

	return nil, errNoDependencies
}
<commit_msg>[game] improve documentation<commit_after>package game

import (
	"errors"
	"fmt"

	"github.com/ghthor/engine/rpg2d/coord"
	"github.com/ghthor/engine/rpg2d/entity"
	"github.com/ghthor/engine/rpg2d/quad"
	"github.com/ghthor/engine/sim/stime"
)

type narrowPhase struct {
	actorIndex actorIndex

	// Reset at the beginning of every ResolveCollisions call
	solved []quad.Collision
	// Generated at the beginning of every ResolveCollisions call
	collisionIndex quad.CollisionIndex
}

func newNarrowPhase(actorIndex actorIndex) narrowPhase {
	return narrowPhase{actorIndex, make([]quad.Collision, 0, 10), nil}
}

// Returns if the collision exists in the
// slice of collisions that have been
// solved during this narrow phase tick.
func (phase narrowPhase) hasSolved(c quad.Collision) bool {
	for _, solved := range phase.solved {
		if c.IsSameAs(solved) {
			return true
		}
	}

	return false
}

// Implementation of the quad.NarrowPhaseHandler interface.
func (phase narrowPhase) ResolveCollisions(cg *quad.CollisionGroup, now stime.Time) ([]entity.Entity, []entity.Entity) {
	// Reset the resolved slice
	phase.solved = phase.solved[:0]

	// Generate a collision index for the collision group
	phase.collisionIndex = cg.CollisionIndex()

	// A map to store entities that still remain in the world
	remaining := make(map[int64]entity.Entity, len(cg.Entities))
	remainingSlice := func() []entity.Entity {
		// Build a slice from the `remaining` map
		s := make([]entity.Entity, 0, len(remaining))
		for _, e := range remaining {
			s = append(s, e)
		}
		return s
	}

	for _, c := range cg.Collisions {
		if phase.hasSolved(c) {
			continue
		}

		var entities []entity.Entity

		// Resolve type of entity in collision.A
		switch e := c.A.(type) {
		case actorEntity:
			// Resolve the type of entity in collision.B
			entities = phase.resolveActorEntity(phase.actorIndex[e.Id()], c.B, c)
		}

		// As collisions are solved they return entities
		// that have been created or modified and we store
		// them in a map by their Id. Multiple collisions
		// may modify and entity, therefor we only will
		// one version of the entity back to engine when
		// we return.
		for _, e := range entities {
			remaining[e.Id()] = e
		}
	}

	return remainingSlice(), nil
}

func (phase *narrowPhase) resolveActorEntity(a *actor, with entity.Entity, collision quad.Collision) []entity.Entity {
	switch e := with.(type) {
	case actorEntity:
		b := phase.actorIndex[e.Id()]

		return phase.solveActorActor(&solverActorActor{}, a, b, collision)
	}

	return nil
}

func newActorActorCollision(a, b *actor) (*actor, *actor, coord.Collision) {
	var collision coord.Collision

	switch {
	case a.pathAction == nil && b.pathAction != nil:
		a, b = b, a
		fallthrough
	case a.pathAction != nil && b.pathAction == nil:
		collision = coord.NewCellCollision(*a.pathAction, b.Cell())

		// A or B may have had a previous collision resolved that
		// caused this collision to not be possible anymore.
		// It is more relevant to return nil here then a
		// coord.Collision with type CT_NONE
		if collision.Type() == coord.CT_NONE {
			return a, b, nil
		}

	case a.pathAction != nil && b.pathAction != nil:
		pathCollision := coord.NewPathCollision(*a.pathAction, *b.pathAction)

		// coord.NewPathCollision can flip the,
		// A and B paths to simplify the number
		// of collision types. This normalizes
		// actor A with pathCollision.A
		if *a.pathAction != pathCollision.A {
			a, b = b, a
		}

		collision = pathCollision
	case a.pathAction == nil && b.pathAction == nil:
		// This case handles actors being on the same square,
		// but not moving at all.
		// There isn't a coord.CollisionType for this case.
		// Maybe there should be?
		return a, b, nil

	default:
		panic(fmt.Sprintf("impossible collision between {%v} {%v}", a, b))
	}
	return a, b, collision
}

type node struct {
	actor  *actor
	entity entity.Entity
}

// Move forward in the directed graph. This movement is based on
// which entity is occupying the destination of the other's path action.
func followGraph(a, b *actor, collision quad.Collision) node {
	// normalize a, b to collision.[A, B]
	if a.Id() != collision.A.Id() {
		a, b = b, a
	}

	var actor *actor
	var entity entity.Entity

	switch {
	case a.pathAction.Orig == b.pathAction.Dest:
		entity = collision.A
		actor = a

	case b.pathAction.Orig == a.pathAction.Dest:
		entity = collision.B
		actor = b

	default:
		panic(fmt.Sprintf("unexpected graph state %v between %v & %v", collision, a, b))
	}

	return node{actor, entity}
}

// Used to figure out which actor is "A" if
// the collision was CT_A_INTO_B instead of CT_NONE
func currentNode(a, b *actor, collision quad.Collision) *actor {
	switch {
	case a.pathAction.Orig == b.pathAction.Dest:
		return b

	case b.pathAction.Orig == a.pathAction.Dest:
		return a

	default:
		panic(fmt.Sprintf("unexpected graph state %v between %v & %v", collision, a, b))
	}
}

// Compare entity Id's with the entities in
// a collision and return the one that isn't
// the actor.
func otherEntityIn(a *actor, collision quad.Collision) entity.Entity {
	var e entity.Entity

	// figure out is prioritized actor is A or B in the collision
	switch {
	case a.Id() != collision.A.Id():
		e = collision.A

	case a.Id() != collision.B.Id():
		e = collision.B

	default:
		panic(fmt.Sprintf("unexpected graph state %v actor %v", collision, a))
	}

	return e
}

// Store what actor's have been visited during
// a recursive solve. Used to avoid infinite
// recursion through a cycle in the graph.
type solverActorActor struct {
	visited []*actor
}

func (s solverActorActor) hasVisited(actor *actor) bool {
	for _, a := range s.visited {
		if actor == a {
			return true
		}
	}

	return false
}

func (phase *narrowPhase) solveActorActor(solver *solverActorActor, a, b *actor, collision quad.Collision) []entity.Entity {

	// When this functions returns the
	// collision will have been solved
	defer func() {
		phase.solved = append(phase.solved, collision)
	}()

	var entities []entity.Entity

attemptSolve:
	a, b, coordCollision := newActorActorCollision(a, b)
	if coordCollision == nil {
		goto resolved
	}

	switch coordCollision.Type() {
	case coord.CT_NONE:
		// This may not be entirely accurate.
		// We should walk through the collision index
		// of our partner too see if they should resolve
		// some of there collisions first. They may
		// appear to be moving to us right now, but
		// have a collision that when solved will
		// render them motionless, thus we would become
		// motionless as well.
		e, err := phase.solveDependencies(solver, a, b, collision)

		switch err {
		case errCycleDetected:
			// Detected a cycle, we can't move
			currentNode(a, b, collision).revertMoveAction()
			goto resolved

		case errNoDependencies:
			// All dependencies have been solved
			// We can move
			goto resolved

		case nil:
		}

		if len(e) > 0 {
			entities = append(entities, e...)
		}

		// Try solving again
		goto attemptSolve

	case coord.CT_CELL_DEST:
		a.revertMoveAction()
		goto resolved

	case coord.CT_SWAP:
		a.revertMoveAction()
		b.revertMoveAction()
		goto resolved

	case coord.CT_A_INTO_B_FROM_SIDE:
		// This may not be entirely accurate.
		// We should walk through the collision index
		// of our partner too see if they should resolve
		// some of there collisions first. They may
		// appear to be moving to us right now, but
		// have a collision that when solved will
		// render them motionless, thus we would become
		// motionless as well.
		e, err := phase.solveDependencies(solver, a, b, collision)

		switch err {
		case nil:
			if len(e) > 0 {
				entities = append(entities, e...)
			}

			// Try solving again
			goto attemptSolve

		case errCycleDetected:
			a.revertMoveAction()
			goto resolved

		case errNoDependencies:
		}

		// If we ever hit this point it means we've
		// resolved all the collisions this one
		// depends on and therefor it can be resolved.
		if a.pathAction.End() >= b.pathAction.End() {
			goto resolved
		}

		fallthrough

	case coord.CT_A_INTO_B:
		a.revertMoveAction()
		goto resolved

	case coord.CT_HEAD_TO_HEAD:
		fallthrough

	case coord.CT_FROM_SIDE:
		if a.pathAction.Start() < b.pathAction.Start() {
			// A has already won the destination
			b.revertMoveAction()
			goto resolved

		} else if a.pathAction.Start() > b.pathAction.Start() {
			// B has already won the destination
			a.revertMoveAction()
			goto resolved
		}
		// Start values are equal

		if a.pathAction.End() < b.pathAction.End() {
			// A is moving faster and wins the destination
			b.revertMoveAction()
			goto resolved

		} else if a.pathAction.End() > b.pathAction.End() {
			// B is moving faster and wins the destination
			a.revertMoveAction()
			goto resolved
		}
		// End values are equal

		// Movement direction priority goes in this order
		// N -> E -> S -> W
		if a.facing < b.facing {
			// A's movement direction has a higher priority
			b.revertMoveAction()
			goto resolved

		} else {
			// B's movement direction has a higher priority
			a.revertMoveAction()
			goto resolved
		}
	}

resolved:
	return append(entities, a.Entity(), b.Entity())
}

var errNoDependencies = errors.New("no dependencies")
var errCycleDetected = errors.New("cycle detected")

// Error can be errNoDependencies, errCycleDetected or nil
func (phase *narrowPhase) solveDependencies(solver *solverActorActor, a, b *actor, collision quad.Collision) ([]entity.Entity, error) {
	node := followGraph(a, b, collision)

	// Mark what actors have been visited
	if a != node.actor {
		solver.visited = append(solver.visited, a)
	} else {
		solver.visited = append(solver.visited, b)
	}

	// If the next node only has one collision
	// then there are no dependencies and the
	// collision can be solved
	if len(phase.collisionIndex[node.entity]) == 1 {
		return nil, errNoDependencies
	}

	// Walk through the directed graph of collisions and solve
	// all the collisions that the collision depends on.
	for _, c := range phase.collisionIndex[node.entity] {
		// Ignore the collision that caused us to recurse
		if c.IsSameAs(collision) {
			continue
		}

		// Avoid solving a collision that's already been solving.
		if phase.hasSolved(c) {
			continue
		}

		e := otherEntityIn(node.actor, c)

		switch e := e.(type) {
		case actorEntity:
			actor := phase.actorIndex[e.Id()]

			// Detect cycles
			if solver.hasVisited(actor) {
				return nil, errCycleDetected
			}

			// Recurse
			return phase.solveActorActor(solver, node.actor, actor, c), nil
		}

	}

	return nil, errNoDependencies
}
<|endoftext|>


<commit_before>package gdk3

/*
#include <gdk/gdk.h>
static inline guint getModifiers(GdkEventKey* ke) {
	return ke->is_modifier;
}

*/
import "C"
import "github.com/norisatir/go-gtk3/gobject"
import "unsafe"

type EventLike interface {
	EventType() int
	GdkWindow() *Window
	SentExplicitly() bool
}

// GdkEventAny
type EventAny struct {
	eventType int
	window    *Window
	sendEvent bool
}

// To-be event like
func (self EventAny) EventType() int {
	return self.eventType
}

func (self EventAny) Window() *Window {
	return self.window
}

func (self EventAny) SentExplicitly() bool {
	return self.sendEvent
}

// GdkEventKey
type EventKey struct {
	EventAny
	Time            uint32
	State           uint
	KeyVal          uint
	HardwareKeycode uint16
	Group           byte
	IsModifier      uint
}

func createEventKey(obj unsafe.Pointer) EventKey {
	ke := (*C.GdkEventKey)(obj)
	keyEvent := EventKey{}
	keyEvent.Time = uint32(ke.time)
	keyEvent.State = uint(ke.state)
	keyEvent.KeyVal = uint(ke.keyval)
	keyEvent.HardwareKeycode = uint16(ke.hardware_keycode)
	keyEvent.Group = byte(ke.group)
	keyEvent.IsModifier = uint(C.getModifiers(ke))
	return keyEvent
}

// GdkEventButton
type EventButton struct {
	EventAny
	Time   uint32
	X      float64
	Y      float64
	State  uint
	Button uint
	Device *Device
	X_Root float64
	Y_Root float64
}

func createEventButton(obj unsafe.Pointer) EventButton {
	eb := (*C.GdkEventButton)(obj)
	eventButton := EventButton{}
	eventButton.Time = uint32(eb.time)
	eventButton.X = float64(eb.x)
	eventButton.Y = float64(eb.y)
	eventButton.State = uint(eb.state)
	eventButton.Button = uint(eb.button)
	gd, _ := gobject.ConvertToGo(unsafe.Pointer(eb.device), GdkType.DEVICE)
	eventButton.Device = gd.(*Device)
	eventButton.X_Root = float64(eb.x_root)
	eventButton.Y_Root = float64(eb.y_root)
	return eventButton
}

// Conversion function
func newEventFromNative(obj unsafe.Pointer) interface{} {
	// Cast to EventAny to extract type and send var
	var window *Window = nil
	ceventAny := (*C.GdkEventAny)(obj)
	t := int(ceventAny._type)
	if win, err := gobject.ConvertToGo(unsafe.Pointer(ceventAny.window)); err == nil {
		window = win.(*Window)
	}
	se := ceventAny.send_event
	send := gobject.GoBool(unsafe.Pointer(&se))

	// Create new EventAny Struct
	eventAny := EventAny{t, window, send}

	// test specific events
	switch t {
	case GdkEventType.KEY_PRESS, GdkEventType.KEY_RELEASE:
		ek := createEventKey(obj)
		ek.EventAny = eventAny
		return ek
	case GdkEventType.BUTTON_PRESS, GdkEventType.BUTTON_PRESS_2, GdkEventType.BUTTON_PRESS_3,
		GdkEventType.BUTTON_RELEASE:
		eb := createEventButton(obj)
		eb.EventAny = eventAny
		return eb
	}
	return eventAny
}

func init() {
	//Register GdkEvent to gobject (In Go)
	gobject.RegisterCType(GdkType.EVENT, newEventFromNative)
	init_events()
	init_mask()
}

var GdkEventMask gdkEventMask

type gdkEventMask struct {
	EXPOSURE_MASK            int
	POINTER_MOTION_MASK      int
	POINTER_MOTION_HINT_MASK int
	BUTTON_MOTION_MASK       int
	BUTTON1_MOTION_MASK      int
	BUTTON2_MOTION_MASK      int
	BUTTON3_MOTION_MASK      int
	BUTTON_PRESS_MASK        int
	BUTTON_RELEASE_MASK      int
	KEY_PRESS_MASK           int
	KEY_RELEASE_MASK         int
	ENTER_NOTIFY_MASK        int
	LEAVE_NOTIFY_MASK        int
	FOCUS_CHANGE_MASK        int
	STRUCTURE_MASK           int
	PROPERTY_CHANGE_MASK     int
	VISIBILITY_CHANGE_MASK   int
	PROXIMITY_IN_MASK        int
	PROXIMITY_OUT_MASK       int
	SUBSTRUCTURE_MASK        int
	SCROLL_MASK              int
	ALL_EVENTS_MASK          int
}

func init_mask() {
	GdkEventMask.EXPOSURE_MASK = 1 << 1
	GdkEventMask.POINTER_MOTION_MASK = 1 << 2
	GdkEventMask.POINTER_MOTION_HINT_MASK = 1 << 3
	GdkEventMask.BUTTON_MOTION_MASK = 1 << 4
	GdkEventMask.BUTTON1_MOTION_MASK = 1 << 5
	GdkEventMask.BUTTON2_MOTION_MASK = 1 << 6
	GdkEventMask.BUTTON3_MOTION_MASK = 1 << 7
	GdkEventMask.BUTTON_PRESS_MASK = 1 << 8
	GdkEventMask.BUTTON_RELEASE_MASK = 1 << 9
	GdkEventMask.KEY_PRESS_MASK = 1 << 10
	GdkEventMask.KEY_RELEASE_MASK = 1 << 11
	GdkEventMask.ENTER_NOTIFY_MASK = 1 << 12
	GdkEventMask.LEAVE_NOTIFY_MASK = 1 << 13
	GdkEventMask.FOCUS_CHANGE_MASK = 1 << 14
	GdkEventMask.STRUCTURE_MASK = 1 << 15
	GdkEventMask.PROPERTY_CHANGE_MASK = 1 << 16
	GdkEventMask.VISIBILITY_CHANGE_MASK = 1 << 17
	GdkEventMask.PROXIMITY_IN_MASK = 1 << 18
	GdkEventMask.PROXIMITY_OUT_MASK = 1 << 19
	GdkEventMask.SUBSTRUCTURE_MASK = 1 << 20
	GdkEventMask.SCROLL_MASK = 1 << 21
	GdkEventMask.ALL_EVENTS_MASK = 0x3FFFFE
}

var GdkEventType gdkEventType

type gdkEventType struct {
	NOTHING           int
	DELETE            int
	DESTROY           int
	EXPOSE            int
	MOTION_NOTIFY     int
	BUTTON_PRESS      int
	BUTTON_PRESS_2    int
	BUTTON_PRESS_3    int
	BUTTON_RELEASE    int
	KEY_PRESS         int
	KEY_RELEASE       int
	ENTER_NOTIFY      int
	LEAVE_NOTIFY      int
	FOCUS_CHANGE      int
	CONFIGURE         int
	MAP               int
	UNMAP             int
	PROPERTY_NOTIFY   int
	SELECTION_CLEAR   int
	SELECTION_REQUEST int
	SELECTION_NOTIFY  int
	PROXIMITY_IN      int
	PROXIMITY_OUT     int
	DRAG_ENTER        int
	DRAG_LEAVE        int
	DRAG_MOTION       int
	DRAG_STATUS       int
	DRAG_START        int
	DRAG_FINISHED     int
	CLIENT_EVENT      int
	VISIBILITY_NOTIFY int
	SCROLL            int
	WINDOW_STATE      int
	SETTING           int
	OWNER_CHANGE      int
	GRAB_BROKEN       int
	DAMAGE            int
}

func init_events() {
	GdkEventType.NOTHING = -1
	GdkEventType.DELETE = 0
	GdkEventType.DESTROY = 1
	GdkEventType.EXPOSE = 2
	GdkEventType.MOTION_NOTIFY = 3
	GdkEventType.BUTTON_PRESS = 4
	GdkEventType.BUTTON_PRESS_2 = 5
	GdkEventType.BUTTON_PRESS_3 = 6
	GdkEventType.BUTTON_RELEASE = 7
	GdkEventType.KEY_PRESS = 8
	GdkEventType.KEY_RELEASE = 9
	GdkEventType.ENTER_NOTIFY = 10
	GdkEventType.LEAVE_NOTIFY = 11
	GdkEventType.FOCUS_CHANGE = 12
	GdkEventType.CONFIGURE = 13
	GdkEventType.MAP = 14
	GdkEventType.UNMAP = 15
	GdkEventType.PROPERTY_NOTIFY = 16
	GdkEventType.SELECTION_CLEAR = 17
	GdkEventType.SELECTION_REQUEST = 18
	GdkEventType.SELECTION_NOTIFY = 19
	GdkEventType.PROXIMITY_IN = 20
	GdkEventType.PROXIMITY_OUT = 21
	GdkEventType.DRAG_ENTER = 22
	GdkEventType.DRAG_LEAVE = 23
	GdkEventType.DRAG_MOTION = 24
	GdkEventType.DRAG_STATUS = 25
	GdkEventType.DRAG_START = 26
	GdkEventType.DRAG_FINISHED = 27
	GdkEventType.CLIENT_EVENT = 28
	GdkEventType.VISIBILITY_NOTIFY = 29
	GdkEventType.SCROLL = 31
	GdkEventType.WINDOW_STATE = 32
	GdkEventType.SETTING = 33
	GdkEventType.OWNER_CHANGE = 34
	GdkEventType.GRAB_BROKEN = 35
	GdkEventType.DAMAGE = 36
}
<commit_msg>Added check for nil Device pointer.<commit_after>package gdk3

/*
#include <gdk/gdk.h>
static inline guint getModifiers(GdkEventKey* ke) {
	return ke->is_modifier;
}

*/
import "C"
import "github.com/norisatir/go-gtk3/gobject"
import "unsafe"

type EventLike interface {
	EventType() int
	GdkWindow() *Window
	SentExplicitly() bool
}

// GdkEventAny
type EventAny struct {
	eventType int
	window    *Window
	sendEvent bool
}

// To-be event like
func (self EventAny) EventType() int {
	return self.eventType
}

func (self EventAny) Window() *Window {
	return self.window
}

func (self EventAny) SentExplicitly() bool {
	return self.sendEvent
}

// GdkEventKey
type EventKey struct {
	EventAny
	Time            uint32
	State           uint
	KeyVal          uint
	HardwareKeycode uint16
	Group           byte
	IsModifier      uint
}

func createEventKey(obj unsafe.Pointer) EventKey {
	ke := (*C.GdkEventKey)(obj)
	keyEvent := EventKey{}
	keyEvent.Time = uint32(ke.time)
	keyEvent.State = uint(ke.state)
	keyEvent.KeyVal = uint(ke.keyval)
	keyEvent.HardwareKeycode = uint16(ke.hardware_keycode)
	keyEvent.Group = byte(ke.group)
	keyEvent.IsModifier = uint(C.getModifiers(ke))
	return keyEvent
}

// GdkEventButton
type EventButton struct {
	EventAny
	Time   uint32
	X      float64
	Y      float64
	State  uint
	Button uint
	Device *Device
	X_Root float64
	Y_Root float64
}

func createEventButton(obj unsafe.Pointer) EventButton {
	eb := (*C.GdkEventButton)(obj)
	eventButton := EventButton{}
	eventButton.Time = uint32(eb.time)
	eventButton.X = float64(eb.x)
	eventButton.Y = float64(eb.y)
	eventButton.State = uint(eb.state)
	eventButton.Button = uint(eb.button)
	eventButton.Device = nil
	if gd, err := gobject.ConvertToGo(unsafe.Pointer(eb.device), GdkType.DEVICE); err == nil {
		eventButton.Device = gd.(*Device)
	}
	eventButton.X_Root = float64(eb.x_root)
	eventButton.Y_Root = float64(eb.y_root)
	return eventButton
}

// Conversion function
func newEventFromNative(obj unsafe.Pointer) interface{} {
	// Cast to EventAny to extract type and send var
	var window *Window = nil
	ceventAny := (*C.GdkEventAny)(obj)
	t := int(ceventAny._type)
	if win, err := gobject.ConvertToGo(unsafe.Pointer(ceventAny.window)); err == nil {
		window = win.(*Window)
	}
	se := ceventAny.send_event
	send := gobject.GoBool(unsafe.Pointer(&se))

	// Create new EventAny Struct
	eventAny := EventAny{t, window, send}

	// test specific events
	switch t {
	case GdkEventType.KEY_PRESS, GdkEventType.KEY_RELEASE:
		ek := createEventKey(obj)
		ek.EventAny = eventAny
		return ek
	case GdkEventType.BUTTON_PRESS, GdkEventType.BUTTON_PRESS_2, GdkEventType.BUTTON_PRESS_3,
		GdkEventType.BUTTON_RELEASE:
		eb := createEventButton(obj)
		eb.EventAny = eventAny
		return eb
	}
	return eventAny
}

func init() {
	//Register GdkEvent to gobject (In Go)
	gobject.RegisterCType(GdkType.EVENT, newEventFromNative)
	init_events()
	init_mask()
}

var GdkEventMask gdkEventMask

type gdkEventMask struct {
	EXPOSURE_MASK            int
	POINTER_MOTION_MASK      int
	POINTER_MOTION_HINT_MASK int
	BUTTON_MOTION_MASK       int
	BUTTON1_MOTION_MASK      int
	BUTTON2_MOTION_MASK      int
	BUTTON3_MOTION_MASK      int
	BUTTON_PRESS_MASK        int
	BUTTON_RELEASE_MASK      int
	KEY_PRESS_MASK           int
	KEY_RELEASE_MASK         int
	ENTER_NOTIFY_MASK        int
	LEAVE_NOTIFY_MASK        int
	FOCUS_CHANGE_MASK        int
	STRUCTURE_MASK           int
	PROPERTY_CHANGE_MASK     int
	VISIBILITY_CHANGE_MASK   int
	PROXIMITY_IN_MASK        int
	PROXIMITY_OUT_MASK       int
	SUBSTRUCTURE_MASK        int
	SCROLL_MASK              int
	ALL_EVENTS_MASK          int
}

func init_mask() {
	GdkEventMask.EXPOSURE_MASK = 1 << 1
	GdkEventMask.POINTER_MOTION_MASK = 1 << 2
	GdkEventMask.POINTER_MOTION_HINT_MASK = 1 << 3
	GdkEventMask.BUTTON_MOTION_MASK = 1 << 4
	GdkEventMask.BUTTON1_MOTION_MASK = 1 << 5
	GdkEventMask.BUTTON2_MOTION_MASK = 1 << 6
	GdkEventMask.BUTTON3_MOTION_MASK = 1 << 7
	GdkEventMask.BUTTON_PRESS_MASK = 1 << 8
	GdkEventMask.BUTTON_RELEASE_MASK = 1 << 9
	GdkEventMask.KEY_PRESS_MASK = 1 << 10
	GdkEventMask.KEY_RELEASE_MASK = 1 << 11
	GdkEventMask.ENTER_NOTIFY_MASK = 1 << 12
	GdkEventMask.LEAVE_NOTIFY_MASK = 1 << 13
	GdkEventMask.FOCUS_CHANGE_MASK = 1 << 14
	GdkEventMask.STRUCTURE_MASK = 1 << 15
	GdkEventMask.PROPERTY_CHANGE_MASK = 1 << 16
	GdkEventMask.VISIBILITY_CHANGE_MASK = 1 << 17
	GdkEventMask.PROXIMITY_IN_MASK = 1 << 18
	GdkEventMask.PROXIMITY_OUT_MASK = 1 << 19
	GdkEventMask.SUBSTRUCTURE_MASK = 1 << 20
	GdkEventMask.SCROLL_MASK = 1 << 21
	GdkEventMask.ALL_EVENTS_MASK = 0x3FFFFE
}

var GdkEventType gdkEventType

type gdkEventType struct {
	NOTHING           int
	DELETE            int
	DESTROY           int
	EXPOSE            int
	MOTION_NOTIFY     int
	BUTTON_PRESS      int
	BUTTON_PRESS_2    int
	BUTTON_PRESS_3    int
	BUTTON_RELEASE    int
	KEY_PRESS         int
	KEY_RELEASE       int
	ENTER_NOTIFY      int
	LEAVE_NOTIFY      int
	FOCUS_CHANGE      int
	CONFIGURE         int
	MAP               int
	UNMAP             int
	PROPERTY_NOTIFY   int
	SELECTION_CLEAR   int
	SELECTION_REQUEST int
	SELECTION_NOTIFY  int
	PROXIMITY_IN      int
	PROXIMITY_OUT     int
	DRAG_ENTER        int
	DRAG_LEAVE        int
	DRAG_MOTION       int
	DRAG_STATUS       int
	DRAG_START        int
	DRAG_FINISHED     int
	CLIENT_EVENT      int
	VISIBILITY_NOTIFY int
	SCROLL            int
	WINDOW_STATE      int
	SETTING           int
	OWNER_CHANGE      int
	GRAB_BROKEN       int
	DAMAGE            int
}

func init_events() {
	GdkEventType.NOTHING = -1
	GdkEventType.DELETE = 0
	GdkEventType.DESTROY = 1
	GdkEventType.EXPOSE = 2
	GdkEventType.MOTION_NOTIFY = 3
	GdkEventType.BUTTON_PRESS = 4
	GdkEventType.BUTTON_PRESS_2 = 5
	GdkEventType.BUTTON_PRESS_3 = 6
	GdkEventType.BUTTON_RELEASE = 7
	GdkEventType.KEY_PRESS = 8
	GdkEventType.KEY_RELEASE = 9
	GdkEventType.ENTER_NOTIFY = 10
	GdkEventType.LEAVE_NOTIFY = 11
	GdkEventType.FOCUS_CHANGE = 12
	GdkEventType.CONFIGURE = 13
	GdkEventType.MAP = 14
	GdkEventType.UNMAP = 15
	GdkEventType.PROPERTY_NOTIFY = 16
	GdkEventType.SELECTION_CLEAR = 17
	GdkEventType.SELECTION_REQUEST = 18
	GdkEventType.SELECTION_NOTIFY = 19
	GdkEventType.PROXIMITY_IN = 20
	GdkEventType.PROXIMITY_OUT = 21
	GdkEventType.DRAG_ENTER = 22
	GdkEventType.DRAG_LEAVE = 23
	GdkEventType.DRAG_MOTION = 24
	GdkEventType.DRAG_STATUS = 25
	GdkEventType.DRAG_START = 26
	GdkEventType.DRAG_FINISHED = 27
	GdkEventType.CLIENT_EVENT = 28
	GdkEventType.VISIBILITY_NOTIFY = 29
	GdkEventType.SCROLL = 31
	GdkEventType.WINDOW_STATE = 32
	GdkEventType.SETTING = 33
	GdkEventType.OWNER_CHANGE = 34
	GdkEventType.GRAB_BROKEN = 35
	GdkEventType.DAMAGE = 36
}
<|endoftext|>


<commit_before>// errchk $G -e $D/$F.go

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

// Static error messages about interface conversions.

package main

type T struct {
	a int
}

var t *T

type I interface {
	M()
}

var i I

type I2 interface {
	M()
	N()
}

var i2 I2

type E interface{}

var e E

func main() {
	e = t // ok
	t = e // ERROR "need explicit|need type assertion"

	// neither of these can work,
	// because i has an extra method
	// that t does not, so i cannot contain a t.
	i = t // ERROR "incompatible|missing M method"
	t = i // ERROR "incompatible|need type assertion"

	i = i2 // ok
	i2 = i // ERROR "missing N method"

	i = I(i2)  // ok
	i2 = I2(i) // ERROR "missing N method"

	e = E(t) // ok
	t = T(e) // ERROR "need explicit|need type assertion|incompatible"
}

type M interface { M() }
var m M

var _ = m.(int)	// ERROR "impossible type assertion"

type Int int
func (Int) M(float) {}

var _ = m.(Int)	// ERROR "impossible type assertion"

var ii int
var jj Int

var m1 M = ii	// ERROR "missing"
var m2 M = jj	// ERROR "wrong type for M method"

var m3 = M(ii)	// ERROR "missing"
var m4 = M(jj)	// ERROR "wrong type for M method"
<commit_msg>test: Match gccgo error messages.<commit_after>// errchk $G -e $D/$F.go

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

// Static error messages about interface conversions.

package main

type T struct {
	a int
}

var t *T

type I interface {
	M()
}

var i I

type I2 interface {
	M()
	N()
}

var i2 I2

type E interface{}

var e E

func main() {
	e = t // ok
	t = e // ERROR "need explicit|need type assertion"

	// neither of these can work,
	// because i has an extra method
	// that t does not, so i cannot contain a t.
	i = t // ERROR "incompatible|missing M method"
	t = i // ERROR "incompatible|need type assertion"

	i = i2 // ok
	i2 = i // ERROR "incompatible|missing N method"

	i = I(i2)  // ok
	i2 = I2(i) // ERROR "invalid|missing N method"

	e = E(t) // ok
	t = T(e) // ERROR "need explicit|need type assertion|incompatible"
}

type M interface { M() }
var m M

var _ = m.(int)	// ERROR "impossible type assertion"

type Int int
func (Int) M(float) {}

var _ = m.(Int)	// ERROR "impossible type assertion"

var ii int
var jj Int

var m1 M = ii	// ERROR "incompatible|missing"
var m2 M = jj	// ERROR "incompatible|wrong type for M method"

var m3 = M(ii)	// ERROR "invalid|missing"
var m4 = M(jj)	// ERROR "invalid|wrong type for M method"
<|endoftext|>


<commit_before>package utils

import (
	"io"
	"net"
	"os"
	"sync"
)

func Proxy(ip string) error {
	_, err := os.Stat("/var/run/docker.sock")
	if err == nil {
		err = os.Remove("/var/run/docker.sock")
		if err != nil {
			return err
		}
	}

	listener, err := net.Listen("unix", "/var/run/docker.sock")
	if err != nil {
		return err
	}

	err = os.Chmod("/var/run/docker.sock", 0777)
	if err != nil {
		return err
	}

	wg := &sync.WaitGroup{}
	for {
		client, err := listener.Accept()
		if err != nil {
			return nil
		}

		wg.Add(1)
		go func() {
			defer wg.Done()
			// defer client.Close()
			server, err := net.Dial("tcp", ip+":2375")
			if err != nil {
				return
			}
			// defer server.Close()
			go func() {
				_, err := io.Copy(client, server)
				if err != nil {
					return
				}

				client.Close()
				server.Close()
			}()

			go func() {
				_, err := io.Copy(server, client)
				if err != nil {
					return
				}

				client.Close()
				server.Close()
			}()
		}()
	}

	wg.Wait()
	return nil
}
<commit_msg>refactor the reverse proxy, closes #96, closes #98<commit_after>package utils

import (
	"io"
	"net"
	"net/http"
	"os"
	"strings"
)

func Proxy(ip string) error {
	_, err := os.Stat("/var/run/docker.sock")
	if err == nil {
		err = os.Remove("/var/run/docker.sock")
		if err != nil {
			return err
		}
	}

	listener, err := net.Listen("unix", "/var/run/docker.sock")
	if err != nil {
		return err
	}

	err = os.Chmod("/var/run/docker.sock", 0777)
	if err != nil {
		return err
	}

	handler := http.HandlerFunc(func (w http.ResponseWriter, r *http.Request) {
		r.URL.Scheme = "http"
		r.URL.Host = ip+":2375"

		if len(r.Header["Upgrade"]) > 0 && strings.ToLower(r.Header["Upgrade"][0]) == "tcp" {
			hj, ok := w.(http.Hijacker)
			if !ok {
				w.WriteHeader(http.StatusServiceUnavailable)
				return
			}

			conn, _, err := hj.Hijack()
			if err != nil {
				w.WriteHeader(http.StatusServiceUnavailable)
				return
			}

			defer conn.Close()

			backend, err := net.Dial("tcp", ip+":2375")
			if err != nil {
				w.WriteHeader(http.StatusServiceUnavailable)
				return
			}

			defer backend.Close()

			err = r.Write(backend)
			if err != nil {
				w.WriteHeader(http.StatusServiceUnavailable)
				return
			}

			finished := make(chan bool, 1)
			go func() {
				io.Copy(backend, conn)
			}()

			go func() {
				io.Copy(conn, backend)
				finished <- true
			}()

			<-finished
		} else {
			resp, err := http.DefaultTransport.RoundTrip(r)
			if err != nil {
				w.WriteHeader(http.StatusServiceUnavailable)
				return
			}

			defer resp.Body.Close()

			for k, v := range resp.Header {
				for _, vv := range v {
					w.Header().Add(k, vv)
				}
			}

			w.WriteHeader(resp.StatusCode)
			io.Copy(w, resp.Body)
		}
	})

	server := http.Server{
		Handler: handler,
	}

	return server.Serve(listener)
}
<|endoftext|>


<commit_before>package utils

import (
	"bytes"
	"os/exec"
	"syscall"
)

const PR_SET_CHILD_SUBREAPER = 36

func ExecCmd(name string, args ...string) (string, error) {
	cmd := exec.Command(name, args...)
	var out bytes.Buffer
	cmd.Stdout = &out

	err := cmd.Run()
	if err != nil {
		return "", err
	}

	return out.String(), nil
}

// SetSubreaper sets the value i as the subreaper setting for the calling process
func SetSubreaper(i int) error {
	return Prctl(PR_SET_CHILD_SUBREAPER, uintptr(i), 0, 0, 0)
}

// Prctl is a way to make the prctl linux syscall
func Prctl(option int, arg2, arg3, arg4, arg5 uintptr) (err error) {
	_, _, e1 := syscall.Syscall6(syscall.SYS_PRCTL, uintptr(option), arg2, arg3, arg4, arg5, 0)
	if e1 != 0 {
		err = e1
	}
	return
}
<commit_msg>Fix the err info of utils.ExecCmd<commit_after>package utils

import (
	"bytes"
	"fmt"
	"os/exec"
	"strings"
	"syscall"
)

const PR_SET_CHILD_SUBREAPER = 36

func ExecCmd(name string, args ...string) (string, error) {
	cmd := exec.Command(name, args...)
	var stdout bytes.Buffer
	var stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr

	err := cmd.Run()
	if err != nil {
		return "", fmt.Errorf("`%v %v` failed: %v (%v)", name, strings.Join(args, " "), stderr.String(), err)
	}

	return stdout.String(), nil
}

// SetSubreaper sets the value i as the subreaper setting for the calling process
func SetSubreaper(i int) error {
	return Prctl(PR_SET_CHILD_SUBREAPER, uintptr(i), 0, 0, 0)
}

// Prctl is a way to make the prctl linux syscall
func Prctl(option int, arg2, arg3, arg4, arg5 uintptr) (err error) {
	_, _, e1 := syscall.Syscall6(syscall.SYS_PRCTL, uintptr(option), arg2, arg3, arg4, arg5, 0)
	if e1 != 0 {
		err = e1
	}
	return
}
<|endoftext|>


<commit_before>package utils

import (
	"errors"
	"net/url"
	"strings"

	ct "github.com/flynn/flynn-controller/types"
	"github.com/flynn/flynn-host/types"
	"github.com/flynn/go-dockerclient"
)

func FormatEnv(envs ...map[string]string) []string {
	env := make(map[string]string)
	for _, e := range envs {
		for k, v := range e {
			env[k] = v
		}
	}
	res := make([]string, 0, len(env))
	for k, v := range env {
		res = append(res, k+"="+v)
	}
	return res
}

func DockerImage(uri string) (string, error) {
	// TODO: ID refs (see https://github.com/dotcloud/docker/issues/4106)
	u, err := url.Parse(uri)
	if err != nil {
		return "", err
	}
	if u.Scheme != "docker" {
		return "", errors.New("utils: only docker artifact URIs are currently supported")
	}
	if tag := u.Query().Get("tag"); tag != "" {
		u.Path += ":" + tag
	}
	if u.Host == "" {
		// docker:///foo/bar results in u.Host == ""
		u.Path = strings.TrimPrefix(u.Path, "/")
	}
	return u.Host + u.Path, nil
}

func JobConfig(f *ct.ExpandedFormation, name string) (*host.Job, error) {
	t := f.Release.Processes[name]
	image, err := DockerImage(f.Artifact.URI)
	if err != nil {
		return nil, err
	}
	return &host.Job{
		TCPPorts: t.Ports.TCP,
		Attributes: map[string]string{
			"flynn-controller.app":     f.App.ID,
			"flynn-controller.release": f.Release.ID,
			"flynn-controller.type":    name,
		},
		Config: &docker.Config{
			Cmd: t.Cmd,
			Env: FormatEnv(f.Release.Env, t.Env,
				map[string]string{
					"FLYNN_APP_ID":     f.App.ID,
					"FLYNN_RELEASE_ID": f.Release.ID,
				},
			),
			Image: image,
		},
	}, nil
}
<commit_msg>utils: Add basic data volume support to JobConfig<commit_after>package utils

import (
	"errors"
	"net/url"
	"strings"

	ct "github.com/flynn/flynn-controller/types"
	"github.com/flynn/flynn-host/types"
	"github.com/flynn/go-dockerclient"
)

func FormatEnv(envs ...map[string]string) []string {
	env := make(map[string]string)
	for _, e := range envs {
		for k, v := range e {
			env[k] = v
		}
	}
	res := make([]string, 0, len(env))
	for k, v := range env {
		res = append(res, k+"="+v)
	}
	return res
}

func DockerImage(uri string) (string, error) {
	// TODO: ID refs (see https://github.com/dotcloud/docker/issues/4106)
	u, err := url.Parse(uri)
	if err != nil {
		return "", err
	}
	if u.Scheme != "docker" {
		return "", errors.New("utils: only docker artifact URIs are currently supported")
	}
	if tag := u.Query().Get("tag"); tag != "" {
		u.Path += ":" + tag
	}
	if u.Host == "" {
		// docker:///foo/bar results in u.Host == ""
		u.Path = strings.TrimPrefix(u.Path, "/")
	}
	return u.Host + u.Path, nil
}

func JobConfig(f *ct.ExpandedFormation, name string) (*host.Job, error) {
	t := f.Release.Processes[name]
	image, err := DockerImage(f.Artifact.URI)
	if err != nil {
		return nil, err
	}
	job := &host.Job{
		TCPPorts: t.Ports.TCP,
		Attributes: map[string]string{
			"flynn-controller.app":     f.App.ID,
			"flynn-controller.release": f.Release.ID,
			"flynn-controller.type":    name,
		},
		Config: &docker.Config{
			Cmd: t.Cmd,
			Env: FormatEnv(f.Release.Env, t.Env,
				map[string]string{
					"FLYNN_APP_ID":     f.App.ID,
					"FLYNN_RELEASE_ID": f.Release.ID,
				},
			),
			Image: image,
		},
	}
	if t.Data {
		job.Config.Volumes = map[string]struct{}{"/data": {}}
	}
	return job, nil
}
<|endoftext|>