<commit_before>/*
Copyright 2013 The Camlistore Authors

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

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

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

// Package storagetest tests blobserver.Storage implementations
package storagetest

import (
	"errors"
	"fmt"
	"io"
	"reflect"
	"sort"
	"strconv"
	"strings"
	"testing"
	"time"

	"camlistore.org/pkg/blob"
	"camlistore.org/pkg/blobserver"
	"camlistore.org/pkg/context"
	"camlistore.org/pkg/syncutil"
	"camlistore.org/pkg/test"
)

func Test(t *testing.T, fn func(*testing.T) (sto blobserver.Storage, cleanup func())) {
	sto, cleanup := fn(t)
	defer func() {
		if t.Failed() {
			t.Logf("test %T FAILED, skipping cleanup!", sto)
		} else {
			cleanup()
		}
	}()
	t.Logf("Testing blobserver storage %T", sto)

	t.Logf("Testing Enumerate for empty")
	testEnumerate(t, sto, nil)

	var blobs []*test.Blob
	var blobRefs []blob.Ref
	var blobSizedRefs []blob.SizedRef

	contents := []string{"foo", "quux", "asdf", "qwerty", "0123456789"}
	if !testing.Short() {
		for i := 0; i < 95; i++ {
			contents = append(contents, "foo-"+strconv.Itoa(i))
		}
	}
	t.Logf("Testing receive")
	for _, x := range contents {
		b1 := &test.Blob{x}
		b1s, err := sto.ReceiveBlob(b1.BlobRef(), b1.Reader())
		if err != nil {
			t.Fatalf("ReceiveBlob of %s: %v", b1, err)
		}
		if b1s != b1.SizedRef() {
			t.Fatal("Received %v; want %v", b1s, b1.SizedRef())
		}
		blobs = append(blobs, b1)
		blobRefs = append(blobRefs, b1.BlobRef())
		blobSizedRefs = append(blobSizedRefs, b1.SizedRef())

		switch len(blobSizedRefs) {
		case 1, 5, 100:
			t.Logf("Testing Enumerate for %d blobs", len(blobSizedRefs))
			testEnumerate(t, sto, blobSizedRefs)
		}
	}
	b1 := blobs[0]

	// finish here if you want to examine the test directory
	//t.Fatalf("FINISH")

	t.Logf("Testing Fetch")
	for i, b2 := range blobs {
		rc, size, err := sto.Fetch(b2.BlobRef())
		if err != nil {
			t.Fatalf("error fetching %d. %s: %v", i, b2, err)
		}
		defer rc.Close()
		testSizedBlob(t, rc, b2.BlobRef(), int64(size))
	}

	t.Logf("Testing Stat")
	dest := make(chan blob.SizedRef)
	go func() {
		if err := sto.StatBlobs(dest, blobRefs); err != nil {
			t.Fatalf("error stating blobs %s: %v", blobRefs, err)
		}
	}()
	testStat(t, dest, blobSizedRefs)

	// Enumerate tests.
	sort.Sort(blob.SizedByRef(blobSizedRefs))

	t.Logf("Testing Enumerate on all")
	testEnumerate(t, sto, blobSizedRefs)

	t.Logf("Testing Enumerate 'limit' param")
	testEnumerate(t, sto, blobSizedRefs[:3], 3)

	// Enumerate 'after'
	{
		after := blobSizedRefs[2].Ref.String()
		t.Logf("Testing Enumerate 'after' param; after %q", after)
		testEnumerate(t, sto, blobSizedRefs[3:], after)
	}

	// Enumerate 'after' + limit
	{
		after := blobSizedRefs[2].Ref.String()
		t.Logf("Testing Enumerate 'after' + 'limit' param; after %q, limit 1", after)
		testEnumerate(t, sto, blobSizedRefs[3:4], after, 1)
	}

	// Enumerate 'after' with prefix of a blobref + limit
	{
		after := "a"
		t.Logf("Testing Enumerate 'after' + 'limit' param; after %q, limit 1", after)
		testEnumerate(t, sto, blobSizedRefs[:1], after, 1)
	}

	t.Logf("Testing Remove")
	if err := sto.RemoveBlobs(blobRefs); err != nil {
		if strings.Contains(err.Error(), "not implemented") {
			t.Logf("RemoveBlob %s: %v", b1, err)
		} else {
			t.Fatalf("RemoveBlob %s: %v", b1, err)
		}
	}
}

func testSizedBlob(t *testing.T, r io.Reader, b1 blob.Ref, size int64) {
	h := b1.Hash()
	n, err := io.Copy(h, r)
	if err != nil {
		t.Fatalf("error reading from %s: %v", r, err)
	}
	if n != size {
		t.Fatalf("read %d bytes from %s, metadata said %d!", n, size)
	}
	b2 := blob.RefFromHash(h)
	if b2 != b1 {
		t.Fatalf("content mismatch (awaited %s, got %s)", b1, b2)
	}
}

func CheckEnumerate(sto blobserver.Storage, wantUnsorted []blob.SizedRef, opts ...interface{}) error {
	var after string
	var n = 1000
	for _, opt := range opts {
		switch v := opt.(type) {
		case string:
			after = v
		case int:
			n = v
		default:
			panic("bad option of type " + fmt.Sprint("%T", v))
		}
	}

	want := append([]blob.SizedRef(nil), wantUnsorted...)
	sort.Sort(blob.SizedByRef(want))

	sbc := make(chan blob.SizedRef, 10)

	var got []blob.SizedRef
	var grp syncutil.Group
	sawEnd := make(chan bool, 1)
	grp.Go(func() error {
		if err := sto.EnumerateBlobs(context.New(), sbc, after, n); err != nil {
			return fmt.Errorf("EnumerateBlobs(%q, %d): %v", after, n, err)
		}
		return nil
	})
	grp.Go(func() error {
		for sb := range sbc {
			if !sb.Valid() {
				return fmt.Errorf("invalid blobref %#v received in enumerate", sb)
			}
			got = append(got, sb)
		}
		sawEnd <- true
		return nil

	})
	grp.Go(func() error {
		select {
		case <-sawEnd:
			return nil
		case <-time.After(10 * time.Second):
			return errors.New("timeout waiting for EnumerateBlobs to close its channel")
		}

	})
	if err := grp.Err(); err != nil {
		return fmt.Errorf("Enumerate error: %v", err)
	}
	if len(got) == 0 && len(want) == 0 {
		return nil
	}
	if !reflect.DeepEqual(got, want) {
		return fmt.Errorf("Enumerate mismatch. Got %d; want %d.\n Got: %v\nWant: %v\n",
			len(got), len(want), got, want)
	}
	return nil
}

func testEnumerate(t *testing.T, sto blobserver.Storage, wantUnsorted []blob.SizedRef, opts ...interface{}) {
	if err := CheckEnumerate(sto, wantUnsorted, opts...); err != nil {
		t.Fatalf("%v", err)
	}
}

func testStat(t *testing.T, enum <-chan blob.SizedRef, want []blob.SizedRef) {
	// blobs may arrive in ANY order
	m := make(map[string]int, len(want))
	for i, sb := range want {
		m[sb.Ref.String()] = i
	}

	i := 0
	for sb := range enum {
		if !sb.Valid() {
			break
		}
		wanted := want[m[sb.Ref.String()]]
		if wanted.Size != sb.Size {
			t.Fatalf("received blob size is %d, wanted %d for &%d", sb.Size, wanted.Size, i)
		}
		if wanted.Ref != sb.Ref {
			t.Fatalf("received blob ref mismatch &%d: wanted %s, got %s", i, sb.Ref, wanted.Ref)
		}
		i++
		if i >= len(want) {
			break
		}
	}
}
<commit_msg>pkg/blobserver/storagetest: Implement tests for blobserver.Salter.<commit_after>/*
Copyright 2013 The Camlistore Authors

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

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

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

// Package storagetest tests blobserver.Storage implementations
package storagetest

import (
	"bytes"
	"encoding/hex"
	"errors"
	"fmt"
	"io"
	"reflect"
	"sort"
	"strconv"
	"strings"
	"testing"
	"time"

	"camlistore.org/pkg/blob"
	"camlistore.org/pkg/blobserver"
	"camlistore.org/pkg/context"
	"camlistore.org/pkg/syncutil"
	"camlistore.org/pkg/test"
)

func Test(t *testing.T, fn func(*testing.T) (sto blobserver.Storage, cleanup func())) {
	sto, cleanup := fn(t)
	defer func() {
		if t.Failed() {
			t.Logf("test %T FAILED, skipping cleanup!", sto)
		} else {
			cleanup()
		}
	}()
	t.Logf("Testing blobserver storage %T", sto)

	t.Logf("Testing Enumerate for empty")
	testEnumerate(t, sto, nil)

	var blobs []*test.Blob
	var blobRefs []blob.Ref
	var blobSizedRefs []blob.SizedRef

	contents := []string{"foo", "quux", "asdf", "qwerty", "0123456789"}
	if !testing.Short() {
		for i := 0; i < 95; i++ {
			contents = append(contents, "foo-"+strconv.Itoa(i))
		}
	}
	t.Logf("Testing receive")
	for _, x := range contents {
		b1 := &test.Blob{x}
		b1s, err := sto.ReceiveBlob(b1.BlobRef(), b1.Reader())
		if err != nil {
			t.Fatalf("ReceiveBlob of %s: %v", b1, err)
		}
		if b1s != b1.SizedRef() {
			t.Fatal("Received %v; want %v", b1s, b1.SizedRef())
		}
		blobs = append(blobs, b1)
		blobRefs = append(blobRefs, b1.BlobRef())
		blobSizedRefs = append(blobSizedRefs, b1.SizedRef())

		switch len(blobSizedRefs) {
		case 1, 5, 100:
			t.Logf("Testing Enumerate for %d blobs", len(blobSizedRefs))
			testEnumerate(t, sto, blobSizedRefs)
		}
	}
	b1 := blobs[0]

	// finish here if you want to examine the test directory
	//t.Fatalf("FINISH")

	t.Logf("Testing Fetch")
	for i, b2 := range blobs {
		rc, size, err := sto.Fetch(b2.BlobRef())
		if err != nil {
			t.Fatalf("error fetching %d. %s: %v", i, b2, err)
		}
		defer rc.Close()
		testSizedBlob(t, rc, b2.BlobRef(), int64(size))
	}

	t.Logf("Testing Stat")
	dest := make(chan blob.SizedRef)
	go func() {
		if err := sto.StatBlobs(dest, blobRefs); err != nil {
			t.Fatalf("error stating blobs %s: %v", blobRefs, err)
		}
	}()
	testStat(t, dest, blobSizedRefs)

	// Enumerate tests.
	sort.Sort(blob.SizedByRef(blobSizedRefs))

	t.Logf("Testing Enumerate on all")
	testEnumerate(t, sto, blobSizedRefs)

	t.Logf("Testing Enumerate 'limit' param")
	testEnumerate(t, sto, blobSizedRefs[:3], 3)

	// Enumerate 'after'
	{
		after := blobSizedRefs[2].Ref.String()
		t.Logf("Testing Enumerate 'after' param; after %q", after)
		testEnumerate(t, sto, blobSizedRefs[3:], after)
	}

	// Enumerate 'after' + limit
	{
		after := blobSizedRefs[2].Ref.String()
		t.Logf("Testing Enumerate 'after' + 'limit' param; after %q, limit 1", after)
		testEnumerate(t, sto, blobSizedRefs[3:4], after, 1)
	}

	// Enumerate 'after' with prefix of a blobref + limit
	{
		after := "a"
		t.Logf("Testing Enumerate 'after' + 'limit' param; after %q, limit 1", after)
		testEnumerate(t, sto, blobSizedRefs[:1], after, 1)
	}

	t.Logf("Testing Remove")
	if err := sto.RemoveBlobs(blobRefs); err != nil {
		if strings.Contains(err.Error(), "not implemented") {
			t.Logf("RemoveBlob %s: %v", b1, err)
		} else {
			t.Fatalf("RemoveBlob %s: %v", b1, err)
		}
	}

	salter, ok := sto.(blobserver.Salter)
	if ok {
		t.Logf("Testing Salter Implementation")
		testSalter(t, salter)
	} else {
		t.Logf("Storage does not implement blobserver.Salter. Skipping testSalter()")
	}
}

func testSizedBlob(t *testing.T, r io.Reader, b1 blob.Ref, size int64) {
	h := b1.Hash()
	n, err := io.Copy(h, r)
	if err != nil {
		t.Fatalf("error reading from %s: %v", r, err)
	}
	if n != size {
		t.Fatalf("read %d bytes from %s, metadata said %d!", n, size)
	}
	b2 := blob.RefFromHash(h)
	if b2 != b1 {
		t.Fatalf("content mismatch (awaited %s, got %s)", b1, b2)
	}
}

func CheckEnumerate(sto blobserver.Storage, wantUnsorted []blob.SizedRef, opts ...interface{}) error {
	var after string
	var n = 1000
	for _, opt := range opts {
		switch v := opt.(type) {
		case string:
			after = v
		case int:
			n = v
		default:
			panic("bad option of type " + fmt.Sprint("%T", v))
		}
	}

	want := append([]blob.SizedRef(nil), wantUnsorted...)
	sort.Sort(blob.SizedByRef(want))

	sbc := make(chan blob.SizedRef, 10)

	var got []blob.SizedRef
	var grp syncutil.Group
	sawEnd := make(chan bool, 1)
	grp.Go(func() error {
		if err := sto.EnumerateBlobs(context.New(), sbc, after, n); err != nil {
			return fmt.Errorf("EnumerateBlobs(%q, %d): %v", after, n, err)
		}
		return nil
	})
	grp.Go(func() error {
		for sb := range sbc {
			if !sb.Valid() {
				return fmt.Errorf("invalid blobref %#v received in enumerate", sb)
			}
			got = append(got, sb)
		}
		sawEnd <- true
		return nil

	})
	grp.Go(func() error {
		select {
		case <-sawEnd:
			return nil
		case <-time.After(10 * time.Second):
			return errors.New("timeout waiting for EnumerateBlobs to close its channel")
		}

	})
	if err := grp.Err(); err != nil {
		return fmt.Errorf("Enumerate error: %v", err)
	}
	if len(got) == 0 && len(want) == 0 {
		return nil
	}
	if !reflect.DeepEqual(got, want) {
		return fmt.Errorf("Enumerate mismatch. Got %d; want %d.\n Got: %v\nWant: %v\n",
			len(got), len(want), got, want)
	}
	return nil
}

func testEnumerate(t *testing.T, sto blobserver.Storage, wantUnsorted []blob.SizedRef, opts ...interface{}) {
	if err := CheckEnumerate(sto, wantUnsorted, opts...); err != nil {
		t.Fatalf("%v", err)
	}
}

func testStat(t *testing.T, enum <-chan blob.SizedRef, want []blob.SizedRef) {
	// blobs may arrive in ANY order
	m := make(map[string]int, len(want))
	for i, sb := range want {
		m[sb.Ref.String()] = i
	}

	i := 0
	for sb := range enum {
		if !sb.Valid() {
			break
		}
		wanted := want[m[sb.Ref.String()]]
		if wanted.Size != sb.Size {
			t.Fatalf("received blob size is %d, wanted %d for &%d", sb.Size, wanted.Size, i)
		}
		if wanted.Ref != sb.Ref {
			t.Fatalf("received blob ref mismatch &%d: wanted %s, got %s", i, sb.Ref, wanted.Ref)
		}
		i++
		if i >= len(want) {
			break
		}
	}
}

func testSalter(t *testing.T, salter blobserver.Salter) {
	ok, err := salter.HasSalt()
	if err != nil {
		t.Errorf("blobserver.Salter.HasSalt(): %v", err)
		return
	}
	if ok {
		t.Errorf("blobserver.Salter.HasSalt(): Expected false, got true")
		return
	}

	data := "a967b8de7868db4513fbfd4eb9ce331f"
	salt, err := hex.DecodeString(data)
	if err != nil {
		t.Errorf("hex.DecodeString(): %v", err)
		return
	}

	err = salter.PutSalt(salt)
	if err != nil {
		t.Errorf("blobserver.Salter.PutSalt(): %v", err)
		return
	}

	got, err := salter.GetSalt()
	if err != nil {
		t.Errorf("blobserver.Salter.GetSalt(): %v", err)
		return
	}

	if !bytes.Equal(salt, got) {
		t.Errorf("blobserver.Salter.GetSalt(): Got salt different from put salt: Put %+v, Got: %+v", salt, got)
		return
	}

}
<|endoftext|>


<commit_before>package generate

import (
	"fmt"
	"io"
	"os"
	"strings"

	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	kcmdutil "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd/util"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util/errors"
	"github.com/fsouza/go-dockerclient"
	"github.com/golang/glog"
	"github.com/spf13/cobra"

	"github.com/openshift/origin/pkg/api/latest"
	osclient "github.com/openshift/origin/pkg/client"
	cmdutil "github.com/openshift/origin/pkg/cmd/util"
	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
	dh "github.com/openshift/origin/pkg/cmd/util/docker"
	"github.com/openshift/origin/pkg/dockerregistry"
	genapp "github.com/openshift/origin/pkg/generate/app"
	gen "github.com/openshift/origin/pkg/generate/generator"
	"github.com/openshift/origin/pkg/generate/source"
)

const longDescription = `
Experimental command

Generate configuration to build and deploy code in OpenShift from a source code
repository.

Docker builds - If a Dockerfile is present in the source code repository, then
a docker build is generated.

STI builds - If no builder image is specified as an argument, generate will detect
the type of source repository (JEE, Ruby, NodeJS) and associate a default builder
to it.

Services and Exposed Port - For Docker builds, generate looks for EXPOSE directives
in the Dockerfile to determine which port to expose. For STI builds, generate will
use the exposed port of the builder image. In either case, if a different port
needs to be exposed, use the --port flag to specify them. Services will be
generated using this port as well.

Usage:
openshift ex generate [source]

The source parameter may be a directory or a repository URL.
If not specified, the current directory is used.

Examples:

	# Find a git repository in the current directory and build artifacts based on detection
    $ openshift ex generate

    # Specify the directory for the repository to use
    $ openshift ex generate ./repo/dir

    # Use a remote git repository
    $ openshift ex generate https://github.com/openshift/ruby-hello-world.git

    # Force the application to use the specific builder-image
    $ openshift ex generate --builder-image=openshift/ruby-20-centos7
`

type params struct {
	name,
	sourceDir,
	sourceRef,
	sourceURL,
	dockerContext,
	builderImage,
	port string
	env cmdutil.Environment
}

func NewCmdGenerate(f *clientcmd.Factory, parentName, name string) *cobra.Command {
	dockerHelper := dh.NewHelper()
	input := params{}

	c := &cobra.Command{
		Use:   fmt.Sprintf("%s%s", name, clientcmd.ConfigSyntax),
		Short: "Generates an application configuration from a source repository",
		Long:  longDescription,
		Run: func(c *cobra.Command, args []string) {
			osClient, _, err := f.Clients(c)
			if err != nil {
				osClient = nil
			}
			dockerClient, _, err := dockerHelper.GetClient()
			if err != nil {
				osClient = nil
			}
			if len(args) == 1 {
				if genapp.IsRemoteRepository(args[0]) {
					input.sourceURL = args[0]
				} else {
					input.sourceDir = args[0]
				}
			}
			if len(input.sourceDir) == 0 && len(input.sourceURL) == 0 {
				if input.sourceDir, err = os.Getwd(); err != nil {
					exitWithError(err)
				}
			}
			if envParam := kcmdutil.GetFlagString(c, "environment"); len(envParam) > 0 {
				envVars := strings.Split(envParam, ",")
				env, _, errs := cmdutil.ParseEnvironmentArguments(envVars)
				if len(errs) > 0 {
					exitWithError(errors.NewAggregate(errs))
				}
				input.env = env
			}
			namespace, err := f.DefaultNamespace(c)
			if err != nil {
				namespace = ""
			}
			imageResolver := newImageResolver(namespace, osClient, dockerClient)

			if err = generateApp(input, imageResolver, os.Stdout); err != nil {
				exitWithError(err)
			}
		},
	}

	flag := c.Flags()
	flag.StringVar(&input.name, "name", "", "Set name to use for generated application artifacts")
	flag.StringVar(&input.sourceRef, "ref", "", "Set the name of the repository branch/ref to use")
	flag.StringVar(&input.sourceURL, "source-url", "", "Set the source URL")
	flag.StringVar(&input.dockerContext, "docker-context", "", "Context path for Dockerfile if creating a Docker build")
	flag.StringVar(&input.builderImage, "builder-image", "", "Image to use for STI build")
	flag.StringVarP(&input.port, "port", "p", "", "Port to expose on pod deployment")
	flag.StringP("environment", "e", "", "Comma-separated list of environment variables to add to the deployment. Should be in the form of var1=value1,var2=value2,...")
	dockerHelper.InstallFlags(flag)
	return c
}

func newImageResolver(namespace string, osClient osclient.Interface, dockerClient *docker.Client) genapp.Resolver {
	resolver := genapp.PerfectMatchWeightedResolver{}

	if dockerClient != nil {
		localDockerResolver := &genapp.DockerClientResolver{Client: dockerClient}
		resolver = append(resolver, genapp.WeightedResolver{localDockerResolver, 0.0})
	}

	if osClient != nil {
		namespaces := []string{}
		if len(namespace) > 0 {
			namespaces = append(namespaces, namespace)
		}
		namespaces = append(namespaces, "default")
		imageStreamResolver := &genapp.ImageStreamResolver{
			Client:     osClient,
			Images:     osClient,
			Namespaces: namespaces,
		}
		resolver = append(resolver, genapp.WeightedResolver{imageStreamResolver, 0.0})
	}

	dockerRegistryResolver := &genapp.DockerRegistryResolver{dockerregistry.NewClient()}
	resolver = append(resolver, genapp.WeightedResolver{dockerRegistryResolver, 0.0})

	return resolver
}

func generateSourceRef(url string, dir string, ref string, name string) (*genapp.SourceRef, error) {
	srcRefGen := gen.NewSourceRefGenerator()
	var result *genapp.SourceRef
	var err error
	if len(url) > 0 {
		glog.V(3).Infof("Generating source reference from URL: %s", url)
		if result, err = srcRefGen.FromGitURL(url); err != nil {
			return nil, err
		}
	} else {
		glog.V(3).Infof("Generating source reference from directory: %s", dir)
		if result, err = srcRefGen.FromDirectory(dir); err != nil {
			return nil, err
		}
	}
	if len(ref) > 0 {
		result.Ref = ref
	}
	if len(name) > 0 {
		result.Name = name
	}
	return result, nil
}

func generateBuildStrategyRef(srcRef *genapp.SourceRef, dockerContext string, builderImage string, resolver genapp.Resolver) (*genapp.BuildStrategyRef, error) {
	strategyRefGen := gen.NewBuildStrategyRefGenerator(source.DefaultDetectors, resolver)
	imageRefGen := gen.NewImageRefGenerator()
	if len(dockerContext) > 0 {
		glog.V(3).Infof("Generating build strategy reference using dockerContext: %s", dockerContext)
		return strategyRefGen.FromSourceRefAndDockerContext(*srcRef, dockerContext)
	} else if len(builderImage) > 0 {
		glog.V(3).Infof("Generating build strategy reference using builder image: %s", builderImage)
		builderRef, err := imageRefGen.FromNameAndResolver(builderImage, resolver)
		if err != nil {
			return nil, err
		}
		return strategyRefGen.FromSTIBuilderImage(builderRef)
	} else {
		glog.V(3).Infof("Detecting build strategy using source reference: %#v", srcRef)
		return strategyRefGen.FromSourceRef(*srcRef)
	}
}

func generateApp(input params, imageResolver genapp.Resolver, out io.Writer) error {
	// Get a SourceRef
	srcRef, err := generateSourceRef(input.sourceURL, input.sourceDir, input.sourceRef, input.name)
	if err != nil {
		return err
	}
	glog.V(2).Infof("Source reference: %#v", srcRef)

	// Get a BuildStrategyRef
	strategyRef, err := generateBuildStrategyRef(srcRef, input.dockerContext, input.builderImage, imageResolver)
	if err != nil {
		return err
	}
	glog.V(2).Infof("Generated build strategy reference: %#v", strategyRef)

	if len(input.port) > 0 {
		strategyRef.Base.Info.Config.ExposedPorts = map[string]struct{}{input.port: {}}
	}

	pipeline, err := genapp.NewBuildPipeline(srcRef.Name, strategyRef.Base, strategyRef, srcRef)
	if err != nil {
		return err
	}
	env := genapp.Environment{}
	for k, v := range input.env {
		env[k] = v
	}
	if err := pipeline.NeedsDeployment(env); err != nil {
		return err
	}

	objects, err := pipeline.Objects(genapp.NewAcceptFirst())
	if err != nil {
		return err
	}
	objects = genapp.AddServices(objects)
	list := &kapi.List{Items: objects}
	output, err := latest.Codec.Encode(list)
	if err != nil {
		return err
	}
	_, err = out.Write(output)
	return err
}

func exitWithError(err error) {
	fmt.Fprintf(os.Stderr, "Error: %v\n", err)
	os.Exit(1)
}
<commit_msg>Bug 1191960 - Remove --master from usage text for ex generate<commit_after>package generate

import (
	"fmt"
	"io"
	"os"
	"strings"

	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	kcmdutil "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd/util"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util/errors"
	"github.com/fsouza/go-dockerclient"
	"github.com/golang/glog"
	"github.com/spf13/cobra"

	"github.com/openshift/origin/pkg/api/latest"
	osclient "github.com/openshift/origin/pkg/client"
	cmdutil "github.com/openshift/origin/pkg/cmd/util"
	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
	dh "github.com/openshift/origin/pkg/cmd/util/docker"
	"github.com/openshift/origin/pkg/dockerregistry"
	genapp "github.com/openshift/origin/pkg/generate/app"
	gen "github.com/openshift/origin/pkg/generate/generator"
	"github.com/openshift/origin/pkg/generate/source"
)

const longDescription = `
Experimental command

Generate configuration to build and deploy code in OpenShift from a source code
repository.

Docker builds - If a Dockerfile is present in the source code repository, then
a docker build is generated.

STI builds - If no builder image is specified as an argument, generate will detect
the type of source repository (JEE, Ruby, NodeJS) and associate a default builder
to it.

Services and Exposed Port - For Docker builds, generate looks for EXPOSE directives
in the Dockerfile to determine which port to expose. For STI builds, generate will
use the exposed port of the builder image. In either case, if a different port
needs to be exposed, use the --port flag to specify them. Services will be
generated using this port as well.

Usage:
openshift ex generate [source]

The source parameter may be a directory or a repository URL.
If not specified, the current directory is used.

Examples:

	# Find a git repository in the current directory and build artifacts based on detection
    $ openshift ex generate

    # Specify the directory for the repository to use
    $ openshift ex generate ./repo/dir

    # Use a remote git repository
    $ openshift ex generate https://github.com/openshift/ruby-hello-world.git

    # Force the application to use the specific builder-image
    $ openshift ex generate --builder-image=openshift/ruby-20-centos7
`

type params struct {
	name,
	sourceDir,
	sourceRef,
	sourceURL,
	dockerContext,
	builderImage,
	port string
	env cmdutil.Environment
}

func NewCmdGenerate(f *clientcmd.Factory, parentName, name string) *cobra.Command {
	dockerHelper := dh.NewHelper()
	input := params{}

	c := &cobra.Command{
		Use:   fmt.Sprintf("%s [source]", name),
		Short: "Generates an application configuration from a source repository",
		Long:  longDescription,
		Run: func(c *cobra.Command, args []string) {
			osClient, _, err := f.Clients(c)
			if err != nil {
				osClient = nil
			}
			dockerClient, _, err := dockerHelper.GetClient()
			if err != nil {
				osClient = nil
			}
			if len(args) == 1 {
				if genapp.IsRemoteRepository(args[0]) {
					input.sourceURL = args[0]
				} else {
					input.sourceDir = args[0]
				}
			}
			if len(input.sourceDir) == 0 && len(input.sourceURL) == 0 {
				if input.sourceDir, err = os.Getwd(); err != nil {
					exitWithError(err)
				}
			}
			if envParam := kcmdutil.GetFlagString(c, "environment"); len(envParam) > 0 {
				envVars := strings.Split(envParam, ",")
				env, _, errs := cmdutil.ParseEnvironmentArguments(envVars)
				if len(errs) > 0 {
					exitWithError(errors.NewAggregate(errs))
				}
				input.env = env
			}
			namespace, err := f.DefaultNamespace(c)
			if err != nil {
				namespace = ""
			}
			imageResolver := newImageResolver(namespace, osClient, dockerClient)

			if err = generateApp(input, imageResolver, os.Stdout); err != nil {
				exitWithError(err)
			}
		},
	}

	flag := c.Flags()
	flag.StringVar(&input.name, "name", "", "Set name to use for generated application artifacts")
	flag.StringVar(&input.sourceRef, "ref", "", "Set the name of the repository branch/ref to use")
	flag.StringVar(&input.sourceURL, "source-url", "", "Set the source URL")
	flag.StringVar(&input.dockerContext, "docker-context", "", "Context path for Dockerfile if creating a Docker build")
	flag.StringVar(&input.builderImage, "builder-image", "", "Image to use for STI build")
	flag.StringVarP(&input.port, "port", "p", "", "Port to expose on pod deployment")
	flag.StringP("environment", "e", "", "Comma-separated list of environment variables to add to the deployment. Should be in the form of var1=value1,var2=value2,...")
	dockerHelper.InstallFlags(flag)
	return c
}

func newImageResolver(namespace string, osClient osclient.Interface, dockerClient *docker.Client) genapp.Resolver {
	resolver := genapp.PerfectMatchWeightedResolver{}

	if dockerClient != nil {
		localDockerResolver := &genapp.DockerClientResolver{Client: dockerClient}
		resolver = append(resolver, genapp.WeightedResolver{localDockerResolver, 0.0})
	}

	if osClient != nil {
		namespaces := []string{}
		if len(namespace) > 0 {
			namespaces = append(namespaces, namespace)
		}
		namespaces = append(namespaces, "default")
		imageStreamResolver := &genapp.ImageStreamResolver{
			Client:     osClient,
			Images:     osClient,
			Namespaces: namespaces,
		}
		resolver = append(resolver, genapp.WeightedResolver{imageStreamResolver, 0.0})
	}

	dockerRegistryResolver := &genapp.DockerRegistryResolver{dockerregistry.NewClient()}
	resolver = append(resolver, genapp.WeightedResolver{dockerRegistryResolver, 0.0})

	return resolver
}

func generateSourceRef(url string, dir string, ref string, name string) (*genapp.SourceRef, error) {
	srcRefGen := gen.NewSourceRefGenerator()
	var result *genapp.SourceRef
	var err error
	if len(url) > 0 {
		glog.V(3).Infof("Generating source reference from URL: %s", url)
		if result, err = srcRefGen.FromGitURL(url); err != nil {
			return nil, err
		}
	} else {
		glog.V(3).Infof("Generating source reference from directory: %s", dir)
		if result, err = srcRefGen.FromDirectory(dir); err != nil {
			return nil, err
		}
	}
	if len(ref) > 0 {
		result.Ref = ref
	}
	if len(name) > 0 {
		result.Name = name
	}
	return result, nil
}

func generateBuildStrategyRef(srcRef *genapp.SourceRef, dockerContext string, builderImage string, resolver genapp.Resolver) (*genapp.BuildStrategyRef, error) {
	strategyRefGen := gen.NewBuildStrategyRefGenerator(source.DefaultDetectors, resolver)
	imageRefGen := gen.NewImageRefGenerator()
	if len(dockerContext) > 0 {
		glog.V(3).Infof("Generating build strategy reference using dockerContext: %s", dockerContext)
		return strategyRefGen.FromSourceRefAndDockerContext(*srcRef, dockerContext)
	} else if len(builderImage) > 0 {
		glog.V(3).Infof("Generating build strategy reference using builder image: %s", builderImage)
		builderRef, err := imageRefGen.FromNameAndResolver(builderImage, resolver)
		if err != nil {
			return nil, err
		}
		return strategyRefGen.FromSTIBuilderImage(builderRef)
	} else {
		glog.V(3).Infof("Detecting build strategy using source reference: %#v", srcRef)
		return strategyRefGen.FromSourceRef(*srcRef)
	}
}

func generateApp(input params, imageResolver genapp.Resolver, out io.Writer) error {
	// Get a SourceRef
	srcRef, err := generateSourceRef(input.sourceURL, input.sourceDir, input.sourceRef, input.name)
	if err != nil {
		return err
	}
	glog.V(2).Infof("Source reference: %#v", srcRef)

	// Get a BuildStrategyRef
	strategyRef, err := generateBuildStrategyRef(srcRef, input.dockerContext, input.builderImage, imageResolver)
	if err != nil {
		return err
	}
	glog.V(2).Infof("Generated build strategy reference: %#v", strategyRef)

	if len(input.port) > 0 {
		strategyRef.Base.Info.Config.ExposedPorts = map[string]struct{}{input.port: {}}
	}

	pipeline, err := genapp.NewBuildPipeline(srcRef.Name, strategyRef.Base, strategyRef, srcRef)
	if err != nil {
		return err
	}
	env := genapp.Environment{}
	for k, v := range input.env {
		env[k] = v
	}
	if err := pipeline.NeedsDeployment(env); err != nil {
		return err
	}

	objects, err := pipeline.Objects(genapp.NewAcceptFirst())
	if err != nil {
		return err
	}
	objects = genapp.AddServices(objects)
	list := &kapi.List{Items: objects}
	output, err := latest.Codec.Encode(list)
	if err != nil {
		return err
	}
	_, err = out.Write(output)
	return err
}

func exitWithError(err error) {
	fmt.Fprintf(os.Stderr, "Error: %v\n", err)
	os.Exit(1)
}
<|endoftext|>


<commit_before>package twitter

import (
	"fmt"
	"net/http"

	"github.com/dghubble/sling"
)

// Tweet represents a Twitter Tweet, previously called a status.
// https://dev.twitter.com/overview/api/tweets
// Unused or deprecated fields not provided: Geo, Annotations
// TODO: Place
type Tweet struct {
	Contributors         []Contributor     `json:"contributors"`
	Coordinates          *Coordinates      `json:"coordinates"`
	CreatedAt            string            `json:"created_at"`
	CurrentUserRetweet   *TweetIdentifier  `json:"current_user_retweet"`
	Entities             *Entities         `json:"entities"`
	FavoriteCount        int               `json:"favorite_count"`
	Favorited            bool              `json:"favorited"`
	FilterLevel          string            `json:"filter_level"`
	ID                   int64             `json:"id"`
	IDStr                string            `json:"id_str"`
	InReplyToScreenName  string            `json:"in_reply_to_screen_name"`
	InReplyToStatusID    int64             `json:"in_reply_to_status_id"`
	InReplyToStatusIDStr string            `json:"in_reply_to_status_id_str"`
	InReplyToUserID      int64             `json:"in_reply_to_user_id"`
	InReplyToUserIDStr   string            `json:"in_reply_to_user_id_str"`
	Lang                 string            `json:"lang"`
	PossiblySensitive    bool              `json:"possibly_sensitive"`
	RetweetCount         int               `json:"retweet_count"`
	Retweeted            bool              `json:"retweeted"`
	RetweetedStatus      *Tweet            `json:"retweeted_status"`
	Source               string            `json:"source"`
	Scopes               map[string]string `json:"scopes"`
	Text                 string            `json:"text"`
	Truncated            bool              `json:"truncated"`
	User                 *User             `json:"user"`
	WithheldCopyright    bool              `json:"withheld_copyright"`
	WithheldInCountries  []string          `json:"withheld_in_countries"`
	WithheldScope        string            `json:"withheld_scope"`
	ExtendedEntities     *ExtendedEntity   `json:"extended_entities"`
	QuotedStatusID       int64             `json:"quoted_status_id"`
	QuotedStatusIDStr    string            `json:"quoted_status_id_str"`
	QuotedStatus         *Tweet            `json:"quoted_status"`
}

// Contributor represents a brief summary of a User identifiers.
type Contributor struct {
	ID         int64  `json:"id"`
	IDStr      string `json:"id_str"`
	ScreenName string `json:"screen_name"`
}

// Coordinates are pairs of longitude and latitude locations.
type Coordinates struct {
	Coordinates [2]float64 `json:"coordinates"`
	Type        string     `json:"type"`
}

// TweetIdentifier represents the id by which a Tweet can be identified.
type TweetIdentifier struct {
	ID    int64  `json:"id"`
	IDStr string `json:"id_str"`
}

// StatusService provides methods for accessing Twitter status API endpoints.
type StatusService struct {
	sling *sling.Sling
}

// newStatusService returns a new StatusService.
func newStatusService(sling *sling.Sling) *StatusService {
	return &StatusService{
		sling: sling.Path("statuses/"),
	}
}

// StatusShowParams are the parameters for StatusService.Show
type StatusShowParams struct {
	ID               int64 `url:"id,omitempty"`
	TrimUser         *bool `url:"trim_user,omitempty"`
	IncludeMyRetweet *bool `url:"include_my_retweet,omitempty"`
	IncludeEntities  *bool `url:"include_entities,omitempty"`
}

// Show returns the requested Tweet.
// https://dev.twitter.com/rest/reference/get/statuses/show/%3Aid
func (s *StatusService) Show(id int64, params *StatusShowParams) (*Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusShowParams{}
	}
	params.ID = id
	tweet := new(Tweet)
	apiError := new(APIError)
	resp, err := s.sling.New().Get("show.json").QueryStruct(params).Receive(tweet, apiError)
	return tweet, resp, relevantError(err, *apiError)
}

// StatusLookupParams are the parameters for StatusService.Lookup
type StatusLookupParams struct {
	ID              []int64 `url:"id,omitempty,comma"`
	TrimUser        *bool   `url:"trim_user,omitempty"`
	IncludeEntities *bool   `url:"include_entities,omitempty"`
	Map             *bool   `url:"map,omitempty"`
}

// Lookup returns the requested Tweets as a slice. Combines ids from the
// required ids argument and from params.Id.
// https://dev.twitter.com/rest/reference/get/statuses/lookup
func (s *StatusService) Lookup(ids []int64, params *StatusLookupParams) ([]Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusLookupParams{}
	}
	params.ID = append(params.ID, ids...)
	tweets := new([]Tweet)
	apiError := new(APIError)
	resp, err := s.sling.New().Get("lookup.json").QueryStruct(params).Receive(tweets, apiError)
	return *tweets, resp, relevantError(err, *apiError)
}

// StatusUpdateParams are the parameters for StatusService.Update
type StatusUpdateParams struct {
	Status             string   `url:"status,omitempty"`
	InReplyToStatusID  int64    `url:"in_reply_to_status_id,omitempty"`
	PossiblySensitive  *bool    `url:"possibly_sensitive,omitempty"`
	Lat                *float64 `url:"lat,omitempty"`
	Long               *float64 `url:"long,omitempty"`
	PlaceID            string   `url:"place_id,omitempty"`
	DisplayCoordinates *bool    `url:"display_coordinates,omitempty"`
	TrimUser           *bool    `url:"trim_user,omitempty"`
	MediaIds           []int64  `url:"media_ids,omitempty,comma"`
}

// Update updates the user's status, also known as Tweeting.
// Requires a user auth context.
// https://dev.twitter.com/rest/reference/post/statuses/update
func (s *StatusService) Update(status string, params *StatusUpdateParams) (*Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusUpdateParams{}
	}
	params.Status = status
	tweet := new(Tweet)
	apiError := new(APIError)
	resp, err := s.sling.New().Post("update.json").BodyForm(params).Receive(tweet, apiError)
	return tweet, resp, relevantError(err, *apiError)
}

// StatusRetweetParams are the parameters for StatusService.Retweet
type StatusRetweetParams struct {
	ID       int64 `url:"id,omitempty"`
	TrimUser *bool `url:"trim_user,omitempty"`
}

// Retweet retweets the Tweet with the given id and returns the original Tweet
// with embedded retweet details.
// Requires a user auth context.
// https://dev.twitter.com/rest/reference/post/statuses/retweet/%3Aid
func (s *StatusService) Retweet(id int64, params *StatusRetweetParams) (*Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusRetweetParams{}
	}
	params.ID = id
	tweet := new(Tweet)
	apiError := new(APIError)
	path := fmt.Sprintf("retweet/%d.json", params.ID)
	resp, err := s.sling.New().Post(path).BodyForm(params).Receive(tweet, apiError)
	return tweet, resp, relevantError(err, *apiError)
}

// StatusDestroyParams are the parameters for StatusService.Destroy
type StatusDestroyParams struct {
	ID       int64 `url:"id,omitempty"`
	TrimUser *bool `url:"trim_user,omitempty"`
}

// Destroy deletes the Tweet with the given id and returns it if successful.
// Requires a user auth context.
// https://dev.twitter.com/rest/reference/post/statuses/destroy/%3Aid
func (s *StatusService) Destroy(id int64, params *StatusDestroyParams) (*Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusDestroyParams{}
	}
	params.ID = id
	tweet := new(Tweet)
	apiError := new(APIError)
	path := fmt.Sprintf("destroy/%d.json", params.ID)
	resp, err := s.sling.New().Post(path).BodyForm(params).Receive(tweet, apiError)
	return tweet, resp, relevantError(err, *apiError)
}
<commit_msg>Add support for statuses/oembed endpoint<commit_after>package twitter

import (
	"fmt"
	"net/http"

	"github.com/dghubble/sling"
)

// Tweet represents a Twitter Tweet, previously called a status.
// https://dev.twitter.com/overview/api/tweets
// Unused or deprecated fields not provided: Geo, Annotations
// TODO: Place
type Tweet struct {
	Contributors         []Contributor     `json:"contributors"`
	Coordinates          *Coordinates      `json:"coordinates"`
	CreatedAt            string            `json:"created_at"`
	CurrentUserRetweet   *TweetIdentifier  `json:"current_user_retweet"`
	Entities             *Entities         `json:"entities"`
	FavoriteCount        int               `json:"favorite_count"`
	Favorited            bool              `json:"favorited"`
	FilterLevel          string            `json:"filter_level"`
	ID                   int64             `json:"id"`
	IDStr                string            `json:"id_str"`
	InReplyToScreenName  string            `json:"in_reply_to_screen_name"`
	InReplyToStatusID    int64             `json:"in_reply_to_status_id"`
	InReplyToStatusIDStr string            `json:"in_reply_to_status_id_str"`
	InReplyToUserID      int64             `json:"in_reply_to_user_id"`
	InReplyToUserIDStr   string            `json:"in_reply_to_user_id_str"`
	Lang                 string            `json:"lang"`
	PossiblySensitive    bool              `json:"possibly_sensitive"`
	RetweetCount         int               `json:"retweet_count"`
	Retweeted            bool              `json:"retweeted"`
	RetweetedStatus      *Tweet            `json:"retweeted_status"`
	Source               string            `json:"source"`
	Scopes               map[string]string `json:"scopes"`
	Text                 string            `json:"text"`
	Truncated            bool              `json:"truncated"`
	User                 *User             `json:"user"`
	WithheldCopyright    bool              `json:"withheld_copyright"`
	WithheldInCountries  []string          `json:"withheld_in_countries"`
	WithheldScope        string            `json:"withheld_scope"`
	ExtendedEntities     *ExtendedEntity   `json:"extended_entities"`
	QuotedStatusID       int64             `json:"quoted_status_id"`
	QuotedStatusIDStr    string            `json:"quoted_status_id_str"`
	QuotedStatus         *Tweet            `json:"quoted_status"`
}

// Contributor represents a brief summary of a User identifiers.
type Contributor struct {
	ID         int64  `json:"id"`
	IDStr      string `json:"id_str"`
	ScreenName string `json:"screen_name"`
}

// Coordinates are pairs of longitude and latitude locations.
type Coordinates struct {
	Coordinates [2]float64 `json:"coordinates"`
	Type        string     `json:"type"`
}

// TweetIdentifier represents the id by which a Tweet can be identified.
type TweetIdentifier struct {
	ID    int64  `json:"id"`
	IDStr string `json:"id_str"`
}

// StatusService provides methods for accessing Twitter status API endpoints.
type StatusService struct {
	sling *sling.Sling
}

// newStatusService returns a new StatusService.
func newStatusService(sling *sling.Sling) *StatusService {
	return &StatusService{
		sling: sling.Path("statuses/"),
	}
}

// StatusShowParams are the parameters for StatusService.Show
type StatusShowParams struct {
	ID               int64 `url:"id,omitempty"`
	TrimUser         *bool `url:"trim_user,omitempty"`
	IncludeMyRetweet *bool `url:"include_my_retweet,omitempty"`
	IncludeEntities  *bool `url:"include_entities,omitempty"`
}

// Show returns the requested Tweet.
// https://dev.twitter.com/rest/reference/get/statuses/show/%3Aid
func (s *StatusService) Show(id int64, params *StatusShowParams) (*Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusShowParams{}
	}
	params.ID = id
	tweet := new(Tweet)
	apiError := new(APIError)
	resp, err := s.sling.New().Get("show.json").QueryStruct(params).Receive(tweet, apiError)
	return tweet, resp, relevantError(err, *apiError)
}

// StatusLookupParams are the parameters for StatusService.Lookup
type StatusLookupParams struct {
	ID              []int64 `url:"id,omitempty,comma"`
	TrimUser        *bool   `url:"trim_user,omitempty"`
	IncludeEntities *bool   `url:"include_entities,omitempty"`
	Map             *bool   `url:"map,omitempty"`
}

// Lookup returns the requested Tweets as a slice. Combines ids from the
// required ids argument and from params.Id.
// https://dev.twitter.com/rest/reference/get/statuses/lookup
func (s *StatusService) Lookup(ids []int64, params *StatusLookupParams) ([]Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusLookupParams{}
	}
	params.ID = append(params.ID, ids...)
	tweets := new([]Tweet)
	apiError := new(APIError)
	resp, err := s.sling.New().Get("lookup.json").QueryStruct(params).Receive(tweets, apiError)
	return *tweets, resp, relevantError(err, *apiError)
}

// StatusUpdateParams are the parameters for StatusService.Update
type StatusUpdateParams struct {
	Status             string   `url:"status,omitempty"`
	InReplyToStatusID  int64    `url:"in_reply_to_status_id,omitempty"`
	PossiblySensitive  *bool    `url:"possibly_sensitive,omitempty"`
	Lat                *float64 `url:"lat,omitempty"`
	Long               *float64 `url:"long,omitempty"`
	PlaceID            string   `url:"place_id,omitempty"`
	DisplayCoordinates *bool    `url:"display_coordinates,omitempty"`
	TrimUser           *bool    `url:"trim_user,omitempty"`
	MediaIds           []int64  `url:"media_ids,omitempty,comma"`
}

// Update updates the user's status, also known as Tweeting.
// Requires a user auth context.
// https://dev.twitter.com/rest/reference/post/statuses/update
func (s *StatusService) Update(status string, params *StatusUpdateParams) (*Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusUpdateParams{}
	}
	params.Status = status
	tweet := new(Tweet)
	apiError := new(APIError)
	resp, err := s.sling.New().Post("update.json").BodyForm(params).Receive(tweet, apiError)
	return tweet, resp, relevantError(err, *apiError)
}

// StatusRetweetParams are the parameters for StatusService.Retweet
type StatusRetweetParams struct {
	ID       int64 `url:"id,omitempty"`
	TrimUser *bool `url:"trim_user,omitempty"`
}

// Retweet retweets the Tweet with the given id and returns the original Tweet
// with embedded retweet details.
// Requires a user auth context.
// https://dev.twitter.com/rest/reference/post/statuses/retweet/%3Aid
func (s *StatusService) Retweet(id int64, params *StatusRetweetParams) (*Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusRetweetParams{}
	}
	params.ID = id
	tweet := new(Tweet)
	apiError := new(APIError)
	path := fmt.Sprintf("retweet/%d.json", params.ID)
	resp, err := s.sling.New().Post(path).BodyForm(params).Receive(tweet, apiError)
	return tweet, resp, relevantError(err, *apiError)
}

// StatusDestroyParams are the parameters for StatusService.Destroy
type StatusDestroyParams struct {
	ID       int64 `url:"id,omitempty"`
	TrimUser *bool `url:"trim_user,omitempty"`
}

// Destroy deletes the Tweet with the given id and returns it if successful.
// Requires a user auth context.
// https://dev.twitter.com/rest/reference/post/statuses/destroy/%3Aid
func (s *StatusService) Destroy(id int64, params *StatusDestroyParams) (*Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusDestroyParams{}
	}
	params.ID = id
	tweet := new(Tweet)
	apiError := new(APIError)
	path := fmt.Sprintf("destroy/%d.json", params.ID)
	resp, err := s.sling.New().Post(path).BodyForm(params).Receive(tweet, apiError)
	return tweet, resp, relevantError(err, *apiError)
}

// OEmbedTweet represents a Tweet in oEmbed format.
type OEmbedTweet struct {
	URL          string `json:"url"`
	ProviderURL  string `json:"provider_url"`
	ProviderName string `json:"provider_name"`
	AuthorName   string `json:"author_name"`
	Version      string `json:"version"`
	AuthorURL    string `json:"author_url"`
	Type         string `json:"type"`
	HTML         string `json:"html"`
	Height       int64  `json:"height"`
	Width        int64  `json:"width"`
}

// StatusOEmbedParams are the parameters for StatusService.OEmbed
type StatusOEmbedParams struct {
	ID       int64 `url:"id,omitempty"`
	maxWidth int64 `url:"maxwidth,omitempty"`
}

// OEmbed returns the requested Tweet in oEmbed format.
// Requires a user auth context.
// https://dev.twitter.com/rest/reference/get/statuses/oembed
func (s *StatusService) OEmbed(id int64, params *StatusOEmbedParams) (*OEmbedTweet, *http.Response, error) {
	if params == nil {
		params = &StatusOEmbedParams{}
	}
	params.ID = id
	oEmbedTweet := new(OEmbedTweet)
	apiError := new(APIError)
	resp, err := s.sling.New().Get("oembed.json").QueryStruct(params).Receive(oEmbedTweet, apiError)
	return oEmbedTweet, resp, relevantError(err, *apiError)
}
<|endoftext|>


<commit_before>package twitter

import (
	"fmt"
	"net/http"
	"time"

	"github.com/dghubble/sling"
)

// Tweet represents a Twitter Tweet, previously called a status.
// https://dev.twitter.com/overview/api/tweets
type Tweet struct {
	Coordinates          *Coordinates           `json:"coordinates"`
	CreatedAt            string                 `json:"created_at"`
	CurrentUserRetweet   *TweetIdentifier       `json:"current_user_retweet"`
	Entities             *Entities              `json:"entities"`
	FavoriteCount        int                    `json:"favorite_count"`
	Favorited            bool                   `json:"favorited"`
	FilterLevel          string                 `json:"filter_level"`
	ID                   int64                  `json:"id"`
	IDStr                string                 `json:"id_str"`
	InReplyToScreenName  string                 `json:"in_reply_to_screen_name"`
	InReplyToStatusID    int64                  `json:"in_reply_to_status_id"`
	InReplyToStatusIDStr string                 `json:"in_reply_to_status_id_str"`
	InReplyToUserID      int64                  `json:"in_reply_to_user_id"`
	InReplyToUserIDStr   string                 `json:"in_reply_to_user_id_str"`
	Lang                 string                 `json:"lang"`
	PossiblySensitive    bool                   `json:"possibly_sensitive"`
	QuoteCount           int                    `json:"quote_count"`
	ReplyCount           int                    `json:"reply_count"`
	RetweetCount         int                    `json:"retweet_count"`
	Retweeted            bool                   `json:"retweeted"`
	RetweetedStatus      *Tweet                 `json:"retweeted_status"`
	Source               string                 `json:"source"`
	Scopes               map[string]interface{} `json:"scopes"`
	Text                 string                 `json:"text"`
	FullText             string                 `json:"full_text"`
	DisplayTextRange     Indices                `json:"display_text_range"`
	Place                *Place                 `json:"place"`
	Truncated            bool                   `json:"truncated"`
	User                 *User                  `json:"user"`
	WithheldCopyright    bool                   `json:"withheld_copyright"`
	WithheldInCountries  []string               `json:"withheld_in_countries"`
	WithheldScope        string                 `json:"withheld_scope"`
	ExtendedEntities     *ExtendedEntity        `json:"extended_entities"`
	ExtendedTweet        *ExtendedTweet         `json:"extended_tweet"`
	QuotedStatusID       int64                  `json:"quoted_status_id"`
	QuotedStatusIDStr    string                 `json:"quoted_status_id_str"`
	QuotedStatus         *Tweet                 `json:"quoted_status"`
}

// CreatedAtTime returns the time a tweet was created.
func (t Tweet) CreatedAtTime() (time.Time, error) {
	return time.Parse(time.RubyDate, t.CreatedAt)
}

// ExtendedTweet represents fields embedded in extended Tweets when served in
// compatibility mode (default).
// https://dev.twitter.com/overview/api/upcoming-changes-to-tweets
type ExtendedTweet struct {
	FullText         string          `json:"full_text"`
	DisplayTextRange Indices         `json:"display_text_range"`
	Entities         *Entities       `json:"entities"`
	ExtendedEntities *ExtendedEntity `json:"extended_entities"`
}

// Place represents a Twitter Place / Location
// https://dev.twitter.com/overview/api/places
type Place struct {
	Attributes  map[string]string `json:"attributes"`
	BoundingBox *BoundingBox      `json:"bounding_box"`
	Country     string            `json:"country"`
	CountryCode string            `json:"country_code"`
	FullName    string            `json:"full_name"`
	Geometry    *BoundingBox      `json:"geometry"`
	ID          string            `json:"id"`
	Name        string            `json:"name"`
	PlaceType   string            `json:"place_type"`
	Polylines   []string          `json:"polylines"`
	URL         string            `json:"url"`
}

// BoundingBox represents the bounding coordinates (longitude, latitutde)
// defining the bounds of a box containing a Place entity.
type BoundingBox struct {
	Coordinates [][][2]float64 `json:"coordinates"`
	Type        string         `json:"type"`
}

// Coordinates are pairs of longitude and latitude locations.
type Coordinates struct {
	Coordinates [2]float64 `json:"coordinates"`
	Type        string     `json:"type"`
}

// TweetIdentifier represents the id by which a Tweet can be identified.
type TweetIdentifier struct {
	ID    int64  `json:"id"`
	IDStr string `json:"id_str"`
}

// StatusService provides methods for accessing Twitter status API endpoints.
type StatusService struct {
	sling *sling.Sling
}

// newStatusService returns a new StatusService.
func newStatusService(sling *sling.Sling) *StatusService {
	return &StatusService{
		sling: sling.Path("statuses/"),
	}
}

// StatusShowParams are the parameters for StatusService.Show
type StatusShowParams struct {
	ID               int64  `url:"id,omitempty"`
	TrimUser         *bool  `url:"trim_user,omitempty"`
	IncludeMyRetweet *bool  `url:"include_my_retweet,omitempty"`
	IncludeEntities  *bool  `url:"include_entities,omitempty"`
	TweetMode        string `url:"tweet_mode,omitempty"`
}

// Show returns the requested Tweet.
// https://developer.twitter.com/en/docs/twitter-api/v1/tweets/post-and-engage/api-reference/get-statuses-show-id
func (s *StatusService) Show(id int64, params *StatusShowParams) (*Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusShowParams{}
	}
	params.ID = id
	tweet := new(Tweet)
	apiError := new(APIError)
	resp, err := s.sling.New().Get("show.json").QueryStruct(params).Receive(tweet, apiError)
	return tweet, resp, relevantError(err, *apiError)
}

// StatusLookupParams are the parameters for StatusService.Lookup
type StatusLookupParams struct {
	ID              []int64 `url:"id,omitempty,comma"`
	TrimUser        *bool   `url:"trim_user,omitempty"`
	IncludeEntities *bool   `url:"include_entities,omitempty"`
	Map             *bool   `url:"map,omitempty"`
	TweetMode       string  `url:"tweet_mode,omitempty"`
}

// Lookup returns the requested Tweets as a slice. Combines ids from the
// required ids argument and from params.Id.
// https://developer.twitter.com/en/docs/twitter-api/v1/tweets/post-and-engage/api-reference/get-statuses-lookup
func (s *StatusService) Lookup(ids []int64, params *StatusLookupParams) ([]Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusLookupParams{}
	}
	params.ID = append(params.ID, ids...)
	tweets := new([]Tweet)
	apiError := new(APIError)
	resp, err := s.sling.New().Get("lookup.json").QueryStruct(params).Receive(tweets, apiError)
	return *tweets, resp, relevantError(err, *apiError)
}

// StatusUpdateParams are the parameters for StatusService.Update
type StatusUpdateParams struct {
	Status             string   `url:"status,omitempty"`
	InReplyToStatusID  int64    `url:"in_reply_to_status_id,omitempty"`
	PossiblySensitive  *bool    `url:"possibly_sensitive,omitempty"`
	Lat                *float64 `url:"lat,omitempty"`
	Long               *float64 `url:"long,omitempty"`
	PlaceID            string   `url:"place_id,omitempty"`
	DisplayCoordinates *bool    `url:"display_coordinates,omitempty"`
	TrimUser           *bool    `url:"trim_user,omitempty"`
	MediaIds           []int64  `url:"media_ids,omitempty,comma"`
	TweetMode          string   `url:"tweet_mode,omitempty"`
}

// Update updates the user's status, also known as Tweeting.
// Requires a user auth context.
// https://developer.twitter.com/en/docs/twitter-api/v1/tweets/post-and-engage/api-reference/post-statuses-update
func (s *StatusService) Update(status string, params *StatusUpdateParams) (*Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusUpdateParams{}
	}
	params.Status = status
	tweet := new(Tweet)
	apiError := new(APIError)
	resp, err := s.sling.New().Post("update.json").BodyForm(params).Receive(tweet, apiError)
	return tweet, resp, relevantError(err, *apiError)
}

// StatusRetweetParams are the parameters for StatusService.Retweet
type StatusRetweetParams struct {
	ID        int64  `url:"id,omitempty"`
	TrimUser  *bool  `url:"trim_user,omitempty"`
	TweetMode string `url:"tweet_mode,omitempty"`
}

// Retweet retweets the Tweet with the given id and returns the original Tweet
// with embedded retweet details.
// Requires a user auth context.
// https://developer.twitter.com/en/docs/twitter-api/v1/tweets/post-and-engage/api-reference/post-statuses-retweet-id
func (s *StatusService) Retweet(id int64, params *StatusRetweetParams) (*Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusRetweetParams{}
	}
	params.ID = id
	tweet := new(Tweet)
	apiError := new(APIError)
	path := fmt.Sprintf("retweet/%d.json", params.ID)
	resp, err := s.sling.New().Post(path).BodyForm(params).Receive(tweet, apiError)
	return tweet, resp, relevantError(err, *apiError)
}

// StatusUnretweetParams are the parameters for StatusService.Unretweet
type StatusUnretweetParams struct {
	ID        int64  `url:"id,omitempty"`
	TrimUser  *bool  `url:"trim_user,omitempty"`
	TweetMode string `url:"tweet_mode,omitempty"`
}

// Unretweet unretweets the Tweet with the given id and returns the original Tweet.
// Requires a user auth context.
// https://developer.twitter.com/en/docs/twitter-api/v1/tweets/post-and-engage/api-reference/post-statuses-unretweet-id
func (s *StatusService) Unretweet(id int64, params *StatusUnretweetParams) (*Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusUnretweetParams{}
	}
	params.ID = id
	tweet := new(Tweet)
	apiError := new(APIError)
	path := fmt.Sprintf("unretweet/%d.json", params.ID)
	resp, err := s.sling.New().Post(path).BodyForm(params).Receive(tweet, apiError)
	return tweet, resp, relevantError(err, *apiError)
}

// StatusRetweetsParams are the parameters for StatusService.Retweets
type StatusRetweetsParams struct {
	ID        int64  `url:"id,omitempty"`
	Count     int    `url:"count,omitempty"`
	TrimUser  *bool  `url:"trim_user,omitempty"`
	TweetMode string `url:"tweet_mode,omitempty"`
}

// Retweets returns the most recent retweets of the Tweet with the given id.
// https://developer.twitter.com/en/docs/twitter-api/v1/tweets/post-and-engage/api-reference/get-statuses-retweets-id
func (s *StatusService) Retweets(id int64, params *StatusRetweetsParams) ([]Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusRetweetsParams{}
	}
	params.ID = id
	tweets := new([]Tweet)
	apiError := new(APIError)
	path := fmt.Sprintf("retweets/%d.json", params.ID)
	resp, err := s.sling.New().Get(path).QueryStruct(params).Receive(tweets, apiError)
	return *tweets, resp, relevantError(err, *apiError)
}

// StatusDestroyParams are the parameters for StatusService.Destroy
type StatusDestroyParams struct {
	ID        int64  `url:"id,omitempty"`
	TrimUser  *bool  `url:"trim_user,omitempty"`
	TweetMode string `url:"tweet_mode,omitempty"`
}

// Destroy deletes the Tweet with the given id and returns it if successful.
// Requires a user auth context.
// https://developer.twitter.com/en/docs/twitter-api/v1/tweets/post-and-engage/api-reference/post-favorites-destroy
func (s *StatusService) Destroy(id int64, params *StatusDestroyParams) (*Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusDestroyParams{}
	}
	params.ID = id
	tweet := new(Tweet)
	apiError := new(APIError)
	path := fmt.Sprintf("destroy/%d.json", params.ID)
	resp, err := s.sling.New().Post(path).BodyForm(params).Receive(tweet, apiError)
	return tweet, resp, relevantError(err, *apiError)
}

// OEmbedTweet represents a Tweet in oEmbed format.
type OEmbedTweet struct {
	URL          string `json:"url"`
	ProviderURL  string `json:"provider_url"`
	ProviderName string `json:"provider_name"`
	AuthorName   string `json:"author_name"`
	Version      string `json:"version"`
	AuthorURL    string `json:"author_url"`
	Type         string `json:"type"`
	HTML         string `json:"html"`
	Height       int64  `json:"height"`
	Width        int64  `json:"width"`
	CacheAge     string `json:"cache_age"`
}

// StatusOEmbedParams are the parameters for StatusService.OEmbed
type StatusOEmbedParams struct {
	ID         int64  `url:"id,omitempty"`
	URL        string `url:"url,omitempty"`
	Align      string `url:"align,omitempty"`
	MaxWidth   int64  `url:"maxwidth,omitempty"`
	HideMedia  *bool  `url:"hide_media,omitempty"`
	HideThread *bool  `url:"hide_media,omitempty"`
	OmitScript *bool  `url:"hide_media,omitempty"`
	WidgetType string `url:"widget_type,omitempty"`
	HideTweet  *bool  `url:"hide_tweet,omitempty"`
}

// OEmbed returns the requested Tweet in oEmbed format.
// https://developer.twitter.com/en/docs/twitter-api/v1/tweets/post-and-engage/api-reference/get-statuses-oembed
func (s *StatusService) OEmbed(params *StatusOEmbedParams) (*OEmbedTweet, *http.Response, error) {
	oEmbedTweet := new(OEmbedTweet)
	apiError := new(APIError)
	resp, err := s.sling.New().Get("oembed.json").QueryStruct(params).Receive(oEmbedTweet, apiError)
	return oEmbedTweet, resp, relevantError(err, *apiError)
}
<commit_msg>Add AutoPopulateReplyMetadata *bool to StatusUpdateParams (#186)<commit_after>package twitter

import (
	"fmt"
	"net/http"
	"time"

	"github.com/dghubble/sling"
)

// Tweet represents a Twitter Tweet, previously called a status.
// https://dev.twitter.com/overview/api/tweets
type Tweet struct {
	Coordinates          *Coordinates           `json:"coordinates"`
	CreatedAt            string                 `json:"created_at"`
	CurrentUserRetweet   *TweetIdentifier       `json:"current_user_retweet"`
	Entities             *Entities              `json:"entities"`
	FavoriteCount        int                    `json:"favorite_count"`
	Favorited            bool                   `json:"favorited"`
	FilterLevel          string                 `json:"filter_level"`
	ID                   int64                  `json:"id"`
	IDStr                string                 `json:"id_str"`
	InReplyToScreenName  string                 `json:"in_reply_to_screen_name"`
	InReplyToStatusID    int64                  `json:"in_reply_to_status_id"`
	InReplyToStatusIDStr string                 `json:"in_reply_to_status_id_str"`
	InReplyToUserID      int64                  `json:"in_reply_to_user_id"`
	InReplyToUserIDStr   string                 `json:"in_reply_to_user_id_str"`
	Lang                 string                 `json:"lang"`
	PossiblySensitive    bool                   `json:"possibly_sensitive"`
	QuoteCount           int                    `json:"quote_count"`
	ReplyCount           int                    `json:"reply_count"`
	RetweetCount         int                    `json:"retweet_count"`
	Retweeted            bool                   `json:"retweeted"`
	RetweetedStatus      *Tweet                 `json:"retweeted_status"`
	Source               string                 `json:"source"`
	Scopes               map[string]interface{} `json:"scopes"`
	Text                 string                 `json:"text"`
	FullText             string                 `json:"full_text"`
	DisplayTextRange     Indices                `json:"display_text_range"`
	Place                *Place                 `json:"place"`
	Truncated            bool                   `json:"truncated"`
	User                 *User                  `json:"user"`
	WithheldCopyright    bool                   `json:"withheld_copyright"`
	WithheldInCountries  []string               `json:"withheld_in_countries"`
	WithheldScope        string                 `json:"withheld_scope"`
	ExtendedEntities     *ExtendedEntity        `json:"extended_entities"`
	ExtendedTweet        *ExtendedTweet         `json:"extended_tweet"`
	QuotedStatusID       int64                  `json:"quoted_status_id"`
	QuotedStatusIDStr    string                 `json:"quoted_status_id_str"`
	QuotedStatus         *Tweet                 `json:"quoted_status"`
}

// CreatedAtTime returns the time a tweet was created.
func (t Tweet) CreatedAtTime() (time.Time, error) {
	return time.Parse(time.RubyDate, t.CreatedAt)
}

// ExtendedTweet represents fields embedded in extended Tweets when served in
// compatibility mode (default).
// https://dev.twitter.com/overview/api/upcoming-changes-to-tweets
type ExtendedTweet struct {
	FullText         string          `json:"full_text"`
	DisplayTextRange Indices         `json:"display_text_range"`
	Entities         *Entities       `json:"entities"`
	ExtendedEntities *ExtendedEntity `json:"extended_entities"`
}

// Place represents a Twitter Place / Location
// https://dev.twitter.com/overview/api/places
type Place struct {
	Attributes  map[string]string `json:"attributes"`
	BoundingBox *BoundingBox      `json:"bounding_box"`
	Country     string            `json:"country"`
	CountryCode string            `json:"country_code"`
	FullName    string            `json:"full_name"`
	Geometry    *BoundingBox      `json:"geometry"`
	ID          string            `json:"id"`
	Name        string            `json:"name"`
	PlaceType   string            `json:"place_type"`
	Polylines   []string          `json:"polylines"`
	URL         string            `json:"url"`
}

// BoundingBox represents the bounding coordinates (longitude, latitutde)
// defining the bounds of a box containing a Place entity.
type BoundingBox struct {
	Coordinates [][][2]float64 `json:"coordinates"`
	Type        string         `json:"type"`
}

// Coordinates are pairs of longitude and latitude locations.
type Coordinates struct {
	Coordinates [2]float64 `json:"coordinates"`
	Type        string     `json:"type"`
}

// TweetIdentifier represents the id by which a Tweet can be identified.
type TweetIdentifier struct {
	ID    int64  `json:"id"`
	IDStr string `json:"id_str"`
}

// StatusService provides methods for accessing Twitter status API endpoints.
type StatusService struct {
	sling *sling.Sling
}

// newStatusService returns a new StatusService.
func newStatusService(sling *sling.Sling) *StatusService {
	return &StatusService{
		sling: sling.Path("statuses/"),
	}
}

// StatusShowParams are the parameters for StatusService.Show
type StatusShowParams struct {
	ID               int64  `url:"id,omitempty"`
	TrimUser         *bool  `url:"trim_user,omitempty"`
	IncludeMyRetweet *bool  `url:"include_my_retweet,omitempty"`
	IncludeEntities  *bool  `url:"include_entities,omitempty"`
	TweetMode        string `url:"tweet_mode,omitempty"`
}

// Show returns the requested Tweet.
// https://developer.twitter.com/en/docs/twitter-api/v1/tweets/post-and-engage/api-reference/get-statuses-show-id
func (s *StatusService) Show(id int64, params *StatusShowParams) (*Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusShowParams{}
	}
	params.ID = id
	tweet := new(Tweet)
	apiError := new(APIError)
	resp, err := s.sling.New().Get("show.json").QueryStruct(params).Receive(tweet, apiError)
	return tweet, resp, relevantError(err, *apiError)
}

// StatusLookupParams are the parameters for StatusService.Lookup
type StatusLookupParams struct {
	ID              []int64 `url:"id,omitempty,comma"`
	TrimUser        *bool   `url:"trim_user,omitempty"`
	IncludeEntities *bool   `url:"include_entities,omitempty"`
	Map             *bool   `url:"map,omitempty"`
	TweetMode       string  `url:"tweet_mode,omitempty"`
}

// Lookup returns the requested Tweets as a slice. Combines ids from the
// required ids argument and from params.Id.
// https://developer.twitter.com/en/docs/twitter-api/v1/tweets/post-and-engage/api-reference/get-statuses-lookup
func (s *StatusService) Lookup(ids []int64, params *StatusLookupParams) ([]Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusLookupParams{}
	}
	params.ID = append(params.ID, ids...)
	tweets := new([]Tweet)
	apiError := new(APIError)
	resp, err := s.sling.New().Get("lookup.json").QueryStruct(params).Receive(tweets, apiError)
	return *tweets, resp, relevantError(err, *apiError)
}

// StatusUpdateParams are the parameters for StatusService.Update
type StatusUpdateParams struct {
	Status                    string   `url:"status,omitempty"`
	InReplyToStatusID         int64    `url:"in_reply_to_status_id,omitempty"`
	AutoPopulateReplyMetadata *bool    `url:"auto_populate_reply_metadata,omitempty"`
	PossiblySensitive         *bool    `url:"possibly_sensitive,omitempty"`
	Lat                       *float64 `url:"lat,omitempty"`
	Long                      *float64 `url:"long,omitempty"`
	PlaceID                   string   `url:"place_id,omitempty"`
	DisplayCoordinates        *bool    `url:"display_coordinates,omitempty"`
	TrimUser                  *bool    `url:"trim_user,omitempty"`
	MediaIds                  []int64  `url:"media_ids,omitempty,comma"`
	TweetMode                 string   `url:"tweet_mode,omitempty"`
}

// Update updates the user's status, also known as Tweeting.
// Requires a user auth context.
// https://developer.twitter.com/en/docs/twitter-api/v1/tweets/post-and-engage/api-reference/post-statuses-update
func (s *StatusService) Update(status string, params *StatusUpdateParams) (*Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusUpdateParams{}
	}
	params.Status = status
	tweet := new(Tweet)
	apiError := new(APIError)
	resp, err := s.sling.New().Post("update.json").BodyForm(params).Receive(tweet, apiError)
	return tweet, resp, relevantError(err, *apiError)
}

// StatusRetweetParams are the parameters for StatusService.Retweet
type StatusRetweetParams struct {
	ID        int64  `url:"id,omitempty"`
	TrimUser  *bool  `url:"trim_user,omitempty"`
	TweetMode string `url:"tweet_mode,omitempty"`
}

// Retweet retweets the Tweet with the given id and returns the original Tweet
// with embedded retweet details.
// Requires a user auth context.
// https://developer.twitter.com/en/docs/twitter-api/v1/tweets/post-and-engage/api-reference/post-statuses-retweet-id
func (s *StatusService) Retweet(id int64, params *StatusRetweetParams) (*Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusRetweetParams{}
	}
	params.ID = id
	tweet := new(Tweet)
	apiError := new(APIError)
	path := fmt.Sprintf("retweet/%d.json", params.ID)
	resp, err := s.sling.New().Post(path).BodyForm(params).Receive(tweet, apiError)
	return tweet, resp, relevantError(err, *apiError)
}

// StatusUnretweetParams are the parameters for StatusService.Unretweet
type StatusUnretweetParams struct {
	ID        int64  `url:"id,omitempty"`
	TrimUser  *bool  `url:"trim_user,omitempty"`
	TweetMode string `url:"tweet_mode,omitempty"`
}

// Unretweet unretweets the Tweet with the given id and returns the original Tweet.
// Requires a user auth context.
// https://developer.twitter.com/en/docs/twitter-api/v1/tweets/post-and-engage/api-reference/post-statuses-unretweet-id
func (s *StatusService) Unretweet(id int64, params *StatusUnretweetParams) (*Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusUnretweetParams{}
	}
	params.ID = id
	tweet := new(Tweet)
	apiError := new(APIError)
	path := fmt.Sprintf("unretweet/%d.json", params.ID)
	resp, err := s.sling.New().Post(path).BodyForm(params).Receive(tweet, apiError)
	return tweet, resp, relevantError(err, *apiError)
}

// StatusRetweetsParams are the parameters for StatusService.Retweets
type StatusRetweetsParams struct {
	ID        int64  `url:"id,omitempty"`
	Count     int    `url:"count,omitempty"`
	TrimUser  *bool  `url:"trim_user,omitempty"`
	TweetMode string `url:"tweet_mode,omitempty"`
}

// Retweets returns the most recent retweets of the Tweet with the given id.
// https://developer.twitter.com/en/docs/twitter-api/v1/tweets/post-and-engage/api-reference/get-statuses-retweets-id
func (s *StatusService) Retweets(id int64, params *StatusRetweetsParams) ([]Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusRetweetsParams{}
	}
	params.ID = id
	tweets := new([]Tweet)
	apiError := new(APIError)
	path := fmt.Sprintf("retweets/%d.json", params.ID)
	resp, err := s.sling.New().Get(path).QueryStruct(params).Receive(tweets, apiError)
	return *tweets, resp, relevantError(err, *apiError)
}

// StatusDestroyParams are the parameters for StatusService.Destroy
type StatusDestroyParams struct {
	ID        int64  `url:"id,omitempty"`
	TrimUser  *bool  `url:"trim_user,omitempty"`
	TweetMode string `url:"tweet_mode,omitempty"`
}

// Destroy deletes the Tweet with the given id and returns it if successful.
// Requires a user auth context.
// https://developer.twitter.com/en/docs/twitter-api/v1/tweets/post-and-engage/api-reference/post-favorites-destroy
func (s *StatusService) Destroy(id int64, params *StatusDestroyParams) (*Tweet, *http.Response, error) {
	if params == nil {
		params = &StatusDestroyParams{}
	}
	params.ID = id
	tweet := new(Tweet)
	apiError := new(APIError)
	path := fmt.Sprintf("destroy/%d.json", params.ID)
	resp, err := s.sling.New().Post(path).BodyForm(params).Receive(tweet, apiError)
	return tweet, resp, relevantError(err, *apiError)
}

// OEmbedTweet represents a Tweet in oEmbed format.
type OEmbedTweet struct {
	URL          string `json:"url"`
	ProviderURL  string `json:"provider_url"`
	ProviderName string `json:"provider_name"`
	AuthorName   string `json:"author_name"`
	Version      string `json:"version"`
	AuthorURL    string `json:"author_url"`
	Type         string `json:"type"`
	HTML         string `json:"html"`
	Height       int64  `json:"height"`
	Width        int64  `json:"width"`
	CacheAge     string `json:"cache_age"`
}

// StatusOEmbedParams are the parameters for StatusService.OEmbed
type StatusOEmbedParams struct {
	ID         int64  `url:"id,omitempty"`
	URL        string `url:"url,omitempty"`
	Align      string `url:"align,omitempty"`
	MaxWidth   int64  `url:"maxwidth,omitempty"`
	HideMedia  *bool  `url:"hide_media,omitempty"`
	HideThread *bool  `url:"hide_media,omitempty"`
	OmitScript *bool  `url:"hide_media,omitempty"`
	WidgetType string `url:"widget_type,omitempty"`
	HideTweet  *bool  `url:"hide_tweet,omitempty"`
}

// OEmbed returns the requested Tweet in oEmbed format.
// https://developer.twitter.com/en/docs/twitter-api/v1/tweets/post-and-engage/api-reference/get-statuses-oembed
func (s *StatusService) OEmbed(params *StatusOEmbedParams) (*OEmbedTweet, *http.Response, error) {
	oEmbedTweet := new(OEmbedTweet)
	apiError := new(APIError)
	resp, err := s.sling.New().Get("oembed.json").QueryStruct(params).Receive(oEmbedTweet, apiError)
	return oEmbedTweet, resp, relevantError(err, *apiError)
}
<|endoftext|>


<commit_before>// +build !windows

/*
Copyright 2018 The Skaffold Authors

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

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

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

package tag

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
	"time"

	"github.com/GoogleContainerTools/skaffold/testutil"
	git "gopkg.in/src-d/go-git.v4"
	"gopkg.in/src-d/go-git.v4/plumbing"
	"gopkg.in/src-d/go-git.v4/plumbing/object"
)

// These tests do not run on windows
// See: https://github.com/src-d/go-git/issues/378
func TestGitCommit_GenerateFullyQualifiedImageName(t *testing.T) {
	tests := []struct {
		description   string
		expectedName  string
		createGitRepo func(string)
		opts          *Options
		subDir        string
		shouldErr     bool
	}{
		{
			description: "success",
			opts: &Options{
				ImageName: "test",
			},
			expectedName: "test:eefe1b9",
			createGitRepo: func(dir string) {
				gitInit(t, dir).
					write("source.go", []byte("code")).
					add("source.go").
					commit("initial")
			},
		},
		{
			description: "use tag over commit",
			opts: &Options{
				ImageName: "test",
			},
			expectedName: "test:v2",
			createGitRepo: func(dir string) {
				gitInit(t, dir).
					write("source.go", []byte("code")).
					add("source.go").
					commit("initial").
					tag("v1").
					write("other.go", []byte("other")).
					add("other.go").
					commit("second commit").
					tag("v2")
			},
		},
		{
			description: "dirty",
			opts: &Options{
				ImageName: "test",
			},
			expectedName: "test:eefe1b9-dirty-8b8c4dad90faa822",
			createGitRepo: func(dir string) {
				gitInit(t, dir).
					write("source.go", []byte("code")).
					add("source.go").
					commit("initial").
					write("source.go", []byte("updated code"))
			},
		},
		{
			description: "ignore tag when dirty",
			opts: &Options{
				ImageName: "test",
			},
			expectedName: "test:eefe1b9-dirty-8b8c4dad90faa822",
			createGitRepo: func(dir string) {
				gitInit(t, dir).
					write("source.go", []byte("code")).
					add("source.go").
					commit("initial").
					tag("v1").
					write("source.go", []byte("updated code"))
			},
		},
		{
			description: "untracked",
			opts: &Options{
				ImageName: "test",
			},
			expectedName: "test:eefe1b9-dirty-e0bc2923501f63b7",
			createGitRepo: func(dir string) {
				gitInit(t, dir).
					write("source.go", []byte("code")).
					add("source.go").
					commit("initial").
					write("new.go", []byte("new code"))
			},
		},
		{
			description: "one file deleted",
			opts: &Options{
				ImageName: "test",
			},
			expectedName: "test:279d53f-dirty-6a3ce511c689eda7",
			createGitRepo: func(dir string) {
				gitInit(t, dir).
					write("source1.go", []byte("code1")).
					write("source2.go", []byte("code2")).
					add("source1.go", "source2.go").
					commit("initial").
					delete("source1.go")
			},
		},
		{
			description: "two files deleted",
			opts: &Options{
				ImageName: "test",
			},
			expectedName: "test:279d53f-dirty-d48c11ed65c37a09", // Must be <> than when only one file is deleted
			createGitRepo: func(dir string) {
				gitInit(t, dir).
					write("source1.go", []byte("code1")).
					write("source2.go", []byte("code2")).
					add("source1.go", "source2.go").
					commit("initial").
					delete("source1.go", "source2.go")
			},
		},
		{
			description: "rename",
			opts: &Options{
				ImageName: "test",
			},
			expectedName: "test:eefe1b9-dirty-c9417af5dc664b60",
			createGitRepo: func(dir string) {
				gitInit(t, dir).
					write("source.go", []byte("code")).
					add("source.go").
					commit("initial").
					rename("source.go", "source2.go")
			},
		},
		{
			description: "rename to different name",
			opts: &Options{
				ImageName: "test",
			},
			expectedName: "test:eefe1b9-dirty-91fd2028ff0a5cf3", // Must be <> each time a new name is used
			createGitRepo: func(dir string) {
				gitInit(t, dir).
					write("source.go", []byte("code")).
					add("source.go").
					commit("initial").
					rename("source.go", "source3.go")
			},
		},
		{
			description: "sub directory",
			opts: &Options{
				ImageName: "test",
			},
			expectedName: "test:a7b32a6",
			createGitRepo: func(dir string) {
				gitInit(t, dir).
					mkdir("sub/sub").
					commit("initial")
			},
			subDir: "sub/sub",
		},
		{
			description: "sub directory with dirty status",
			opts: &Options{
				ImageName: "test",
			},
			expectedName: "test:a7b32a6-dirty-2dfb095d0f4830ad",
			createGitRepo: func(dir string) {
				gitInit(t, dir).
					mkdir("sub/sub").
					commit("initial").
					write("source.go", []byte("updated code"))
			},
			subDir: "sub/sub",
		},
		{
			description:   "failure",
			createGitRepo: func(dir string) {},
			shouldErr:     true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.description, func(t *testing.T) {
			tmpDir, cleanup := testutil.TempDir(t)
			defer cleanup()

			tt.createGitRepo(tmpDir)
			workspace := filepath.Join(tmpDir, tt.subDir)

			c := &GitCommit{}
			name, err := c.GenerateFullyQualifiedImageName(workspace, tt.opts)
			testutil.CheckErrorAndDeepEqual(t, tt.shouldErr, err, tt.expectedName, name)

			name, err = generateNameGoGit(workspace, tt.opts)
			testutil.CheckErrorAndDeepEqual(t, tt.shouldErr, err, tt.expectedName, name)

			name, err = generateNameGitShellOut(workspace, tt.opts)
			testutil.CheckErrorAndDeepEqual(t, tt.shouldErr, err, tt.expectedName, name)
		})
	}
}

// gitRepo deals with test git repositories
type gitRepo struct {
	dir      string
	repo     *git.Repository
	workTree *git.Worktree
	t        *testing.T
}

func gitInit(t *testing.T, dir string) *gitRepo {
	repo, err := git.PlainInit(dir, false)
	failNowIfError(t, err)

	w, err := repo.Worktree()
	failNowIfError(t, err)

	return &gitRepo{
		dir:      dir,
		repo:     repo,
		workTree: w,
		t:        t,
	}
}

func (g *gitRepo) mkdir(folder string) *gitRepo {
	err := os.MkdirAll(filepath.Join(g.dir, folder), os.ModePerm)
	failNowIfError(g.t, err)
	return g
}

func (g *gitRepo) write(file string, content []byte) *gitRepo {
	err := ioutil.WriteFile(filepath.Join(g.dir, file), content, os.ModePerm)
	failNowIfError(g.t, err)
	return g
}

func (g *gitRepo) rename(file, to string) *gitRepo {
	err := os.Rename(filepath.Join(g.dir, file), filepath.Join(g.dir, to))
	failNowIfError(g.t, err)
	return g
}

func (g *gitRepo) delete(files ...string) *gitRepo {
	for _, file := range files {
		err := os.Remove(filepath.Join(g.dir, file))
		failNowIfError(g.t, err)
	}
	return g
}

func (g *gitRepo) add(files ...string) *gitRepo {
	for _, file := range files {
		_, err := g.workTree.Add(file)
		failNowIfError(g.t, err)
	}
	return g
}

func (g *gitRepo) commit(msg string) *gitRepo {
	now, err := time.Parse("Jan 2, 2006 at 15:04:05 -0700 MST", "Feb 3, 2013 at 19:54:00 -0700 MST")
	failNowIfError(g.t, err)

	_, err = g.workTree.Commit(msg, &git.CommitOptions{
		Author: &object.Signature{
			Name:  "John Doe",
			Email: "john@doe.org",
			When:  now,
		},
	})
	failNowIfError(g.t, err)

	return g
}

func (g *gitRepo) tag(tag string) *gitRepo {
	head, err := g.repo.Head()
	failNowIfError(g.t, err)

	n := plumbing.ReferenceName("refs/tags/" + tag)
	t := plumbing.NewHashReference(n, head.Hash())

	err = g.repo.Storer.SetReference(t)
	failNowIfError(g.t, err)

	return g
}

func failNowIfError(t *testing.T, err error) {
	if err != nil {
		t.Fatal(err)
	}
}
<commit_msg>Remove duplication<commit_after>// +build !windows

/*
Copyright 2018 The Skaffold Authors

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

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

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

package tag

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
	"time"

	"github.com/GoogleContainerTools/skaffold/testutil"
	git "gopkg.in/src-d/go-git.v4"
	"gopkg.in/src-d/go-git.v4/plumbing"
	"gopkg.in/src-d/go-git.v4/plumbing/object"
)

// These tests do not run on windows
// See: https://github.com/src-d/go-git/issues/378
func TestGitCommit_GenerateFullyQualifiedImageName(t *testing.T) {
	tests := []struct {
		description   string
		expectedName  string
		createGitRepo func(string)
		subDir        string
		shouldErr     bool
	}{
		{
			description:  "success",
			expectedName: "test:eefe1b9",
			createGitRepo: func(dir string) {
				gitInit(t, dir).
					write("source.go", []byte("code")).
					add("source.go").
					commit("initial")
			},
		},
		{
			description:  "use tag over commit",
			expectedName: "test:v2",
			createGitRepo: func(dir string) {
				gitInit(t, dir).
					write("source.go", []byte("code")).
					add("source.go").
					commit("initial").
					tag("v1").
					write("other.go", []byte("other")).
					add("other.go").
					commit("second commit").
					tag("v2")
			},
		},
		{
			description:  "dirty",
			expectedName: "test:eefe1b9-dirty-af8de1fde8be4367",
			createGitRepo: func(dir string) {
				gitInit(t, dir).
					write("source.go", []byte("code")).
					add("source.go").
					commit("initial").
					write("source.go", []byte("updated code"))
			},
		},
		{
			description:  "ignore tag when dirty",
			expectedName: "test:eefe1b9-dirty-af8de1fde8be4367",
			createGitRepo: func(dir string) {
				gitInit(t, dir).
					write("source.go", []byte("code")).
					add("source.go").
					commit("initial").
					tag("v1").
					write("source.go", []byte("updated code"))
			},
		},
		{
			description:  "untracked",
			expectedName: "test:eefe1b9-dirty-bfe9b4566c9d3fec",
			createGitRepo: func(dir string) {
				gitInit(t, dir).
					write("source.go", []byte("code")).
					add("source.go").
					commit("initial").
					write("new.go", []byte("new code"))
			},
		},
		{
			description:  "one file deleted",
			expectedName: "test:279d53f-dirty-6a3ce511c689eda7",
			createGitRepo: func(dir string) {
				gitInit(t, dir).
					write("source1.go", []byte("code1")).
					write("source2.go", []byte("code2")).
					add("source1.go", "source2.go").
					commit("initial").
					delete("source1.go")
			},
		},
		{
			description:  "two files deleted",
			expectedName: "test:279d53f-dirty-d48c11ed65c37a09", // Must be <> than when only one file is deleted
			createGitRepo: func(dir string) {
				gitInit(t, dir).
					write("source1.go", []byte("code1")).
					write("source2.go", []byte("code2")).
					add("source1.go", "source2.go").
					commit("initial").
					delete("source1.go", "source2.go")
			},
		},
		{
			description:  "rename",
			expectedName: "test:eefe1b9-dirty-9c858d88cc0bf792",
			createGitRepo: func(dir string) {
				gitInit(t, dir).
					write("source.go", []byte("code")).
					add("source.go").
					commit("initial").
					rename("source.go", "source2.go")
			},
		},
		{
			description:  "rename to different name",
			expectedName: "test:eefe1b9-dirty-6534adc17ccd1cf4", // Must be <> each time a new name is used
			createGitRepo: func(dir string) {
				gitInit(t, dir).
					write("source.go", []byte("code")).
					add("source.go").
					commit("initial").
					rename("source.go", "source3.go")
			},
		},
		{
			description:  "sub directory",
			expectedName: "test:a7b32a6",
			createGitRepo: func(dir string) {
				gitInit(t, dir).
					mkdir("sub/sub").
					commit("initial")
			},
			subDir: "sub/sub",
		},
		{
			description:  "sub directory with dirty status",
			expectedName: "test:a7b32a6-dirty-83715cdc64e43ee9",
			createGitRepo: func(dir string) {
				gitInit(t, dir).
					mkdir("sub/sub").
					commit("initial").
					write("source.go", []byte("updated code"))
			},
			subDir: "sub/sub",
		},
		{
			description:   "failure",
			createGitRepo: func(dir string) {},
			shouldErr:     true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.description, func(t *testing.T) {
			tmpDir, cleanup := testutil.TempDir(t)
			defer cleanup()

			tt.createGitRepo(tmpDir)
			workspace := filepath.Join(tmpDir, tt.subDir)

			opts := &Options{
				ImageName: "test",
			}

			c := &GitCommit{}
			name, err := c.GenerateFullyQualifiedImageName(workspace, opts)
			testutil.CheckErrorAndDeepEqual(t, tt.shouldErr, err, tt.expectedName, name)

			name, err = generateNameGoGit(workspace, opts)
			testutil.CheckErrorAndDeepEqual(t, tt.shouldErr, err, tt.expectedName, name)

			name, err = generateNameGitShellOut(workspace, opts)
			testutil.CheckErrorAndDeepEqual(t, tt.shouldErr, err, tt.expectedName, name)
		})
	}
}

// gitRepo deals with test git repositories
type gitRepo struct {
	dir      string
	repo     *git.Repository
	workTree *git.Worktree
	t        *testing.T
}

func gitInit(t *testing.T, dir string) *gitRepo {
	repo, err := git.PlainInit(dir, false)
	failNowIfError(t, err)

	w, err := repo.Worktree()
	failNowIfError(t, err)

	return &gitRepo{
		dir:      dir,
		repo:     repo,
		workTree: w,
		t:        t,
	}
}

func (g *gitRepo) mkdir(folder string) *gitRepo {
	err := os.MkdirAll(filepath.Join(g.dir, folder), os.ModePerm)
	failNowIfError(g.t, err)
	return g
}

func (g *gitRepo) write(file string, content []byte) *gitRepo {
	err := ioutil.WriteFile(filepath.Join(g.dir, file), content, os.ModePerm)
	failNowIfError(g.t, err)
	return g
}

func (g *gitRepo) rename(file, to string) *gitRepo {
	err := os.Rename(filepath.Join(g.dir, file), filepath.Join(g.dir, to))
	failNowIfError(g.t, err)
	return g
}

func (g *gitRepo) delete(files ...string) *gitRepo {
	for _, file := range files {
		err := os.Remove(filepath.Join(g.dir, file))
		failNowIfError(g.t, err)
	}
	return g
}

func (g *gitRepo) add(files ...string) *gitRepo {
	for _, file := range files {
		_, err := g.workTree.Add(file)
		failNowIfError(g.t, err)
	}
	return g
}

func (g *gitRepo) commit(msg string) *gitRepo {
	now, err := time.Parse("Jan 2, 2006 at 15:04:05 -0700 MST", "Feb 3, 2013 at 19:54:00 -0700 MST")
	failNowIfError(g.t, err)

	_, err = g.workTree.Commit(msg, &git.CommitOptions{
		Author: &object.Signature{
			Name:  "John Doe",
			Email: "john@doe.org",
			When:  now,
		},
	})
	failNowIfError(g.t, err)

	return g
}

func (g *gitRepo) tag(tag string) *gitRepo {
	head, err := g.repo.Head()
	failNowIfError(g.t, err)

	n := plumbing.ReferenceName("refs/tags/" + tag)
	t := plumbing.NewHashReference(n, head.Hash())

	err = g.repo.Storer.SetReference(t)
	failNowIfError(g.t, err)

	return g
}

func failNowIfError(t *testing.T, err error) {
	if err != nil {
		t.Fatal(err)
	}
}
<|endoftext|>


<commit_before>
package core

import ("fmt"
	"os"
	"strconv"
	"github.com/jackyb/go-sdl2/sdl"
	"github.com/op/go-nanomsg"
	"github.com/fire/go-ogre3d"
	"github.com/ugorji/go/codec"
	"runtime")

type InputState struct {
	yawSens float32
	pitchSens float32
	orientationFactor float32 // +1/-1 easy switch between look around and manipulate something
	yaw float32 // degrees, modulo [-180,180] range
	pitch float32 // degrees, clamped [-90,90] range
	roll float32
	// orientation ogre.Quaternion // current orientation
}

func InitCore() {
	sdl.Init(sdl.INIT_EVERYTHING)
	window := sdl.CreateWindow("es_core::SDL",
		sdl.WINDOWPOS_UNDEFINED,
		sdl.WINDOWPOS_UNDEFINED,
		800,
		600,
		sdl.WINDOW_SHOWN)
	if window == nil {
		panic(fmt.Sprintf("sdl.CreateWindow failed: %s\n", sdl.GetError()))
	}
	defer sdl.Quit()
	var info sdl.SysWMInfo
	if !window.GetWMInfo(&info) {
		panic(fmt.Sprintf("window.GetWMInfo failed.\n"))
	}
	// Parse and print info's version
	// Parse and print info's SYSWM_TYPE
	root := ogre.NewRoot("", "", "ogre.log")
	defer root.Destroy()
	wd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	if runtime.GOOS == "windows" {
	root.LoadPlugin(wd  + "/RenderSystem_GL")
		}
	if runtime.GOOS == "darwin" {
		root.LoadPlugin(wd  + "/../frameworks/RenderSystem_GL")
	}

	renderers := root.GetAvailableRenderers()
	if renderers.RenderSystemListSize() != 1 {

		panic(fmt.Sprintf("Failed to initalize RendererRenderSystem_GL"))
	}
	root.SetRenderSystem(renderers.RenderSystemListGet(0))
	root.Initialise(false, "es_core::ogre")
	params := ogre.CreateNameValuePairList()
	params.AddPair("macAPI", "cocoa")
	cocoaInfo := info.GetCocoaInfo()
	windowString := strconv.FormatUint(uint64(*(*uint32)(cocoaInfo.Window)), 10)
	params.AddPair("parentWindowHandle", windowString)

	renderWindow := root.CreateRenderWindow("es_core::ogre", 800, 600, false, params)
	renderWindow.SetVisible(true)

	nnGameSocket, err := nanomsg.NewSocket(nanomsg.AF_SP, nanomsg.BUS)
        if err != nil {
                panic(err)
        }
        _, err = nnGameSocket.Bind("tcp://127.0.0.1:60206")
        if err != nil {
                panic(err)
        }

	nnRenderSocket, err := nanomsg.NewSocket(nanomsg.AF_SP, nanomsg.BUS)
	if err != nil {
                panic(err)
        }
        _, err = nnRenderSocket.Bind("tcp://127.0.0.1:60207")
        if err != nil {
                panic(err)
        }

	nnInputPub, err := nanomsg.NewSocket(nanomsg.AF_SP, nanomsg.PUB)
        if err != nil {
                panic(err)
        }
        _, err = nnInputPub.Bind("tcp://127.0.0.1:60208")
        if err != nil {
                panic(err)
        }

	nnInputPull, err := nanomsg.NewSocket(nanomsg.AF_SP, nanomsg.PULL)
        if err != nil {
                panic(err)
        }
        _, err = nnInputPull.Bind("tcp://127.0.0.1:60209")
        if err != nil {
                panic(err)
        }
	go gameThread()
	var renderThreadParams RenderThreadParams
	renderThreadParams.root = root
	renderThreadParams.window = window
	renderThreadParams.ogreWindow = renderWindow

	go renderThread(renderThreadParams)

	window.SetGrab(true)
	sdl.SetRelativeMouseMode(true)

	shutdownRequested := false
	var is InputState
	is.yawSens = 0.1
	is.yaw = 0.0
	is.pitchSens = 0.1
	is.pitch = 0.0
	is.roll = 0.0
	is.orientationFactor = -1.0 // Look around config

	// Msgpack
	var (
		v interface{} //Value to decode into
		mh codec.MsgpackHandle
	)

	for !shutdownRequested {
		var b []byte
		// We wait here.
		b, err = nnInputPull.Recv(0)
		fmt.Printf("Game push received:\n")
		if err != nil {
			fmt.Printf("%s\n", err)
		}
		dec := codec.NewDecoderBytes(b, &mh)
		err = dec.Decode(&v)
		if err != nil {
			fmt.Printf("%s\n", err)
		}

		// poll for events before processing the request
		// NOTE: this is how SDL builds the internal mouse and keyboard state
		// TODO: done this way does not meet the objectives of smooth, frame independent mouse view control,
		// Plus it throws some latency into the calling thread

		var event sdl.Event
		for event = sdl.PollEvent(); event != nil; event = sdl.PollEvent {
			switch t := event.(type) {
			case *sdl.KeyDownEvent:
				fmt.Printf("SDL keyboard event:\n")
			case *sdl.KeyUpEvent:
				fmt.Printf("SDL keyboard event:\n")
				if t.Keysym.Scancode == sdl.SCANCODE_ESCAPE {
					// Todo
					sendShutdown(nnRenderSocket, nnGameSocket)
					shutdownRequested = true
				}
			}
		}
	}
}

func sendShutdown (nnRenderSocket *nanomsg.Socket, nnGameSocket *nanomsg.Socket) {
	fmt.Printf("Render socket shutdown.\n")
	fmt.Printf("Game socket shutdown.\n")
}
<commit_msg>Remove function that isn't implemented.<commit_after>
package core

import ("fmt"
	"os"
	"strconv"
	"github.com/jackyb/go-sdl2/sdl"
	"github.com/op/go-nanomsg"
	"github.com/fire/go-ogre3d"
	"github.com/ugorji/go/codec"
	"runtime")

type InputState struct {
	yawSens float32
	pitchSens float32
	orientationFactor float32 // +1/-1 easy switch between look around and manipulate something
	yaw float32 // degrees, modulo [-180,180] range
	pitch float32 // degrees, clamped [-90,90] range
	roll float32
	// orientation ogre.Quaternion // current orientation
}

func InitCore() {
	sdl.Init(sdl.INIT_EVERYTHING)
	window := sdl.CreateWindow("es_core::SDL",
		sdl.WINDOWPOS_UNDEFINED,
		sdl.WINDOWPOS_UNDEFINED,
		800,
		600,
		sdl.WINDOW_SHOWN)
	if window == nil {
		panic(fmt.Sprintf("sdl.CreateWindow failed: %s\n", sdl.GetError()))
	}
	defer sdl.Quit()
	var info sdl.SysWMInfo
	if !window.GetWMInfo(&info) {
		panic(fmt.Sprintf("window.GetWMInfo failed.\n"))
	}
	// Parse and print info's version
	// Parse and print info's SYSWM_TYPE
	root := ogre.NewRoot("", "", "ogre.log")
	defer root.Destroy()
	wd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	if runtime.GOOS == "windows" {
	root.LoadPlugin(wd  + "/RenderSystem_GL")
		}
	if runtime.GOOS == "darwin" {
		root.LoadPlugin(wd  + "/../frameworks/RenderSystem_GL")
	}

	renderers := root.GetAvailableRenderers()
	if renderers.RenderSystemListSize() != 1 {

		panic(fmt.Sprintf("Failed to initalize RendererRenderSystem_GL"))
	}
	root.SetRenderSystem(renderers.RenderSystemListGet(0))
	root.Initialise(false, "es_core::ogre")
	params := ogre.CreateNameValuePairList()
	params.AddPair("macAPI", "cocoa")
	cocoaInfo := info.GetCocoaInfo()
	windowString := strconv.FormatUint(uint64(*(*uint32)(cocoaInfo.Window)), 10)
	params.AddPair("parentWindowHandle", windowString)

	renderWindow := root.CreateRenderWindow("es_core::ogre", 800, 600, false, params)
//	renderWindow.SetVisible(true)

	nnGameSocket, err := nanomsg.NewSocket(nanomsg.AF_SP, nanomsg.BUS)
        if err != nil {
                panic(err)
        }
        _, err = nnGameSocket.Bind("tcp://127.0.0.1:60206")
        if err != nil {
                panic(err)
        }

	nnRenderSocket, err := nanomsg.NewSocket(nanomsg.AF_SP, nanomsg.BUS)
	if err != nil {
                panic(err)
        }
        _, err = nnRenderSocket.Bind("tcp://127.0.0.1:60207")
        if err != nil {
                panic(err)
        }

	nnInputPub, err := nanomsg.NewSocket(nanomsg.AF_SP, nanomsg.PUB)
        if err != nil {
                panic(err)
        }
        _, err = nnInputPub.Bind("tcp://127.0.0.1:60208")
        if err != nil {
                panic(err)
        }

	nnInputPull, err := nanomsg.NewSocket(nanomsg.AF_SP, nanomsg.PULL)
        if err != nil {
                panic(err)
        }
        _, err = nnInputPull.Bind("tcp://127.0.0.1:60209")
        if err != nil {
                panic(err)
        }
	go gameThread()
	var renderThreadParams RenderThreadParams
	renderThreadParams.root = root
	renderThreadParams.window = window
	renderThreadParams.ogreWindow = renderWindow

	go renderThread(renderThreadParams)

	window.SetGrab(true)
	sdl.SetRelativeMouseMode(true)

	shutdownRequested := false
	var is InputState
	is.yawSens = 0.1
	is.yaw = 0.0
	is.pitchSens = 0.1
	is.pitch = 0.0
	is.roll = 0.0
	is.orientationFactor = -1.0 // Look around config

	// Msgpack
	var (
		v interface{} //Value to decode into
		mh codec.MsgpackHandle
	)

	for !shutdownRequested {
		var b []byte
		// We wait here.
		b, err = nnInputPull.Recv(0)
		fmt.Printf("Game push received:\n")
		if err != nil {
			fmt.Printf("%s\n", err)
		}
		dec := codec.NewDecoderBytes(b, &mh)
		err = dec.Decode(&v)
		if err != nil {
			fmt.Printf("%s\n", err)
		}

		// poll for events before processing the request
		// NOTE: this is how SDL builds the internal mouse and keyboard state
		// TODO: done this way does not meet the objectives of smooth, frame independent mouse view control,
		// Plus it throws some latency into the calling thread

		var event sdl.Event
		for event = sdl.PollEvent(); event != nil; event = sdl.PollEvent {
			switch t := event.(type) {
			case *sdl.KeyDownEvent:
				fmt.Printf("SDL keyboard event:\n")
			case *sdl.KeyUpEvent:
				fmt.Printf("SDL keyboard event:\n")
				if t.Keysym.Scancode == sdl.SCANCODE_ESCAPE {
					// Todo
					sendShutdown(nnRenderSocket, nnGameSocket)
					shutdownRequested = true
				}
			}
		}
	}
}

func sendShutdown (nnRenderSocket *nanomsg.Socket, nnGameSocket *nanomsg.Socket) {
	fmt.Printf("Render socket shutdown.\n")
	fmt.Printf("Game socket shutdown.\n")
}
<|endoftext|>