<commit_before>package utils

import (
	"encoding/json"
	"github.com/jfrogdev/jfrog-cli-go/utils/cliutils"
	"github.com/jfrogdev/jfrog-cli-go/utils/ioutils"
	"github.com/jfrogdev/jfrog-cli-go/utils/config"
	"os"
	"io/ioutil"
	"bytes"
	"time"
	"strings"
	"net/http"
)

const BUILD_INFO_DETAILS = "details"

func GetBuildDir(buildName, buildNumber string) (string, error) {
	tempDir := os.TempDir()
	buildsDir := tempDir + "/jfrog/builds/" + buildName + "/" + buildNumber + "/"
	err := os.MkdirAll(buildsDir, 0777)
	if cliutils.CheckError(err) != nil {
		return "", err
	}
	return buildsDir, nil
}

func saveBuildData(action interface{}, buildName, buildNumber string) (err error) {
	b, err := json.Marshal(&action)
	err = cliutils.CheckError(err)
	if err != nil {
		return err
	}
	var content bytes.Buffer
	err = json.Indent(&content, b, "", "  ")
	err = cliutils.CheckError(err)
	if err != nil {
		return err
	}
	dirPath, err := GetBuildDir(buildName, buildNumber)
	if err != nil {
		return err
	}
	tmpfile, err := ioutil.TempFile(dirPath, "temp")
	if err != nil {
		return err
	}
	_, err = tmpfile.Write([]byte(content.String()))
	return
}

func SaveBuildGeneralDetails(buildName, buildNumber string) error {
	path, err := GetBuildDir(buildName, buildNumber)
	if err != nil {
		return err
	}
	path += BUILD_INFO_DETAILS
	var exists bool
	exists, err = ioutils.IsFileExists(path)
	if err != nil {
		return err
	}
	if exists {
		return nil
	}
	meta := BuildGeneralDetails{
		Timestamp: time.Now(),
	}
	b, err := json.Marshal(&meta)
	err = cliutils.CheckError(err)
	var content bytes.Buffer
	err = json.Indent(&content, b, "", "  ")
	err = cliutils.CheckError(err)
	if err != nil {
		return err
	}
	err = ioutil.WriteFile(path, []byte(content.String()), 0600)
	return err
}

type populateBuildInfoWrapper func(*ArtifactBuildInfoWrapper)

func PrepareBuildInfoForSave(buildName, buildNumber string, populateDataFunc populateBuildInfoWrapper) error {
	tempBuildInfo := new(ArtifactBuildInfoWrapper)
	tempBuildInfo.Timestamp = time.Now().UnixNano() / int64(time.Millisecond)
	populateDataFunc(tempBuildInfo)
	return saveBuildData(tempBuildInfo, buildName, buildNumber)
}

func ReadBuildInfoFiles(buildName, buildNumber string) (BuildInfo, error) {
	var buildInfo []*ArtifactBuildInfoWrapper
	path, err := GetBuildDir(buildName, buildNumber)
	if err != nil {
		return nil, err
	}
	buildFiles, err := ioutils.ListFiles(path)
	if err != nil {
		return nil, err
	}
	for _, buildFile := range buildFiles {
		dir, err := ioutils.IsDir(buildFile)
		if err != nil {
			return nil, err
		}
		if dir {
			continue
		}
		if strings.HasSuffix(buildFile, BUILD_INFO_DETAILS) {
			continue
		}
		content, err := ioutils.ReadFile(buildFile)
		if err != nil {
			return nil, err
		}
		atifactBuildInfoWrapper := new(ArtifactBuildInfoWrapper)
		json.Unmarshal(content, &atifactBuildInfoWrapper)
		buildInfo = append(buildInfo, atifactBuildInfoWrapper)
	}

	return buildInfo, nil
}

func ReadBuildInfoGeneralDetails(buildName, buildNumber string) (*BuildGeneralDetails, error) {
	path, err := GetBuildDir(buildName, buildNumber)
	if err != nil {
		return nil, err
	}
	path += BUILD_INFO_DETAILS
	content, err := ioutils.ReadFile(path)
	if err != nil {
		return nil, err
	}
	details := new(BuildGeneralDetails)
	json.Unmarshal(content, &details)
	return details, nil
}

func PublishBuildInfo(url string, content []byte, httpClientsDetails ioutils.HttpClientDetails) (resp *http.Response, body []byte, err error) {
	return ioutils.SendPut(url + "api/build/", content, httpClientsDetails)
}

type BuildEnv map[string]string

type BuildInfoCommon struct {
	Sha1 string `json:"sha1,omitempty"`
	Md5  string `json:"md5,omitempty"`
}

type ArtifactBuildInfo struct {
	Name string `json:"name,omitempty"`
	*BuildInfoCommon
}

type DependenciesBuildInfo struct {
	Id string `json:"id,omitempty"`
	*BuildInfoCommon
}

type BuildInfoAction string

type ArtifactBuildInfoWrapper struct {
	Artifacts    []ArtifactBuildInfo     `json:"Artifacts,omitempty"`
	Dependencies []DependenciesBuildInfo `json:"Dependencies,omitempty"`
	Env          BuildEnv                `json:"Env,omitempty"`
	Timestamp    int64                   `json:"Timestamp,omitempty"`
}

type BuildGeneralDetails struct {
	Timestamp time.Time `json:"Timestamp,omitempty"`
}

type BuildInfo []*ArtifactBuildInfoWrapper

func (wrapper BuildInfo) Len() int {
	return len(wrapper)
}

func (wrapper BuildInfo) Less(i, j int) bool {
	return wrapper[i].Timestamp < wrapper[j].Timestamp;
}

func (wrapper BuildInfo) Swap(i, j int) {
	wrapper[i], wrapper[j] = wrapper[j], wrapper[i]
}

func RemoveBuildDir(buildName, buildNumber string) error {
	tempDirPath, err := GetBuildDir(buildName, buildNumber)
	if err != nil {
		return err
	}
	exists, err := ioutils.IsDirExists(tempDirPath)
	if err != nil {
		return err
	}
	if exists {
		return cliutils.CheckError(os.RemoveAll(tempDirPath))
	}
	return nil
}

type BuildInfoFlags struct {
	ArtDetails *config.ArtifactoryDetails
	DryRun     bool
	EnvInclude string
	EnvExclude string
}

func (flags *BuildInfoFlags) GetArtifactoryDetails() *config.ArtifactoryDetails {
	return flags.ArtDetails
}

func (flags *BuildInfoFlags) IsDryRun() bool {
	return flags.DryRun
}<commit_msg>Support build info<commit_after>package utils

import (
	"encoding/json"
	"github.com/jfrogdev/jfrog-cli-go/utils/cliutils"
	"github.com/jfrogdev/jfrog-cli-go/utils/ioutils"
	"github.com/jfrogdev/jfrog-cli-go/utils/config"
	"os"
	"io/ioutil"
	"bytes"
	"time"
	"strings"
	"net/http"
)

const BUILD_INFO_DETAILS = "details"

func GetBuildDir(buildName, buildNumber string) (string, error) {
	tempDir := os.TempDir()
	buildsDir := tempDir + "/jfrog/builds/" + buildName + "_" + buildNumber + "/"
	err := os.MkdirAll(buildsDir, 0777)
	if cliutils.CheckError(err) != nil {
		return "", err
	}
	return buildsDir, nil
}

func saveBuildData(action interface{}, buildName, buildNumber string) (err error) {
	b, err := json.Marshal(&action)
	err = cliutils.CheckError(err)
	if err != nil {
		return err
	}
	var content bytes.Buffer
	err = json.Indent(&content, b, "", "  ")
	err = cliutils.CheckError(err)
	if err != nil {
		return err
	}
	dirPath, err := GetBuildDir(buildName, buildNumber)
	if err != nil {
		return err
	}
	tmpfile, err := ioutil.TempFile(dirPath, "temp")
	if err != nil {
		return err
	}
	_, err = tmpfile.Write([]byte(content.String()))
	return
}

func SaveBuildGeneralDetails(buildName, buildNumber string) error {
	path, err := GetBuildDir(buildName, buildNumber)
	if err != nil {
		return err
	}
	path += BUILD_INFO_DETAILS
	var exists bool
	exists, err = ioutils.IsFileExists(path)
	if err != nil {
		return err
	}
	if exists {
		return nil
	}
	meta := BuildGeneralDetails{
		Timestamp: time.Now(),
	}
	b, err := json.Marshal(&meta)
	err = cliutils.CheckError(err)
	var content bytes.Buffer
	err = json.Indent(&content, b, "", "  ")
	err = cliutils.CheckError(err)
	if err != nil {
		return err
	}
	err = ioutil.WriteFile(path, []byte(content.String()), 0600)
	return err
}

type populateBuildInfoWrapper func(*ArtifactBuildInfoWrapper)

func PrepareBuildInfoForSave(buildName, buildNumber string, populateDataFunc populateBuildInfoWrapper) error {
	tempBuildInfo := new(ArtifactBuildInfoWrapper)
	tempBuildInfo.Timestamp = time.Now().UnixNano() / int64(time.Millisecond)
	populateDataFunc(tempBuildInfo)
	return saveBuildData(tempBuildInfo, buildName, buildNumber)
}

func ReadBuildInfoFiles(buildName, buildNumber string) (BuildInfo, error) {
	var buildInfo []*ArtifactBuildInfoWrapper
	path, err := GetBuildDir(buildName, buildNumber)
	if err != nil {
		return nil, err
	}
	buildFiles, err := ioutils.ListFiles(path)
	if err != nil {
		return nil, err
	}
	for _, buildFile := range buildFiles {
		dir, err := ioutils.IsDir(buildFile)
		if err != nil {
			return nil, err
		}
		if dir {
			continue
		}
		if strings.HasSuffix(buildFile, BUILD_INFO_DETAILS) {
			continue
		}
		content, err := ioutils.ReadFile(buildFile)
		if err != nil {
			return nil, err
		}
		atifactBuildInfoWrapper := new(ArtifactBuildInfoWrapper)
		json.Unmarshal(content, &atifactBuildInfoWrapper)
		buildInfo = append(buildInfo, atifactBuildInfoWrapper)
	}

	return buildInfo, nil
}

func ReadBuildInfoGeneralDetails(buildName, buildNumber string) (*BuildGeneralDetails, error) {
	path, err := GetBuildDir(buildName, buildNumber)
	if err != nil {
		return nil, err
	}
	path += BUILD_INFO_DETAILS
	content, err := ioutils.ReadFile(path)
	if err != nil {
		return nil, err
	}
	details := new(BuildGeneralDetails)
	json.Unmarshal(content, &details)
	return details, nil
}

func PublishBuildInfo(url string, content []byte, httpClientsDetails ioutils.HttpClientDetails) (resp *http.Response, body []byte, err error) {
	return ioutils.SendPut(url + "api/build/", content, httpClientsDetails)
}

type BuildEnv map[string]string

type BuildInfoCommon struct {
	Sha1 string `json:"sha1,omitempty"`
	Md5  string `json:"md5,omitempty"`
}

type ArtifactBuildInfo struct {
	Name string `json:"name,omitempty"`
	*BuildInfoCommon
}

type DependenciesBuildInfo struct {
	Id string `json:"id,omitempty"`
	*BuildInfoCommon
}

type BuildInfoAction string

type ArtifactBuildInfoWrapper struct {
	Artifacts    []ArtifactBuildInfo     `json:"Artifacts,omitempty"`
	Dependencies []DependenciesBuildInfo `json:"Dependencies,omitempty"`
	Env          BuildEnv                `json:"Env,omitempty"`
	Timestamp    int64                   `json:"Timestamp,omitempty"`
}

type BuildGeneralDetails struct {
	Timestamp time.Time `json:"Timestamp,omitempty"`
}

type BuildInfo []*ArtifactBuildInfoWrapper

func (wrapper BuildInfo) Len() int {
	return len(wrapper)
}

func (wrapper BuildInfo) Less(i, j int) bool {
	return wrapper[i].Timestamp < wrapper[j].Timestamp;
}

func (wrapper BuildInfo) Swap(i, j int) {
	wrapper[i], wrapper[j] = wrapper[j], wrapper[i]
}

func RemoveBuildDir(buildName, buildNumber string) error {
	tempDirPath, err := GetBuildDir(buildName, buildNumber)
	if err != nil {
		return err
	}
	exists, err := ioutils.IsDirExists(tempDirPath)
	if err != nil {
		return err
	}
	if exists {
		return cliutils.CheckError(os.RemoveAll(tempDirPath))
	}
	return nil
}

type BuildInfoFlags struct {
	ArtDetails *config.ArtifactoryDetails
	DryRun     bool
	EnvInclude string
	EnvExclude string
}

func (flags *BuildInfoFlags) GetArtifactoryDetails() *config.ArtifactoryDetails {
	return flags.ArtDetails
}

func (flags *BuildInfoFlags) IsDryRun() bool {
	return flags.DryRun
}<|endoftext|>


<commit_before>package google

import (
	"reflect"
	"strings"
	"testing"

	"fmt"

	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

func TestAccEndpointsService_basic(t *testing.T) {
	// Uses random provider
	skipIfVcr(t)
	t.Parallel()
	serviceId := "tf-test" + randString(t, 10)

	vcrTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		CheckDestroy: testAccCheckEndpointServiceDestroyProducer(t),
		Providers:    testAccProviders,
		ExternalProviders: map[string]resource.ExternalProvider{
			"random": {},
		},
		Steps: []resource.TestStep{
			{
				Config: testAccEndpointsService_basic(serviceId, getTestProjectFromEnv(), "1"),
				Check:  testAccCheckEndpointExistsByName(t, serviceId),
			},
			{
				Config: testAccEndpointsService_basic(serviceId, getTestProjectFromEnv(), "2"),
				Check:  testAccCheckEndpointExistsByName(t, serviceId),
			},
			{
				Config: testAccEndpointsService_basic(serviceId, getTestProjectFromEnv(), "3"),
				Check:  testAccCheckEndpointExistsByName(t, serviceId),
			},
		},
	})
}

func TestAccEndpointsService_grpc(t *testing.T) {
	t.Parallel()
	serviceId := "tf-test" + randString(t, 10)

	vcrTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckEndpointServiceDestroyProducer(t),
		Steps: []resource.TestStep{
			{
				Config: testAccEndpointsService_grpc(serviceId, getTestProjectFromEnv()),
				Check:  testAccCheckEndpointExistsByName(t, serviceId),
			},
		},
	})
}

func TestEndpointsService_grpcMigrateState(t *testing.T) {
	cases := map[string]struct {
		StateVersion       int
		Attributes         map[string]string
		ExpectedAttributes map[string]string
		Meta               interface{}
	}{
		"update from protoc_output to protoc_output_base64": {
			StateVersion: 0,
			Attributes: map[string]string{
				"protoc_output": "123456789",
				"name":          "testcase",
			},
			ExpectedAttributes: map[string]string{
				"protoc_output_base64": "MTIzNDU2Nzg5",
				"protoc_output":        "",
				"name":                 "testcase",
			},
			Meta: &Config{Project: "gcp-project", Region: "us-central1"},
		},
		"update from non-protoc_output": {
			StateVersion: 0,
			Attributes: map[string]string{
				"openapi_config": "foo bar baz",
				"name":           "testcase-2",
			},
			ExpectedAttributes: map[string]string{
				"openapi_config": "foo bar baz",
				"name":           "testcase-2",
			},
			Meta: &Config{Project: "gcp-project", Region: "us-central1"},
		},
	}

	for tn, tc := range cases {
		is := &terraform.InstanceState{
			ID:         tc.Attributes["name"],
			Attributes: tc.Attributes,
		}

		is, err := migrateEndpointsService(tc.StateVersion, is, tc.Meta)

		if err != nil {
			t.Fatalf("bad: %s, err: %#v", tn, err)
		}

		if !reflect.DeepEqual(is.Attributes, tc.ExpectedAttributes) {
			t.Fatalf("Attributes should be `%s` but are `%s`", tc.ExpectedAttributes, is.Attributes)
		}
	}
}

func testAccEndpointsService_basic(serviceId, project, rev string) string {
	return fmt.Sprintf(`
resource "google_endpoints_service" "endpoints_service" {
  service_name   = "%[1]s.endpoints.%[2]s.cloud.goog"
  project        = "%[2]s"
  openapi_config = <<EOF
swagger: "2.0"
info:
  description: "A simple Google Cloud Endpoints API example."
  title: "Endpoints Example, rev. %[3]s"
  version: "1.0.0"
host: "%[1]s.endpoints.%[2]s.cloud.goog"
basePath: "/"
consumes:
- "application/json"
produces:
- "application/json"
schemes:
- "https"
paths:
  "/echo":
    post:
      description: "Echo back a given message."
      operationId: "echo"
      produces:
      - "application/json"
      responses:
        200:
          description: "Echo"
          schema:
            $ref: "#/definitions/echoMessage"
      parameters:
      - description: "Message to echo"
        in: body
        name: message
        required: true
        schema:
          $ref: "#/definitions/echoMessage"
      security:
      - api_key: []
definitions:
  echoMessage:
    properties:
      message:
        type: "string"
EOF

}

resource "random_id" "foo" {
  keepers = {
    config_id = google_endpoints_service.endpoints_service.config_id
  }
  byte_length = 8
}
`, serviceId, project, rev)
}

func testAccEndpointsService_grpc(serviceId, project string) string {
	return fmt.Sprintf(`
resource "google_endpoints_service" "endpoints_service" {
  service_name = "%[1]s.endpoints.%[2]s.cloud.goog"
  project      = "%[2]s"
  grpc_config  = <<EOF
type: google.api.Service
config_version: 3
name: %[1]s.endpoints.%[2]s.cloud.goog
usage:
  rules:
  - selector: endpoints.examples.bookstore.Bookstore.ListShelves
    allow_unregistered_calls: true
EOF

  protoc_output_base64 = filebase64("test-fixtures/test_api_descriptor.pb")
}
`, serviceId, project)
}

func testAccCheckEndpointExistsByName(t *testing.T, serviceId string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		config := googleProviderConfig(t)
		service, err := config.NewServiceManClient(config.userAgent).Services.GetConfig(
			fmt.Sprintf("%s.endpoints.%s.cloud.goog", serviceId, config.Project)).Do()
		if err != nil {
			return err
		}
		if service != nil {
			return nil
		} else {
			return fmt.Errorf("Service %s.endpoints.%s.cloud.goog does not seem to exist.", serviceId, config.Project)
		}
	}
}

func testAccCheckEndpointServiceDestroyProducer(t *testing.T) func(s *terraform.State) error {
	return func(s *terraform.State) error {
		config := googleProviderConfig(t)

		for name, rs := range s.RootModule().Resources {
			if strings.HasPrefix(name, "data.") {
				continue
			}
			if rs.Type != "google_endpoints_service" {
				continue
			}

			serviceName := rs.Primary.Attributes["service_name"]
			service, err := config.NewServiceManClient(config.userAgent).Services.GetConfig(serviceName).Do()
			if err != nil {
				// ServiceManagement returns 403 if service doesn't exist.
				if !isGoogleApiErrorWithCode(err, 403) {
					return err
				}
			}
			if service != nil {
				return fmt.Errorf("expected service %q to have been destroyed, got %+v", service.Name, service)
			}
		}
		return nil
	}
}
<commit_msg>removed unused random_id resource (#4536)<commit_after>package google

import (
	"reflect"
	"strings"
	"testing"

	"fmt"

	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

func TestAccEndpointsService_basic(t *testing.T) {
	// Uses random provider
	skipIfVcr(t)
	t.Parallel()
	serviceId := "tf-test" + randString(t, 10)

	vcrTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		CheckDestroy: testAccCheckEndpointServiceDestroyProducer(t),
		Providers:    testAccProviders,
		ExternalProviders: map[string]resource.ExternalProvider{
			"random": {},
		},
		Steps: []resource.TestStep{
			{
				Config: testAccEndpointsService_basic(serviceId, getTestProjectFromEnv(), "1"),
				Check:  testAccCheckEndpointExistsByName(t, serviceId),
			},
			{
				Config: testAccEndpointsService_basic(serviceId, getTestProjectFromEnv(), "2"),
				Check:  testAccCheckEndpointExistsByName(t, serviceId),
			},
			{
				Config: testAccEndpointsService_basic(serviceId, getTestProjectFromEnv(), "3"),
				Check:  testAccCheckEndpointExistsByName(t, serviceId),
			},
		},
	})
}

func TestAccEndpointsService_grpc(t *testing.T) {
	t.Parallel()
	serviceId := "tf-test" + randString(t, 10)

	vcrTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckEndpointServiceDestroyProducer(t),
		Steps: []resource.TestStep{
			{
				Config: testAccEndpointsService_grpc(serviceId, getTestProjectFromEnv()),
				Check:  testAccCheckEndpointExistsByName(t, serviceId),
			},
		},
	})
}

func TestEndpointsService_grpcMigrateState(t *testing.T) {
	cases := map[string]struct {
		StateVersion       int
		Attributes         map[string]string
		ExpectedAttributes map[string]string
		Meta               interface{}
	}{
		"update from protoc_output to protoc_output_base64": {
			StateVersion: 0,
			Attributes: map[string]string{
				"protoc_output": "123456789",
				"name":          "testcase",
			},
			ExpectedAttributes: map[string]string{
				"protoc_output_base64": "MTIzNDU2Nzg5",
				"protoc_output":        "",
				"name":                 "testcase",
			},
			Meta: &Config{Project: "gcp-project", Region: "us-central1"},
		},
		"update from non-protoc_output": {
			StateVersion: 0,
			Attributes: map[string]string{
				"openapi_config": "foo bar baz",
				"name":           "testcase-2",
			},
			ExpectedAttributes: map[string]string{
				"openapi_config": "foo bar baz",
				"name":           "testcase-2",
			},
			Meta: &Config{Project: "gcp-project", Region: "us-central1"},
		},
	}

	for tn, tc := range cases {
		is := &terraform.InstanceState{
			ID:         tc.Attributes["name"],
			Attributes: tc.Attributes,
		}

		is, err := migrateEndpointsService(tc.StateVersion, is, tc.Meta)

		if err != nil {
			t.Fatalf("bad: %s, err: %#v", tn, err)
		}

		if !reflect.DeepEqual(is.Attributes, tc.ExpectedAttributes) {
			t.Fatalf("Attributes should be `%s` but are `%s`", tc.ExpectedAttributes, is.Attributes)
		}
	}
}

func testAccEndpointsService_basic(serviceId, project, rev string) string {
	return fmt.Sprintf(`
resource "google_endpoints_service" "endpoints_service" {
  service_name   = "%[1]s.endpoints.%[2]s.cloud.goog"
  project        = "%[2]s"
  openapi_config = <<EOF
swagger: "2.0"
info:
  description: "A simple Google Cloud Endpoints API example."
  title: "Endpoints Example, rev. %[3]s"
  version: "1.0.0"
host: "%[1]s.endpoints.%[2]s.cloud.goog"
basePath: "/"
consumes:
- "application/json"
produces:
- "application/json"
schemes:
- "https"
paths:
  "/echo":
    post:
      description: "Echo back a given message."
      operationId: "echo"
      produces:
      - "application/json"
      responses:
        200:
          description: "Echo"
          schema:
            $ref: "#/definitions/echoMessage"
      parameters:
      - description: "Message to echo"
        in: body
        name: message
        required: true
        schema:
          $ref: "#/definitions/echoMessage"
      security:
      - api_key: []
definitions:
  echoMessage:
    properties:
      message:
        type: "string"
EOF

}
`, serviceId, project, rev)
}

func testAccEndpointsService_grpc(serviceId, project string) string {
	return fmt.Sprintf(`
resource "google_endpoints_service" "endpoints_service" {
  service_name = "%[1]s.endpoints.%[2]s.cloud.goog"
  project      = "%[2]s"
  grpc_config  = <<EOF
type: google.api.Service
config_version: 3
name: %[1]s.endpoints.%[2]s.cloud.goog
usage:
  rules:
  - selector: endpoints.examples.bookstore.Bookstore.ListShelves
    allow_unregistered_calls: true
EOF

  protoc_output_base64 = filebase64("test-fixtures/test_api_descriptor.pb")
}
`, serviceId, project)
}

func testAccCheckEndpointExistsByName(t *testing.T, serviceId string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		config := googleProviderConfig(t)
		service, err := config.NewServiceManClient(config.userAgent).Services.GetConfig(
			fmt.Sprintf("%s.endpoints.%s.cloud.goog", serviceId, config.Project)).Do()
		if err != nil {
			return err
		}
		if service != nil {
			return nil
		} else {
			return fmt.Errorf("Service %s.endpoints.%s.cloud.goog does not seem to exist.", serviceId, config.Project)
		}
	}
}

func testAccCheckEndpointServiceDestroyProducer(t *testing.T) func(s *terraform.State) error {
	return func(s *terraform.State) error {
		config := googleProviderConfig(t)

		for name, rs := range s.RootModule().Resources {
			if strings.HasPrefix(name, "data.") {
				continue
			}
			if rs.Type != "google_endpoints_service" {
				continue
			}

			serviceName := rs.Primary.Attributes["service_name"]
			service, err := config.NewServiceManClient(config.userAgent).Services.GetConfig(serviceName).Do()
			if err != nil {
				// ServiceManagement returns 403 if service doesn't exist.
				if !isGoogleApiErrorWithCode(err, 403) {
					return err
				}
			}
			if service != nil {
				return fmt.Errorf("expected service %q to have been destroyed, got %+v", service.Name, service)
			}
		}
		return nil
	}
}
<|endoftext|>


<commit_before>package base

import (
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"encoding/json"

	"mr/app/models"
)

func NewProduct(account_id, token string, jsonStr []byte) (string, int) {

	/* Función que recibe los valores de nickname como string, y como JSON del producto nuevo que se insertará en la BD */

	if CheckToken(token) == false {
		return "token no válido", 403   // Verifica que sea un token válido
	} else if UserExists("_id", account_id) == false{
		return "Usuario no encontrado", 403		//Verifica que el account_id exista en la base de datos
	}

	productVals := &models.Product{}
	json.Unmarshal(jsonStr, productVals)

	if ProductExists(productVals.N_serial , account_id) == true {
		return "El número de serial del producto ya existe",400
	}

	session, err := mgo.Dial(HostDB)

	if err != nil {
		return "No se ha conectado a la base de datos", 500
    }
    defer session.Close()

    session.SetMode(mgo.Monotonic, true)
    con := session.DB(NameDB).C(CollectionDB)

    colQuerier := bson.M{"_id": bson.ObjectIdHex(account_id)}  // Busca el documento por nickname
	change := bson.M{"$push": bson.M{"products": productVals} } // Inserta en el array de productos
	err = con.Update(colQuerier, change)

	if err != nil {
		return "Usuario no encontrado", 401
	}

	return "Producto agregado en el almacén", 201

}

func ProductExists(serial, account_id string) bool {

	/* Función que verifica si existe el número de serial del producto en la base de datos */

	session, err := mgo.Dial(HostDB)
	if err != nil {
		return false
    }
    defer session.Close()

    session.SetMode(mgo.Monotonic, true)
    con := session.DB(NameDB).C(CollectionDB)

    type Result struct{
    	Products []models.Product `json:"products"`
    }

    result := Result{}
    err = con.Find(bson.M{"_id": bson.ObjectIdHex(account_id), "products.n_serial": serial}).Select(bson.M{"products.n_serial": 1, "_id": 0}).One(&result)

    if err != nil{
    	return false
    } else{
    	return true
    }
}

func UpdateProductAmount(account_id, n_serial string, token string, jsonStr []byte) (string, int) {

	/* Función que recibe los valores de ACCOUNT_ID como string, y como JSON la nueva cantidad del producto con n_serial */

	if CheckToken(token) == false {
		return "token no válido", 403   // Verifica que sea un token válido
	} else if UserExists("_id", account_id) == false{
		return "Usuario no encontrado", 403		//Verifica que el account_id exista en la base de datos
	}

	productVals := &models.Product{}
	json.Unmarshal(jsonStr, productVals)

	session, err := mgo.Dial(HostDB)

	if err != nil {
		return "No se ha conectado a la base de datos", 500
    }
    defer session.Close()

    session.SetMode(mgo.Monotonic, true)
    con := session.DB(NameDB).C(CollectionDB)

    colQuerier := bson.M{"_id": bson.ObjectIdHex(account_id), "products.n_serial": n_serial}  // Busca el documento por ACCOUNT_ID
	change := bson.M{"$set": bson.M{"products.$.quantity": productVals.Quantity} } // Inserta en el array de productos
	err = con.Update(colQuerier, change)

	if err != nil {
		return "Producto no encontrado", 400
	}

	return "Cantidad de productos actualizada", 200

}

func UpdateProduct(account_id, n_serial string, token string, jsonStr []byte) (string, int){

	/* Función que actualiza un producto para un usuario en la base de datos
		Se reciben el id de usuario y el número de serie unico del producto */

	if CheckToken(token) == false {
		return "token no válido", 403   // Verifica que sea un token válido
	} else if UserExists("_id", account_id) == false{
		return "Usuario no encontrado", 403		//Verifica que el account_id exista en la base de datos
	}

	productVals := &models.Product{}
	json.Unmarshal(jsonStr, productVals)

	if ProductExists(productVals.N_serial , account_id) == true {
		return "El número de serial del producto ya existe",400
	}

	session, err := mgo.Dial(HostDB)

	if err != nil {
		return "No se ha conectado a la base de datos", 500
    }
    defer session.Close()

    session.SetMode(mgo.Monotonic, true)
    con := session.DB(NameDB).C(CollectionDB)

    colQuerier := bson.M{"_id": bson.ObjectIdHex(account_id), "products.n_serial": n_serial}  // Busca el documento por ACCOUNT_ID
	change := bson.M{"$set": bson.M{"products.$": productVals} } // Inserta en el array de productos
	err = con.Update(colQuerier, change)

	if err != nil {
		return "Producto no encontrado", 400
	}

	return "Datos de producto actualizados", 200

}

func EraseProduct(account_id, n_serial string, token string) (string, int){

	/* Función que elmina un producto del usuario recibido de la base de datos
		se recibe el id de usuario y el numero de serie unico del producto */

	if CheckToken(token) == false {
		return "token no válido", 403   // Verifica que sea un token válido
	} else if UserExists("_id", account_id) == false{
		return "Usuario no encontrado", 403		//Verifica que el account_id exista en la base de datos
	}

	session, err := mgo.Dial(HostDB)

	if err != nil {
		return "No se ha conectado a la base de datos", 500
    }
    defer session.Close()

    session.SetMode(mgo.Monotonic, true)
    con := session.DB(NameDB).C(CollectionDB)

    colQuerier := bson.M{"_id": bson.ObjectIdHex(account_id)}  // Busca el documento por ACCOUNT_ID
	change := bson.M{"$pull": bson.M{"products": bson.M{"n_serial":n_serial } } } // Elimina en el array de productos en base al número de serial
	err = con.Update(colQuerier, change)

	if err != nil {
		return "Producto no encontrado", 400
	}

	return "Producto eliminado", 200

}

func GetProducts(all bool, account_id string, token, n_serial string) (string, int, interface{}) {

	/* 	Función que busca en la base de datos uno o más productos
		"all" es un valor booleano que indica si se quieren todos los productos o uno en específico
		Recibe también los valores de id de la cuenta y el numero de serial del producto en caso de que se requiera
	*/

	data := make(map[string]interface{})

	if CheckToken(token) == false {
		return "token no válido", 403, data   // Verifica que sea un token válido
	} else if UserExists("_id", account_id) == false {
		return "Usuario no encontrado", 403, data		//Verifica que el account_id exista en la base de datos
	}

	session, err := mgo.Dial(HostDB)
	if err != nil {
		return "No se ha conectado a la base de datos", 500, data
    }
    defer session.Close()

    session.SetMode(mgo.Monotonic, true)
    con := session.DB(NameDB).C(CollectionDB)

    type Result struct{
    	Products 	[]models.Product 	`json:"products"`
    }

    result := Result{}

    if all == false {  // Si está desactivada la opción de todos los productos buscará uno en específico de acuerdo al n_serial indicado
    	err = con.Find(bson.M{"_id": bson.ObjectIdHex(account_id)}).Select(bson.M{"products": bson.M{"$elemMatch": bson.M{"n_serial":n_serial} }, "_id":0 }).One(&result)
    } else{
    	err = con.Find(bson.M{"_id": bson.ObjectIdHex(account_id)}).Select(bson.M{"products": 1, "_id":0 }).One(&result)
    }

    if err != nil  {
    	return "No se encontró el producto", 400, data
    }

	data["producto"] = result.Products
	msj := ""

	if len(result.Products) == 0 {
		msj = "No hay productos en el inventario"  // Retorna el mensaje de acuerdo a la cantidad de productos encontrada
	} else if len(result.Products) == 1 {
		msj = "Producto encontrado"
	} else {
		msj = "Productos encontrados"
	}

    return msj, 200, data["producto"]
}<commit_msg>Mejora en las respuestas de GET uno o más productos<commit_after>package base

import (
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"encoding/json"

	"mr/app/models"
)

func NewProduct(account_id, token string, jsonStr []byte) (string, int) {

	/* Función que recibe los valores de nickname como string, y como JSON del producto nuevo que se insertará en la BD */

	if CheckToken(token) == false {
		return "token no válido", 403   // Verifica que sea un token válido
	} else if UserExists("_id", account_id) == false{
		return "Usuario no encontrado", 403		//Verifica que el account_id exista en la base de datos
	}

	productVals := &models.Product{}
	json.Unmarshal(jsonStr, productVals)

	if ProductExists(productVals.N_serial , account_id) == true {
		return "El número de serial del producto ya existe",400
	}

	session, err := mgo.Dial(HostDB)

	if err != nil {
		return "No se ha conectado a la base de datos", 500
    }
    defer session.Close()

    session.SetMode(mgo.Monotonic, true)
    con := session.DB(NameDB).C(CollectionDB)

    colQuerier := bson.M{"_id": bson.ObjectIdHex(account_id)}  // Busca el documento por nickname
	change := bson.M{"$push": bson.M{"products": productVals} } // Inserta en el array de productos
	err = con.Update(colQuerier, change)

	if err != nil {
		return "Usuario no encontrado", 401
	}

	return "Producto agregado en el almacén", 201

}

func ProductExists(serial, account_id string) bool {

	/* Función que verifica si existe el número de serial del producto en la base de datos */

	session, err := mgo.Dial(HostDB)
	if err != nil {
		return false
    }
    defer session.Close()

    session.SetMode(mgo.Monotonic, true)
    con := session.DB(NameDB).C(CollectionDB)

    type Result struct{
    	Products []models.Product `json:"products"`
    }

    result := Result{}
    err = con.Find(bson.M{"_id": bson.ObjectIdHex(account_id), "products.n_serial": serial}).Select(bson.M{"products.n_serial": 1, "_id": 0}).One(&result)

    if err != nil{
    	return false
    } else{
    	return true
    }
}

func UpdateProductAmount(account_id, n_serial string, token string, jsonStr []byte) (string, int) {

	/* Función que recibe los valores de ACCOUNT_ID como string, y como JSON la nueva cantidad del producto con n_serial */

	if CheckToken(token) == false {
		return "token no válido", 403   // Verifica que sea un token válido
	} else if UserExists("_id", account_id) == false{
		return "Usuario no encontrado", 403		//Verifica que el account_id exista en la base de datos
	}

	productVals := &models.Product{}
	json.Unmarshal(jsonStr, productVals)

	session, err := mgo.Dial(HostDB)

	if err != nil {
		return "No se ha conectado a la base de datos", 500
    }
    defer session.Close()

    session.SetMode(mgo.Monotonic, true)
    con := session.DB(NameDB).C(CollectionDB)

    colQuerier := bson.M{"_id": bson.ObjectIdHex(account_id), "products.n_serial": n_serial}  // Busca el documento por ACCOUNT_ID
	change := bson.M{"$set": bson.M{"products.$.quantity": productVals.Quantity} } // Inserta en el array de productos
	err = con.Update(colQuerier, change)

	if err != nil {
		return "Producto no encontrado", 400
	}

	return "Cantidad de productos actualizada", 200

}

func UpdateProduct(account_id, n_serial string, token string, jsonStr []byte) (string, int){

	/* Función que actualiza un producto para un usuario en la base de datos
		Se reciben el id de usuario y el número de serie unico del producto */

	if CheckToken(token) == false {
		return "token no válido", 403   // Verifica que sea un token válido
	} else if UserExists("_id", account_id) == false{
		return "Usuario no encontrado", 403		//Verifica que el account_id exista en la base de datos
	}

	productVals := &models.Product{}
	json.Unmarshal(jsonStr, productVals)

	if ProductExists(productVals.N_serial , account_id) == true {
		return "El número de serial del producto ya existe",400
	}

	session, err := mgo.Dial(HostDB)

	if err != nil {
		return "No se ha conectado a la base de datos", 500
    }
    defer session.Close()

    session.SetMode(mgo.Monotonic, true)
    con := session.DB(NameDB).C(CollectionDB)

    colQuerier := bson.M{"_id": bson.ObjectIdHex(account_id), "products.n_serial": n_serial}  // Busca el documento por ACCOUNT_ID
	change := bson.M{"$set": bson.M{"products.$": productVals} } // Inserta en el array de productos
	err = con.Update(colQuerier, change)

	if err != nil {
		return "Producto no encontrado", 400
	}

	return "Datos de producto actualizados", 200

}

func EraseProduct(account_id, n_serial string, token string) (string, int){

	/* Función que elmina un producto del usuario recibido de la base de datos
		se recibe el id de usuario y el numero de serie unico del producto */

	if CheckToken(token) == false {
		return "token no válido", 403   // Verifica que sea un token válido
	} else if UserExists("_id", account_id) == false{
		return "Usuario no encontrado", 403		//Verifica que el account_id exista en la base de datos
	}

	session, err := mgo.Dial(HostDB)

	if err != nil {
		return "No se ha conectado a la base de datos", 500
    }
    defer session.Close()

    session.SetMode(mgo.Monotonic, true)
    con := session.DB(NameDB).C(CollectionDB)

    colQuerier := bson.M{"_id": bson.ObjectIdHex(account_id)}  // Busca el documento por ACCOUNT_ID
	change := bson.M{"$pull": bson.M{"products": bson.M{"n_serial":n_serial } } } // Elimina en el array de productos en base al número de serial
	err = con.Update(colQuerier, change)

	if err != nil {
		return "Producto no encontrado", 400
	}

	return "Producto eliminado", 200

}

func GetProducts(all bool, account_id string, token, n_serial string) (string, int, interface{}) {

	/* 	Función que busca en la base de datos uno o más productos
		"all" es un valor booleano que indica si se quieren todos los productos o uno en específico
		Recibe también los valores de id de la cuenta y el numero de serial del producto en caso de que se requiera
	*/

	data := make(map[string]interface{})

	if CheckToken(token) == false {
		return "token no válido", 403, data   // Verifica que sea un token válido
	} else if UserExists("_id", account_id) == false {
		return "Usuario no encontrado", 403, data		//Verifica que el account_id exista en la base de datos
	}

	session, err := mgo.Dial(HostDB)
	if err != nil {
		return "No se ha conectado a la base de datos", 500, data
    }
    defer session.Close()

    session.SetMode(mgo.Monotonic, true)
    con := session.DB(NameDB).C(CollectionDB)

    type Result struct{
    	Products 	[]models.Product 	`json:"products"`
    }

    result := Result{}

    if all == false {  // Si está desactivada la opción de todos los productos buscará uno en específico de acuerdo al n_serial indicado
    	err = con.Find(bson.M{"_id": bson.ObjectIdHex(account_id)}).Select(bson.M{"products": bson.M{"$elemMatch": bson.M{"n_serial":n_serial} }, "_id":0 }).One(&result)
    } else{
    	err = con.Find(bson.M{"_id": bson.ObjectIdHex(account_id)}).Select(bson.M{"products": 1, "_id":0 }).One(&result)
    }

    if err != nil  {
    	return "No se encontró el producto", 400, data
    }

	data["producto"] = result.Products
	productsFind := len(result.Products) // Cantidad de productos encontrados

	if productsFind == 0 {
		if all == true {
			return "No hay productos en el inventario", 200, data["producto"]
		} else {
			return "Producto no encontrado", 400, data["producto"]
		}
	} else if productsFind == 1 {
		return "Producto encontrado", 200, data["producto"]
	} else {
		return "Productos encontrados", 200, data["producto"]
	}

}<|endoftext|>


<commit_before>package GoSDK

import (
//"fmt"
)

const (
	_BUCKET_SETS_PREAMBLE = "/api/v/4/bucket_sets/"
)

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

func (d *DevClient) GetBucketSets(systemKey string) ([]interface{}, error) {
	return getBucketSets(d, _BUCKET_SETS_PREAMBLE+systemKey)
}

func (u *UserClient) GetBucketSets(systemKey string) ([]interface{}, error) {
	return getBucketSets(u, _BUCKET_SETS_PREAMBLE+systemKey)
}

func (dv *DeviceClient) GetBucketSets(systemKey string) ([]interface{}, error) {
	return getBucketSets(dv, _BUCKET_SETS_PREAMBLE+systemKey)
}

func getBucketSets(c cbClient, endpoint string) ([]interface{}, error) {
	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(c, endpoint, nil, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return nil, err
	}
	return resp.Body.([]interface{}), nil
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

func (d *DevClient) GetBucketSet(systemKey, deploymentName string) (map[string]interface{}, error) {
	return getBucketSet(d, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName)
}

func (u *UserClient) GetBucketSet(systemKey, deploymentName string) (map[string]interface{}, error) {
	return getBucketSet(u, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName)
}

func (dv *DeviceClient) GetBucketSet(systemKey, deploymentName string) (map[string]interface{}, error) {
	return getBucketSet(dv, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName)
}

func getBucketSet(c cbClient, endpoint string) (map[string]interface{}, error) {
	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(c, endpoint, nil, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return nil, err
	}
	return resp.Body.(map[string]interface{}), nil
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

func (d *DevClient) GetBucketSetFiles(systemKey, deploymentName, box string) (map[string]interface{}, error) {
	return getBucketSetFiles(d, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/files", box)
}

func (u *UserClient) GetBucketSetFiles(systemKey, deploymentName, box string) (map[string]interface{}, error) {
	return getBucketSetFiles(u, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/files", box)
}

func (dv *DeviceClient) GetBucketSetFiles(systemKey, deploymentName, box string) (map[string]interface{}, error) {
	return getBucketSetFiles(dv, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/files", box)
}

func getBucketSetFiles(c cbClient, endpoint, box string) (map[string]interface{}, error) {
	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}
	qs := map[string]string{"box": box}
	resp, err := get(c, endpoint, qs, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return nil, err
	}
	return resp.Body.(map[string]interface{}), nil
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

func (d *DevClient) CreateBucketSetFile(systemKey, deploymentName, box, relPath, contents string) (map[string]interface{}, error) {
	return createBucketSetFile(d, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/create", box, relPath, contents)
}

func (u *UserClient) CreateBucketSetFile(systemKey, deploymentName, box, relPath, contents string) (map[string]interface{}, error) {
	return createBucketSetFile(u, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/create", box, relPath, contents)
}

func (dv *DeviceClient) CreateBucketSetFile(systemKey, deploymentName, box, relPath, contents string) (map[string]interface{}, error) {
	return createBucketSetFile(dv, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/create", box, relPath, contents)
}

func createBucketSetFile(c cbClient, endpoint, box, relPath, contents string) (map[string]interface{}, error) {

	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}

	data := map[string]interface{}{
		"box":      box,
		"path":     relPath,
		"contents": contents,
	}

	resp, err := post(c, endpoint, data, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return nil, err
	}
	return resp.Body.(map[string]interface{}), nil
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

func (d *DevClient) GetBucketSetFile(systemKey, deploymentName, box, relPath string) (map[string]interface{}, error) {
	return getBucketSetFile(d, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/meta", box, relPath)
}

func (u *UserClient) GetBucketSetFile(systemKey, deploymentName, box, relPath string) (map[string]interface{}, error) {
	return getBucketSetFile(u, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/meta", box, relPath)
}

func (dv *DeviceClient) GetBucketSetFile(systemKey, deploymentName, box, relPath string) (map[string]interface{}, error) {
	return getBucketSetFile(dv, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/meta", box, relPath)
}

func getBucketSetFile(c cbClient, endpoint, box, relPath string) (map[string]interface{}, error) {
	queries := map[string]string{"box": box, "path": relPath}
	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(c, endpoint, queries, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return nil, err
	}
	return resp.Body.(map[string]interface{}), nil
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

func (d *DevClient) ReadBucketSetFile(systemKey, deploymentName, box, relPath string) (string, error) {
	return readBucketSetFile(d, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/read", box, relPath)
}

func (u *UserClient) ReadGetBucketSetFile(systemKey, deploymentName, box, relPath string) (string, error) {
	return readBucketSetFile(u, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/read", box, relPath)
}

func (dv *DeviceClient) ReadGetBucketSetFile(systemKey, deploymentName, box, relPath string) (string, error) {
	return readBucketSetFile(dv, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/read", box, relPath)
}

func readBucketSetFile(c cbClient, endpoint, box, relPath string) (string, error) {
	queries := map[string]string{"box": box, "path": relPath}
	creds, err := c.credentials()
	if err != nil {
		return "", err
	}
	resp, err := get(c, endpoint, queries, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return "", err
	}
	return resp.Body.(string), nil
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

func (d *DevClient) CopyBucketSetFile(systemKey, deploymentName, fromBox, fromPath, toBox, toPath string) error {
	return copyBucketSetFile(d, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/copy", fromBox, fromPath, toBox, toPath)
}

func (u *UserClient) CopyBucketSetFile(systemKey, deploymentName, fromBox, fromPath, toBox, toPath string) error {
	return copyBucketSetFile(u, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/copy", fromBox, fromPath, toBox, toPath)
}

func (dv *DeviceClient) CopyBucketSetFile(systemKey, deploymentName, fromBox, fromPath, toBox, toPath string) error {
	return copyBucketSetFile(dv, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/copy", fromBox, fromPath, toBox, toPath)
}

func copyBucketSetFile(c cbClient, endpoint, fromBox, fromPath, toBox, toPath string) error {
	creds, err := c.credentials()
	if err != nil {
		return err
	}
	data := map[string]interface{}{
		"from_box":  fromBox,
		"from_path": fromPath,
		"to_box":    toBox,
		"to_path":   toPath,
	}
	_, err = post(c, endpoint, data, creds, nil)
	return err
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

func (d *DevClient) MoveBucketSetFile(systemKey, deploymentName, fromBox, fromPath, toBox, toPath string) error {
	return moveBucketSetFile(d, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/move", fromBox, fromPath, toBox, toPath)
}

func (u *UserClient) MoveBucketSetFile(systemKey, deploymentName, fromBox, fromPath, toBox, toPath string) error {
	return moveBucketSetFile(u, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/move", fromBox, fromPath, toBox, toPath)
}

func (dv *DeviceClient) MoveBucketSetFile(systemKey, deploymentName, fromBox, fromPath, toBox, toPath string) error {
	return moveBucketSetFile(dv, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/move", fromBox, fromPath, toBox, toPath)
}

func moveBucketSetFile(c cbClient, endpoint, fromBox, fromPath, toBox, toPath string) error {
	creds, err := c.credentials()
	if err != nil {
		return err
	}
	data := map[string]interface{}{
		"from_box":  fromBox,
		"from_path": fromPath,
		"to_box":    toBox,
		"to_path":   toPath,
	}
	_, err = post(c, endpoint, data, creds, nil)
	return err
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

func (d *DevClient) DeleteBucketSetFile(systemKey, deploymentName, box, relPath string) error {
	return deleteBucketSetFile(d, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/delete", box, relPath)
}

func (u *UserClient) DeleteBucketSetFile(systemKey, deploymentName, box, relPath string) error {
	return deleteBucketSetFile(u, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/delete", box, relPath)
}

func (dv *DeviceClient) DeleteBucketSetFile(systemKey, deploymentName, box, relPath string) error {
	return deleteBucketSetFile(dv, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/delete", box, relPath)
}

func deleteBucketSetFile(c cbClient, endpoint, box, relPath string) error {

	creds, err := c.credentials()
	if err != nil {
		return err
	}

	data := map[string]interface{}{
		"box":  box,
		"path": relPath,
	}

	_, err = post(c, endpoint, data, creds, nil)
	return err
}
<commit_msg>added create and delete bucket set<commit_after>package GoSDK

import (
//"fmt"
)

const (
	_BUCKET_SETS_PREAMBLE = "/api/v/4/bucket_sets/"
)

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

func (d *DevClient) CreateBucketSet(systemKey, name string, config map[string]interface{}) (map[string]interface{}, error) {
	return createBucketSet(d, _BUCKET_SETS_PREAMBLE+systemKey, name, config)
}

func (u *UserClient) CreateBucketSet(systemKey, name string, config map[string]interface{}) (map[string]interface{}, error) {
	return createBucketSet(u, _BUCKET_SETS_PREAMBLE+systemKey, name, config)
}

func (dv *DeviceClient) CreateBucketSet(systemKey, name string, config map[string]interface{}) (map[string]interface{}, error) {
	return createBucketSet(dv, _BUCKET_SETS_PREAMBLE+systemKey, name, config)
}

func createBucketSet(c cbClient, endpoint, name string, config map[string]interface{}) (map[string]interface{}, error) {
	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}
	config["name"] = name
	resp, err := post(c, endpoint, config, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return nil, err
	}
	return resp.Body.(map[string]interface{}), nil
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

func (d *DevClient) DeleteBucketSet(systemKey, name string) (map[string]interface{}, error) {
	return deleteBucketSet(d, _BUCKET_SETS_PREAMBLE+systemKey+"/"+name)
}

func (u *UserClient) DeleteBucketSet(systemKey, name string) (map[string]interface{}, error) {
	return deleteBucketSet(u, _BUCKET_SETS_PREAMBLE+systemKey+"/"+name)
}

func (dv *DeviceClient) DeleteBucketSet(systemKey, name string) (map[string]interface{}, error) {
	return deleteBucketSet(dv, _BUCKET_SETS_PREAMBLE+systemKey+"/"+name)
}

func deleteBucketSet(c cbClient, endpoint string) (map[string]interface{}, error) {
	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := delete(c, endpoint, nil, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return nil, err
	}
	return nil, nil
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

func (d *DevClient) GetBucketSets(systemKey string) ([]interface{}, error) {
	return getBucketSets(d, _BUCKET_SETS_PREAMBLE+systemKey)
}

func (u *UserClient) GetBucketSets(systemKey string) ([]interface{}, error) {
	return getBucketSets(u, _BUCKET_SETS_PREAMBLE+systemKey)
}

func (dv *DeviceClient) GetBucketSets(systemKey string) ([]interface{}, error) {
	return getBucketSets(dv, _BUCKET_SETS_PREAMBLE+systemKey)
}

func getBucketSets(c cbClient, endpoint string) ([]interface{}, error) {
	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(c, endpoint, nil, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return nil, err
	}
	return resp.Body.([]interface{}), nil
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

func (d *DevClient) GetBucketSet(systemKey, deploymentName string) (map[string]interface{}, error) {
	return getBucketSet(d, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName)
}

func (u *UserClient) GetBucketSet(systemKey, deploymentName string) (map[string]interface{}, error) {
	return getBucketSet(u, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName)
}

func (dv *DeviceClient) GetBucketSet(systemKey, deploymentName string) (map[string]interface{}, error) {
	return getBucketSet(dv, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName)
}

func getBucketSet(c cbClient, endpoint string) (map[string]interface{}, error) {
	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(c, endpoint, nil, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return nil, err
	}
	return resp.Body.(map[string]interface{}), nil
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

func (d *DevClient) GetBucketSetFiles(systemKey, deploymentName, box string) (map[string]interface{}, error) {
	return getBucketSetFiles(d, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/files", box)
}

func (u *UserClient) GetBucketSetFiles(systemKey, deploymentName, box string) (map[string]interface{}, error) {
	return getBucketSetFiles(u, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/files", box)
}

func (dv *DeviceClient) GetBucketSetFiles(systemKey, deploymentName, box string) (map[string]interface{}, error) {
	return getBucketSetFiles(dv, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/files", box)
}

func getBucketSetFiles(c cbClient, endpoint, box string) (map[string]interface{}, error) {
	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}
	qs := map[string]string{"box": box}
	resp, err := get(c, endpoint, qs, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return nil, err
	}
	return resp.Body.(map[string]interface{}), nil
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

func (d *DevClient) CreateBucketSetFile(systemKey, deploymentName, box, relPath, contents string) (map[string]interface{}, error) {
	return createBucketSetFile(d, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/create", box, relPath, contents)
}

func (u *UserClient) CreateBucketSetFile(systemKey, deploymentName, box, relPath, contents string) (map[string]interface{}, error) {
	return createBucketSetFile(u, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/create", box, relPath, contents)
}

func (dv *DeviceClient) CreateBucketSetFile(systemKey, deploymentName, box, relPath, contents string) (map[string]interface{}, error) {
	return createBucketSetFile(dv, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/create", box, relPath, contents)
}

func createBucketSetFile(c cbClient, endpoint, box, relPath, contents string) (map[string]interface{}, error) {

	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}

	data := map[string]interface{}{
		"box":      box,
		"path":     relPath,
		"contents": contents,
	}

	resp, err := post(c, endpoint, data, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return nil, err
	}
	return resp.Body.(map[string]interface{}), nil
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

func (d *DevClient) GetBucketSetFile(systemKey, deploymentName, box, relPath string) (map[string]interface{}, error) {
	return getBucketSetFile(d, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/meta", box, relPath)
}

func (u *UserClient) GetBucketSetFile(systemKey, deploymentName, box, relPath string) (map[string]interface{}, error) {
	return getBucketSetFile(u, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/meta", box, relPath)
}

func (dv *DeviceClient) GetBucketSetFile(systemKey, deploymentName, box, relPath string) (map[string]interface{}, error) {
	return getBucketSetFile(dv, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/meta", box, relPath)
}

func getBucketSetFile(c cbClient, endpoint, box, relPath string) (map[string]interface{}, error) {
	queries := map[string]string{"box": box, "path": relPath}
	creds, err := c.credentials()
	if err != nil {
		return nil, err
	}
	resp, err := get(c, endpoint, queries, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return nil, err
	}
	return resp.Body.(map[string]interface{}), nil
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

func (d *DevClient) ReadBucketSetFile(systemKey, deploymentName, box, relPath string) (string, error) {
	return readBucketSetFile(d, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/read", box, relPath)
}

func (u *UserClient) ReadGetBucketSetFile(systemKey, deploymentName, box, relPath string) (string, error) {
	return readBucketSetFile(u, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/read", box, relPath)
}

func (dv *DeviceClient) ReadGetBucketSetFile(systemKey, deploymentName, box, relPath string) (string, error) {
	return readBucketSetFile(dv, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/read", box, relPath)
}

func readBucketSetFile(c cbClient, endpoint, box, relPath string) (string, error) {
	queries := map[string]string{"box": box, "path": relPath}
	creds, err := c.credentials()
	if err != nil {
		return "", err
	}
	resp, err := get(c, endpoint, queries, creds, nil)
	resp, err = mapResponse(resp, err)
	if err != nil {
		return "", err
	}
	return resp.Body.(string), nil
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

func (d *DevClient) CopyBucketSetFile(systemKey, deploymentName, fromBox, fromPath, toBox, toPath string) error {
	return copyBucketSetFile(d, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/copy", fromBox, fromPath, toBox, toPath)
}

func (u *UserClient) CopyBucketSetFile(systemKey, deploymentName, fromBox, fromPath, toBox, toPath string) error {
	return copyBucketSetFile(u, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/copy", fromBox, fromPath, toBox, toPath)
}

func (dv *DeviceClient) CopyBucketSetFile(systemKey, deploymentName, fromBox, fromPath, toBox, toPath string) error {
	return copyBucketSetFile(dv, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/copy", fromBox, fromPath, toBox, toPath)
}

func copyBucketSetFile(c cbClient, endpoint, fromBox, fromPath, toBox, toPath string) error {
	creds, err := c.credentials()
	if err != nil {
		return err
	}
	data := map[string]interface{}{
		"from_box":  fromBox,
		"from_path": fromPath,
		"to_box":    toBox,
		"to_path":   toPath,
	}
	_, err = post(c, endpoint, data, creds, nil)
	return err
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

func (d *DevClient) MoveBucketSetFile(systemKey, deploymentName, fromBox, fromPath, toBox, toPath string) error {
	return moveBucketSetFile(d, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/move", fromBox, fromPath, toBox, toPath)
}

func (u *UserClient) MoveBucketSetFile(systemKey, deploymentName, fromBox, fromPath, toBox, toPath string) error {
	return moveBucketSetFile(u, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/move", fromBox, fromPath, toBox, toPath)
}

func (dv *DeviceClient) MoveBucketSetFile(systemKey, deploymentName, fromBox, fromPath, toBox, toPath string) error {
	return moveBucketSetFile(dv, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/move", fromBox, fromPath, toBox, toPath)
}

func moveBucketSetFile(c cbClient, endpoint, fromBox, fromPath, toBox, toPath string) error {
	creds, err := c.credentials()
	if err != nil {
		return err
	}
	data := map[string]interface{}{
		"from_box":  fromBox,
		"from_path": fromPath,
		"to_box":    toBox,
		"to_path":   toPath,
	}
	_, err = post(c, endpoint, data, creds, nil)
	return err
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

func (d *DevClient) DeleteBucketSetFile(systemKey, deploymentName, box, relPath string) error {
	return deleteBucketSetFile(d, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/delete", box, relPath)
}

func (u *UserClient) DeleteBucketSetFile(systemKey, deploymentName, box, relPath string) error {
	return deleteBucketSetFile(u, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/delete", box, relPath)
}

func (dv *DeviceClient) DeleteBucketSetFile(systemKey, deploymentName, box, relPath string) error {
	return deleteBucketSetFile(dv, _BUCKET_SETS_PREAMBLE+systemKey+"/"+deploymentName+"/file/delete", box, relPath)
}

func deleteBucketSetFile(c cbClient, endpoint, box, relPath string) error {

	creds, err := c.credentials()
	if err != nil {
		return err
	}

	data := map[string]interface{}{
		"box":  box,
		"path": relPath,
	}

	_, err = post(c, endpoint, data, creds, nil)
	return err
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/uber-common/cpustat/lib"
)

type pidList []int

func (pl *pidList) String() string {
	if pl == nil {
		return ""
	}
	ss := make([]string, len(*pl))
	for i, pid := range *pl {
		ss[i] = strconv.Itoa(pid)
	}
	return strings.Join(ss, ",")
}

func (pl *pidList) Set(s string) error {
	parts := strings.Split(s, ",")
	for _, part := range parts {
		pid, err := strconv.Atoi(part)
		if err != nil {
			return fmt.Errorf("invalid pid list component %q, expected an integer", part)
		}
		*pl = append(*pl, pid)
	}
	return nil
}

func main() {
	if err := run(); err != nil {
		log.Fatalln(err)
	}
}

func run() error {
	var (
		interval    = flag.Duration("i", 200*time.Millisecond, "duration between measurements")
		sampleCount = flag.Uint("n", 0, "Maximum number of samples to capture")
		pids        pidList
	)
	flag.Var(&pids, "p", "Comma separated PID list to profile")
	flag.Parse()

	if len(pids) == 0 {
		fmt.Fprintf(os.Stderr, "no pids provided")
		os.Exit(1)
	}

	procStats := cpustat.ProcStats{}
	procStatsReaderCount := len(pids)
	procStatsReaders := make([]*cpustat.ProcStatsSeekReader, procStatsReaderCount)

	samplesRemaining := int64(*sampleCount)
	if samplesRemaining == 0 {
		samplesRemaining = -1
	}

	for i, pid := range pids {
		procStatsReader := cpustat.ProcStatsSeekReader{
			PID: pid,
		}
		procStatsReaders[i] = &procStatsReader

		procStatsInitError := procStatsReader.Initialize()
		if procStatsInitError != nil {
			procStatsReaders[i] = nil
			procStatsReaderCount--
		}
	}

	if _, err := fmt.Printf("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n",
		"pid",
		"time",
		"proc.utime",
		"proc.stime",
		"proc.cutime",
		"proc.cstime",
		"proc.numthreads",
		"proc.rss",
		"proc.guesttime",
		"proc.cguesttime",
	); err != nil {
		return err
	}

	for procStatsReaderCount > 0 && samplesRemaining != 0 {
		startOfRead := time.Now()

		for i, procStatsReader := range procStatsReaders {
			if procStatsReader == nil {
				continue
			}

			procStatsError := procStatsReader.ReadStats(&procStats)
			if procStatsError != nil {
				procStatsReaders[i] = nil
				procStatsReaderCount--
				continue
			}

			if _, err := fmt.Printf(
				"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
				procStatsReader.PID,
				procStats.CaptureTime.UnixNano()/1e6,
				procStats.Utime,
				procStats.Stime,
				procStats.Cutime,
				procStats.Cstime,
				procStats.Numthreads,
				procStats.Rss,
				procStats.Guesttime,
				procStats.Cguesttime,
			); err != nil {
				return err
			}
		}

		if samplesRemaining > 0 {
			samplesRemaining--
		}

		if procStatsReaderCount > 0 && samplesRemaining != 0 {
			if adjustedSleep := *interval - time.Now().Sub(startOfRead); adjustedSleep > 0 {
				// TODO actually probably some minimum sleep tolerance
				time.Sleep(adjustedSleep)
			}
		}
	}

	return nil
}
<commit_msg>cpustat-raw: use a buffered writer, and stop printf-ing<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/uber-common/cpustat/lib"
)

type pidList []int

func (pl *pidList) String() string {
	if pl == nil {
		return ""
	}
	ss := make([]string, len(*pl))
	for i, pid := range *pl {
		ss[i] = strconv.Itoa(pid)
	}
	return strings.Join(ss, ",")
}

func (pl *pidList) Set(s string) error {
	parts := strings.Split(s, ",")
	for _, part := range parts {
		pid, err := strconv.Atoi(part)
		if err != nil {
			return fmt.Errorf("invalid pid list component %q, expected an integer", part)
		}
		*pl = append(*pl, pid)
	}
	return nil
}

func main() {
	if err := run(); err != nil {
		log.Fatalln(err)
	}
}

func run() error {
	var (
		interval    = flag.Duration("i", 200*time.Millisecond, "duration between measurements")
		sampleCount = flag.Uint("n", 0, "Maximum number of samples to capture")
		pids        pidList
	)
	flag.Var(&pids, "p", "Comma separated PID list to profile")
	flag.Parse()

	if len(pids) == 0 {
		fmt.Fprintf(os.Stderr, "no pids provided")
		os.Exit(1)
	}

	procStats := cpustat.ProcStats{}
	procStatsReaderCount := len(pids)
	procStatsReaders := make([]*cpustat.ProcStatsSeekReader, procStatsReaderCount)

	samplesRemaining := int64(*sampleCount)
	if samplesRemaining == 0 {
		samplesRemaining = -1
	}

	for i, pid := range pids {
		procStatsReader := cpustat.ProcStatsSeekReader{
			PID: pid,
		}
		procStatsReaders[i] = &procStatsReader

		procStatsInitError := procStatsReader.Initialize()
		if procStatsInitError != nil {
			procStatsReaders[i] = nil
			procStatsReaderCount--
		}
	}

	var (
		bufw = bufio.NewWriterSize(os.Stdout, 4096) // output buffer
		tmp  [256]byte                              // scratch space for marshaling integers
	)

	for i, part := range []string{
		"pid",
		"time",
		"proc.utime",
		"proc.stime",
		"proc.cutime",
		"proc.cstime",
		"proc.numthreads",
		"proc.rss",
		"proc.guesttime",
		"proc.cguesttime",
	} {
		if i > 0 {
			_, _ = bufw.WriteRune(',')
		}
		_, _ = bufw.WriteString(part)
	}
	_, _ = bufw.WriteRune('\n')
	if err := bufw.Flush(); err != nil {
		return err
	}

	for procStatsReaderCount > 0 && samplesRemaining != 0 {
		startOfRead := time.Now()

		for i, procStatsReader := range procStatsReaders {
			if procStatsReader == nil {
				continue
			}

			procStatsError := procStatsReader.ReadStats(&procStats)
			if procStatsError != nil {
				procStatsReaders[i] = nil
				procStatsReaderCount--
				continue
			}

			_, _ = bufw.Write(strconv.AppendInt(tmp[:], int64(procStatsReader.PID), 10))
			_, _ = bufw.WriteRune(',')
			_, _ = bufw.Write(strconv.AppendInt(tmp[:], procStats.CaptureTime.UnixNano()/1e6, 10))
			_, _ = bufw.WriteRune(',')
			_, _ = bufw.Write(strconv.AppendUint(tmp[:], procStats.Utime, 10))
			_, _ = bufw.WriteRune(',')
			_, _ = bufw.Write(strconv.AppendUint(tmp[:], procStats.Stime, 10))
			_, _ = bufw.WriteRune(',')
			_, _ = bufw.Write(strconv.AppendUint(tmp[:], procStats.Cutime, 10))
			_, _ = bufw.WriteRune(',')
			_, _ = bufw.Write(strconv.AppendUint(tmp[:], procStats.Cstime, 10))
			_, _ = bufw.WriteRune(',')
			_, _ = bufw.Write(strconv.AppendUint(tmp[:], procStats.Numthreads, 10))
			_, _ = bufw.WriteRune(',')
			_, _ = bufw.Write(strconv.AppendUint(tmp[:], procStats.Rss, 10))
			_, _ = bufw.WriteRune(',')
			_, _ = bufw.Write(strconv.AppendUint(tmp[:], procStats.Guesttime, 10))
			_, _ = bufw.WriteRune(',')
			_, _ = bufw.Write(strconv.AppendUint(tmp[:], procStats.Cguesttime, 10))
			_, _ = bufw.WriteRune('\n')
			if err := bufw.Flush(); err != nil {
				return err
			}
		}

		if samplesRemaining > 0 {
			samplesRemaining--
		}

		if procStatsReaderCount > 0 && samplesRemaining != 0 {
			if adjustedSleep := *interval - time.Now().Sub(startOfRead); adjustedSleep > 0 {
				// TODO actually probably some minimum sleep tolerance
				time.Sleep(adjustedSleep)
			}
		}
	}

	return nil
}
<|endoftext|>


<commit_before>/*
 *
 * Copyright 2014, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

// Package credentials implements various credentials supported by gRPC library,
// which encapsulate all the state needed by a client to authenticate with a
// server and make various assertions, e.g., about the client's identity, role,
// or whether it is authorized to make a particular call.
package credentials // import "google.golang.org/grpc/credentials"

import (
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"net"
	"strings"
	"time"

	"golang.org/x/net/context"
)

var (
	// alpnProtoStr are the specified application level protocols for gRPC.
	alpnProtoStr = []string{"h2"}
)

// Credentials defines the common interface all supported credentials must
// implement.
type Credentials interface {
	// GetRequestMetadata gets the current request metadata, refreshing
	// tokens if required. This should be called by the transport layer on
	// each request, and the data should be populated in headers or other
	// context. When supported by the underlying implementation, ctx can
	// be used for timeout and cancellation.
	// TODO(zhaoq): Define the set of the qualified keys instead of leaving
	// it as an arbitrary string.
	GetRequestMetadata(ctx context.Context) (map[string]string, error)
}

// ProtocolInfo provides information regarding the gRPC wire protocol version,
// security protocol, security protocol version in use, etc.
type ProtocolInfo struct {
	// ProtocolVersion is the gRPC wire protocol version.
	ProtocolVersion string
	// SecurityProtocol is the security protocol in use.
	SecurityProtocol string
	// SecurityVersion is the security protocol version.
	SecurityVersion string
}

// AuthInfo defines the common interface for the auth information the users are interested in.
type AuthInfo interface {
	Type() string
}

type authInfoKey struct{}

// NewContext creates a new context with authInfo attached.
func NewContext(ctx context.Context, authInfo AuthInfo) context.Context {
	return context.WithValue(ctx, authInfoKey{}, authInfo)
}

// FromContext returns the authInfo in ctx if it exists.
func FromContext(ctx context.Context) (authInfo AuthInfo, ok bool) {
	authInfo, ok = ctx.Value(authInfoKey{}).(AuthInfo)
	return
}

// TransportAuthenticator defines the common interface for all the live gRPC wire
// protocols and supported transport security protocols (e.g., TLS, SSL).
type TransportAuthenticator interface {
	// ClientHandshake does the authentication handshake specified by the corresponding
	// authentication protocol on rawConn for clients. It returns the authenticated
	// connection and the corresponding auth information about the connection.
	ClientHandshake(addr string, rawConn net.Conn, timeout time.Duration) (net.Conn, AuthInfo, error)
	// ServerHandshake does the authentication handshake for servers. It returns
	// the authenticated connection and the corresponding auth information about
	// the connection.
	ServerHandshake(rawConn net.Conn) (net.Conn, AuthInfo, error)
	// Info provides the ProtocolInfo of this TransportAuthenticator.
	Info() ProtocolInfo
	Credentials
}

type TLSInfo struct {
	state tls.ConnectionState
}

func (t TLSInfo) Type() string {
	return "tls"
}

// tlsCreds is the credentials required for authenticating a connection using TLS.
type tlsCreds struct {
	// TLS configuration
	config tls.Config
}

func (c tlsCreds) Info() ProtocolInfo {
	return ProtocolInfo{
		SecurityProtocol: "tls",
		SecurityVersion:  "1.2",
	}
}

// GetRequestMetadata returns nil, nil since TLS credentials does not have
// metadata.
func (c *tlsCreds) GetRequestMetadata(ctx context.Context) (map[string]string, error) {
	return nil, nil
}

type timeoutError struct{}

func (timeoutError) Error() string   { return "credentials: Dial timed out" }
func (timeoutError) Timeout() bool   { return true }
func (timeoutError) Temporary() bool { return true }

func (c *tlsCreds) ClientHandshake(addr string, rawConn net.Conn, timeout time.Duration) (_ net.Conn, _ AuthInfo, err error) {
	// borrow some code from tls.DialWithDialer
	var errChannel chan error
	if timeout != 0 {
		errChannel = make(chan error, 2)
		time.AfterFunc(timeout, func() {
			errChannel <- timeoutError{}
		})
	}
	if c.config.ServerName == "" {
		colonPos := strings.LastIndex(addr, ":")
		if colonPos == -1 {
			colonPos = len(addr)
		}
		c.config.ServerName = addr[:colonPos]
	}
	conn := tls.Client(rawConn, &c.config)
	if timeout == 0 {
		err = conn.Handshake()
	} else {
		go func() {
			errChannel <- conn.Handshake()
		}()
		err = <-errChannel
	}
	if err != nil {
		rawConn.Close()
		return nil, nil, err
	}
	// TODO(zhaoq): Omit the auth info for client now. It is more for
	// information than anything else.
	return conn, nil, nil
}

func (c *tlsCreds) ServerHandshake(rawConn net.Conn) (net.Conn, AuthInfo, error) {
	conn := tls.Server(rawConn, &c.config)
	if err := conn.Handshake(); err != nil {
		rawConn.Close()
		return nil, nil, err
	}
	return conn, &TLSInfo{ conn.ConnectionState() }, nil
}

// NewTLS uses c to construct a TransportAuthenticator based on TLS.
func NewTLS(c *tls.Config) TransportAuthenticator {
	tc := &tlsCreds{*c}
	tc.config.NextProtos = alpnProtoStr
	return tc
}

// NewClientTLSFromCert constructs a TLS from the input certificate for client.
func NewClientTLSFromCert(cp *x509.CertPool, serverName string) TransportAuthenticator {
	return NewTLS(&tls.Config{ServerName: serverName, RootCAs: cp})
}

// NewClientTLSFromFile constructs a TLS from the input certificate file for client.
func NewClientTLSFromFile(certFile, serverName string) (TransportAuthenticator, error) {
	b, err := ioutil.ReadFile(certFile)
	if err != nil {
		return nil, err
	}
	cp := x509.NewCertPool()
	if !cp.AppendCertsFromPEM(b) {
		return nil, fmt.Errorf("credentials: failed to append certificates")
	}
	return NewTLS(&tls.Config{ServerName: serverName, RootCAs: cp}), nil
}

// NewServerTLSFromCert constructs a TLS from the input certificate for server.
func NewServerTLSFromCert(cert *tls.Certificate) TransportAuthenticator {
	return NewTLS(&tls.Config{Certificates: []tls.Certificate{*cert}})
}

// NewServerTLSFromFile constructs a TLS from the input certificate file and key
// file for server.
func NewServerTLSFromFile(certFile, keyFile string) (TransportAuthenticator, error) {
	cert, err := tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		return nil, err
	}
	return NewTLS(&tls.Config{Certificates: []tls.Certificate{cert}}), nil
}
<commit_msg>add comments<commit_after>/*
 *
 * Copyright 2014, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

// Package credentials implements various credentials supported by gRPC library,
// which encapsulate all the state needed by a client to authenticate with a
// server and make various assertions, e.g., about the client's identity, role,
// or whether it is authorized to make a particular call.
package credentials // import "google.golang.org/grpc/credentials"

import (
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"net"
	"strings"
	"time"

	"golang.org/x/net/context"
)

var (
	// alpnProtoStr are the specified application level protocols for gRPC.
	alpnProtoStr = []string{"h2"}
)

// Credentials defines the common interface all supported credentials must
// implement.
type Credentials interface {
	// GetRequestMetadata gets the current request metadata, refreshing
	// tokens if required. This should be called by the transport layer on
	// each request, and the data should be populated in headers or other
	// context. When supported by the underlying implementation, ctx can
	// be used for timeout and cancellation.
	// TODO(zhaoq): Define the set of the qualified keys instead of leaving
	// it as an arbitrary string.
	GetRequestMetadata(ctx context.Context) (map[string]string, error)
}

// ProtocolInfo provides information regarding the gRPC wire protocol version,
// security protocol, security protocol version in use, etc.
type ProtocolInfo struct {
	// ProtocolVersion is the gRPC wire protocol version.
	ProtocolVersion string
	// SecurityProtocol is the security protocol in use.
	SecurityProtocol string
	// SecurityVersion is the security protocol version.
	SecurityVersion string
}

// AuthInfo defines the common interface for the auth information the users are interested in.
type AuthInfo interface {
	Type() string
}

type authInfoKey struct{}

// NewContext creates a new context with authInfo attached.
func NewContext(ctx context.Context, authInfo AuthInfo) context.Context {
	return context.WithValue(ctx, authInfoKey{}, authInfo)
}

// FromContext returns the authInfo in ctx if it exists.
func FromContext(ctx context.Context) (authInfo AuthInfo, ok bool) {
	authInfo, ok = ctx.Value(authInfoKey{}).(AuthInfo)
	return
}

// TransportAuthenticator defines the common interface for all the live gRPC wire
// protocols and supported transport security protocols (e.g., TLS, SSL).
type TransportAuthenticator interface {
	// ClientHandshake does the authentication handshake specified by the corresponding
	// authentication protocol on rawConn for clients. It returns the authenticated
	// connection and the corresponding auth information about the connection.
	ClientHandshake(addr string, rawConn net.Conn, timeout time.Duration) (net.Conn, AuthInfo, error)
	// ServerHandshake does the authentication handshake for servers. It returns
	// the authenticated connection and the corresponding auth information about
	// the connection.
	ServerHandshake(rawConn net.Conn) (net.Conn, AuthInfo, error)
	// Info provides the ProtocolInfo of this TransportAuthenticator.
	Info() ProtocolInfo
	Credentials
}

// TLSInfo contains the auth information for a TLS authenticated connection.
// It implements the AuthInfo interface.
type TLSInfo struct {
	state tls.ConnectionState
}

func (t TLSInfo) Type() string {
	return "tls"
}

// tlsCreds is the credentials required for authenticating a connection using TLS.
type tlsCreds struct {
	// TLS configuration
	config tls.Config
}

func (c tlsCreds) Info() ProtocolInfo {
	return ProtocolInfo{
		SecurityProtocol: "tls",
		SecurityVersion:  "1.2",
	}
}

// GetRequestMetadata returns nil, nil since TLS credentials does not have
// metadata.
func (c *tlsCreds) GetRequestMetadata(ctx context.Context) (map[string]string, error) {
	return nil, nil
}

type timeoutError struct{}

func (timeoutError) Error() string   { return "credentials: Dial timed out" }
func (timeoutError) Timeout() bool   { return true }
func (timeoutError) Temporary() bool { return true }

func (c *tlsCreds) ClientHandshake(addr string, rawConn net.Conn, timeout time.Duration) (_ net.Conn, _ AuthInfo, err error) {
	// borrow some code from tls.DialWithDialer
	var errChannel chan error
	if timeout != 0 {
		errChannel = make(chan error, 2)
		time.AfterFunc(timeout, func() {
			errChannel <- timeoutError{}
		})
	}
	if c.config.ServerName == "" {
		colonPos := strings.LastIndex(addr, ":")
		if colonPos == -1 {
			colonPos = len(addr)
		}
		c.config.ServerName = addr[:colonPos]
	}
	conn := tls.Client(rawConn, &c.config)
	if timeout == 0 {
		err = conn.Handshake()
	} else {
		go func() {
			errChannel <- conn.Handshake()
		}()
		err = <-errChannel
	}
	if err != nil {
		rawConn.Close()
		return nil, nil, err
	}
	// TODO(zhaoq): Omit the auth info for client now. It is more for
	// information than anything else.
	return conn, nil, nil
}

func (c *tlsCreds) ServerHandshake(rawConn net.Conn) (net.Conn, AuthInfo, error) {
	conn := tls.Server(rawConn, &c.config)
	if err := conn.Handshake(); err != nil {
		rawConn.Close()
		return nil, nil, err
	}
	return conn, &TLSInfo{ conn.ConnectionState() }, nil
}

// NewTLS uses c to construct a TransportAuthenticator based on TLS.
func NewTLS(c *tls.Config) TransportAuthenticator {
	tc := &tlsCreds{*c}
	tc.config.NextProtos = alpnProtoStr
	return tc
}

// NewClientTLSFromCert constructs a TLS from the input certificate for client.
func NewClientTLSFromCert(cp *x509.CertPool, serverName string) TransportAuthenticator {
	return NewTLS(&tls.Config{ServerName: serverName, RootCAs: cp})
}

// NewClientTLSFromFile constructs a TLS from the input certificate file for client.
func NewClientTLSFromFile(certFile, serverName string) (TransportAuthenticator, error) {
	b, err := ioutil.ReadFile(certFile)
	if err != nil {
		return nil, err
	}
	cp := x509.NewCertPool()
	if !cp.AppendCertsFromPEM(b) {
		return nil, fmt.Errorf("credentials: failed to append certificates")
	}
	return NewTLS(&tls.Config{ServerName: serverName, RootCAs: cp}), nil
}

// NewServerTLSFromCert constructs a TLS from the input certificate for server.
func NewServerTLSFromCert(cert *tls.Certificate) TransportAuthenticator {
	return NewTLS(&tls.Config{Certificates: []tls.Certificate{*cert}})
}

// NewServerTLSFromFile constructs a TLS from the input certificate file and key
// file for server.
func NewServerTLSFromFile(certFile, keyFile string) (TransportAuthenticator, error) {
	cert, err := tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		return nil, err
	}
	return NewTLS(&tls.Config{Certificates: []tls.Certificate{cert}}), nil
}
<|endoftext|>


<commit_before>package build

import (
	"fmt"
	"os"
	"os/exec"

	"github.com/spf13/cobra"
	"github.com/tomologic/wrench/config"
	"github.com/tomologic/wrench/utils"
)

func AddToWrench(rootCmd *cobra.Command) {
	var cmdBuild = &cobra.Command{
		Use:   "build",
		Short: "Build docker image",
		Long:  `will build docker image for project`,
		Run: func(cmd *cobra.Command, args []string) {
			build()
		},
	}

	rootCmd.AddCommand(cmdBuild)
}

func build() {
	if utils.FileExists("./Dockerfile.builder") {
		fmt.Printf("INFO: %s\n", "Builder build mode")
		buildBuilder()
	} else if utils.FileExists("./Dockerfile") {
		fmt.Printf("INFO: %s\n", "Simple build mode")
		buildSimple()
	} else {
		fmt.Printf("ERROR: %s\n", "No Dockerfile found.")
		os.Exit(1)
	}
}

func buildBuilder() {
	image_name := fmt.Sprintf("%s/%s:%s",
		config.GetProjectOrganization,
		config.GetProjectName,
		config.GetProjectVersion)

	builder_image_name := fmt.Sprintf("%s/builder-%s:%s",
		config.GetProjectOrganization,
		config.GetProjectName,
		config.GetProjectVersion)

	fmt.Printf("INFO: %s %s\n\n",
		"Found Dockerfile.builder, building image builder",
		builder_image_name)

	// Build builder image
	cmd_string := fmt.Sprintf("docker build -f Dockerfile.builder -t '%s' .", builder_image_name)
	cmd := exec.Command("sh", "-c", cmd_string)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err := cmd.Run()

	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	fmt.Printf("\nINFO: %s %s\n\n",
		"Building image with builder",
		image_name)

	// Build image
	cmd_string = fmt.Sprintf("docker run --rm '%s' | docker build -t '%s' -", builder_image_name, image_name)
	cmd = exec.Command("sh", "-c", cmd_string)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err = cmd.Run()

	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	// Cleanup builder image
	cmd_string = fmt.Sprintf("docker rmi '%s'", builder_image_name)
	cmd = exec.Command("sh", "-c", cmd_string)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err = cmd.Run()

	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

func buildSimple() {
	image_name := fmt.Sprintf("%s/%s:%s",
		config.GetProjectOrganization,
		config.GetProjectName,
		config.GetProjectVersion)

	fmt.Printf("INFO: %s %s\n",
		"Found Dockerfile, building image",
		image_name)

	cmd_string := fmt.Sprintf("docker build -t '%s' .", image_name)
	cmd := exec.Command("sh", "-c", cmd_string)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err := cmd.Run()

	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
<commit_msg>Fix bug in build command when retrieving config<commit_after>package build

import (
	"fmt"
	"os"
	"os/exec"

	"github.com/spf13/cobra"
	"github.com/tomologic/wrench/config"
	"github.com/tomologic/wrench/utils"
)

func AddToWrench(rootCmd *cobra.Command) {
	var cmdBuild = &cobra.Command{
		Use:   "build",
		Short: "Build docker image",
		Long:  `will build docker image for project`,
		Run: func(cmd *cobra.Command, args []string) {
			build()
		},
	}

	rootCmd.AddCommand(cmdBuild)
}

func build() {
	if utils.FileExists("./Dockerfile.builder") {
		fmt.Printf("INFO: %s\n", "Builder build mode")
		buildBuilder()
	} else if utils.FileExists("./Dockerfile") {
		fmt.Printf("INFO: %s\n", "Simple build mode")
		buildSimple()
	} else {
		fmt.Printf("ERROR: %s\n", "No Dockerfile found.")
		os.Exit(1)
	}
}

func buildBuilder() {
	image_name := fmt.Sprintf("%s/%s:%s",
		config.GetProjectOrganization(),
		config.GetProjectName(),
		config.GetProjectVersion())

	builder_image_name := fmt.Sprintf("%s/builder-%s:%s",
		config.GetProjectOrganization(),
		config.GetProjectName(),
		config.GetProjectVersion())

	fmt.Printf("INFO: %s %s\n\n",
		"Found Dockerfile.builder, building image builder",
		builder_image_name)

	// Build builder image
	cmd_string := fmt.Sprintf("docker build -f Dockerfile.builder -t '%s' .", builder_image_name)
	cmd := exec.Command("sh", "-c", cmd_string)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err := cmd.Run()

	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	fmt.Printf("\nINFO: %s %s\n\n",
		"Building image with builder",
		image_name)

	// Build image
	cmd_string = fmt.Sprintf("docker run --rm '%s' | docker build -t '%s' -", builder_image_name, image_name)
	cmd = exec.Command("sh", "-c", cmd_string)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err = cmd.Run()

	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	// Cleanup builder image
	cmd_string = fmt.Sprintf("docker rmi '%s'", builder_image_name)
	cmd = exec.Command("sh", "-c", cmd_string)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err = cmd.Run()

	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

func buildSimple() {
	image_name := fmt.Sprintf("%s/%s:%s",
		config.GetProjectOrganization(),
		config.GetProjectName(),
		config.GetProjectVersion())

	fmt.Printf("INFO: %s %s\n",
		"Found Dockerfile, building image",
		image_name)

	cmd_string := fmt.Sprintf("docker build -t '%s' .", image_name)
	cmd := exec.Command("sh", "-c", cmd_string)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err := cmd.Run()

	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
<|endoftext|>


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

package build

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"github.com/google/zoekt"
	"github.com/google/zoekt/ctags"
)

func runCTags(bin string, inputs map[string][]byte) ([]*ctags.Entry, error) {
	const debug = false
	if len(inputs) == 0 {
		return nil, nil
	}
	dir, err := ioutil.TempDir("", "ctags-input")
	if err != nil {
		return nil, err
	}
	if !debug {
		defer os.RemoveAll(dir)
	}

	// --sort shells out to sort(1).
	args := []string{bin, "-n", "-f", "-", "--sort=no"}

	fileCount := 0
	for n, c := range inputs {
		if len(c) == 0 {
			continue
		}

		full := filepath.Join(dir, n)
		if err := os.MkdirAll(filepath.Dir(full), 0700); err != nil {
			return nil, err
		}
		err := ioutil.WriteFile(full, c, 0600)
		if err != nil {
			return nil, err
		}
		args = append(args, n)
		fileCount++
	}
	if fileCount == 0 {
		return nil, nil
	}

	cmd := exec.Command(args[0], args[1:]...)
	cmd.Dir = dir

	var errBuf, outBuf bytes.Buffer
	cmd.Stderr = &errBuf
	cmd.Stdout = &outBuf

	if err := cmd.Start(); err != nil {
		return nil, err
	}

	errChan := make(chan error, 1)
	go func() {
		err := cmd.Wait()
		errChan <- err
	}()
	timeout := time.After(5 * time.Second)
	select {
	case <-timeout:
		cmd.Process.Kill()
		return nil, fmt.Errorf("timeout executing ctags.")
	case err := <-errChan:
		if err != nil {
			return nil, fmt.Errorf("exec(%s): %v, stderr: %s", cmd.Args, err, errBuf.String())
		}
	}

	var entries []*ctags.Entry
	for _, l := range bytes.Split(outBuf.Bytes(), []byte{'\n'}) {
		if len(l) == 0 {
			continue
		}
		e, err := ctags.Parse(string(l))
		if err != nil {
			return nil, err
		}

		if len(e.Sym) == 1 {
			continue
		}
		entries = append(entries, e)
	}
	return entries, nil
}

func runCTagsChunked(bin string, in map[string][]byte) ([]*ctags.Entry, error) {
	var res []*ctags.Entry

	cur := map[string][]byte{}
	sz := 0
	for k, v := range in {
		cur[k] = v
		sz += len(k)

		// 100k seems reasonable.
		if sz > (100 << 10) {
			r, err := runCTags(bin, cur)
			if err != nil {
				return nil, err
			}
			res = append(res, r...)

			cur = map[string][]byte{}
			sz = 0
		}
	}
	r, err := runCTags(bin, cur)
	if err != nil {
		return nil, err
	}
	res = append(res, r...)
	return res, nil
}

func ctagsAddSymbols(todo []*zoekt.Document, parser ctags.Parser, bin string) error {
	pathIndices := map[string]int{}
	contents := map[string][]byte{}
	for i, t := range todo {
		if t.Symbols != nil {
			continue
		}

		_, ok := pathIndices[t.Name]
		if ok {
			continue
		}

		pathIndices[t.Name] = i
		contents[t.Name] = t.Content
	}

	var err error
	var entries []*ctags.Entry
	if parser != nil {
		for k, v := range contents {
			es, err := parser.Parse(k, v)
			if err != nil {
				return err
			}
			entries = append(entries, es...)
		}
	} else {
		entries, err = runCTagsChunked(bin, contents)
		if err != nil {
			return err
		}
	}

	fileTags := map[string][]*ctags.Entry{}
	for _, e := range entries {
		fileTags[e.Path] = append(fileTags[e.Path], e)
	}

	for k, tags := range fileTags {
		symOffsets, err := tagsToSections(contents[k], tags)
		if err != nil {
			return err
		}
		todo[pathIndices[k]].Symbols = symOffsets
		if len(tags) > 0 {
			todo[pathIndices[k]].Language = strings.ToLower(tags[0].Language)
		}
	}
	return nil
}

func tagsToSections(content []byte, tags []*ctags.Entry) ([]zoekt.DocumentSection, error) {
	nls := newLinesIndices(content)
	nls = append(nls, uint32(len(content)))
	var symOffsets []zoekt.DocumentSection
	for _, t := range tags {
		if t.Line <= 0 {
			// Observed this with a .JS file.
			continue
		}
		lineIdx := t.Line - 1
		if lineIdx >= len(nls) {
			log.Println("nls", nls)
			return nil, fmt.Errorf("linenum for entry out of range %v", t)
		}

		lineOff := uint32(0)
		if lineIdx > 0 {
			lineOff = nls[lineIdx-1] + 1
		}

		end := nls[lineIdx]
		line := content[lineOff:end]

		intraOff := bytes.Index(line, []byte(t.Sym))
		if intraOff < 0 {
			// for Go code, this is very common, since
			// ctags barfs on multi-line declarations
			// log.Printf("symbol %s not found in line
			// %q", t.Sym, line)
			continue
		}
		symOffsets = append(symOffsets, zoekt.DocumentSection{
			Start: lineOff + uint32(intraOff),
			End:   lineOff + uint32(intraOff) + uint32(len(t.Sym)),
		})
	}

	return symOffsets, nil
}

func newLinesIndices(in []byte) []uint32 {
	out := make([]uint32, 0, len(in)/30)
	for i, c := range in {
		if c == '\n' {
			out = append(out, uint32(i))
		}
	}
	return out
}
<commit_msg>Simplify universal-ctags call sequence.<commit_after>// Copyright 2016 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package build

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"github.com/google/zoekt"
	"github.com/google/zoekt/ctags"
)

func runCTags(bin string, inputs map[string][]byte) ([]*ctags.Entry, error) {
	const debug = false
	if len(inputs) == 0 {
		return nil, nil
	}
	dir, err := ioutil.TempDir("", "ctags-input")
	if err != nil {
		return nil, err
	}
	if !debug {
		defer os.RemoveAll(dir)
	}

	// --sort shells out to sort(1).
	args := []string{bin, "-n", "-f", "-", "--sort=no"}

	fileCount := 0
	for n, c := range inputs {
		if len(c) == 0 {
			continue
		}

		full := filepath.Join(dir, n)
		if err := os.MkdirAll(filepath.Dir(full), 0700); err != nil {
			return nil, err
		}
		err := ioutil.WriteFile(full, c, 0600)
		if err != nil {
			return nil, err
		}
		args = append(args, n)
		fileCount++
	}
	if fileCount == 0 {
		return nil, nil
	}

	cmd := exec.Command(args[0], args[1:]...)
	cmd.Dir = dir

	var errBuf, outBuf bytes.Buffer
	cmd.Stderr = &errBuf
	cmd.Stdout = &outBuf

	if err := cmd.Start(); err != nil {
		return nil, err
	}

	errChan := make(chan error, 1)
	go func() {
		err := cmd.Wait()
		errChan <- err
	}()
	timeout := time.After(5 * time.Second)
	select {
	case <-timeout:
		cmd.Process.Kill()
		return nil, fmt.Errorf("timeout executing ctags.")
	case err := <-errChan:
		if err != nil {
			return nil, fmt.Errorf("exec(%s): %v, stderr: %s", cmd.Args, err, errBuf.String())
		}
	}

	var entries []*ctags.Entry
	for _, l := range bytes.Split(outBuf.Bytes(), []byte{'\n'}) {
		if len(l) == 0 {
			continue
		}
		e, err := ctags.Parse(string(l))
		if err != nil {
			return nil, err
		}

		if len(e.Sym) == 1 {
			continue
		}
		entries = append(entries, e)
	}
	return entries, nil
}

func runCTagsChunked(bin string, in map[string][]byte) ([]*ctags.Entry, error) {
	var res []*ctags.Entry

	cur := map[string][]byte{}
	sz := 0
	for k, v := range in {
		cur[k] = v
		sz += len(k)

		// 100k seems reasonable.
		if sz > (100 << 10) {
			r, err := runCTags(bin, cur)
			if err != nil {
				return nil, err
			}
			res = append(res, r...)

			cur = map[string][]byte{}
			sz = 0
		}
	}
	r, err := runCTags(bin, cur)
	if err != nil {
		return nil, err
	}
	res = append(res, r...)
	return res, nil
}

func ctagsAddSymbolsParser(todo []*zoekt.Document, parser ctags.Parser) error {
	for _, doc := range todo {
		if doc.Symbols != nil {
			continue
		}

		es, err := parser.Parse(doc.Name, doc.Content)
		if err != nil {
			return err
		}
		symOffsets, err := tagsToSections(doc.Content, es)
		if err != nil {
			return err
		}
		doc.Symbols = symOffsets
	}

	return nil
}

func ctagsAddSymbols(todo []*zoekt.Document, parser ctags.Parser, bin string) error {
	if parser != nil {
		return ctagsAddSymbolsParser(todo, parser)
	}

	pathIndices := map[string]int{}
	contents := map[string][]byte{}
	for i, t := range todo {
		if t.Symbols != nil {
			continue
		}

		_, ok := pathIndices[t.Name]
		if ok {
			continue
		}

		pathIndices[t.Name] = i
		contents[t.Name] = t.Content
	}

	var err error
	var entries []*ctags.Entry
	entries, err = runCTagsChunked(bin, contents)
	if err != nil {
		return err
	}

	fileTags := map[string][]*ctags.Entry{}
	for _, e := range entries {
		fileTags[e.Path] = append(fileTags[e.Path], e)
	}

	for k, tags := range fileTags {
		symOffsets, err := tagsToSections(contents[k], tags)
		if err != nil {
			return err
		}
		todo[pathIndices[k]].Symbols = symOffsets
		if len(tags) > 0 {
			todo[pathIndices[k]].Language = strings.ToLower(tags[0].Language)
		}
	}
	return nil
}

func tagsToSections(content []byte, tags []*ctags.Entry) ([]zoekt.DocumentSection, error) {
	nls := newLinesIndices(content)
	nls = append(nls, uint32(len(content)))
	var symOffsets []zoekt.DocumentSection
	for _, t := range tags {
		if t.Line <= 0 {
			// Observed this with a .JS file.
			continue
		}
		lineIdx := t.Line - 1
		if lineIdx >= len(nls) {
			log.Println("nls", nls)
			return nil, fmt.Errorf("linenum for entry out of range %v", t)
		}

		lineOff := uint32(0)
		if lineIdx > 0 {
			lineOff = nls[lineIdx-1] + 1
		}

		end := nls[lineIdx]
		line := content[lineOff:end]

		intraOff := bytes.Index(line, []byte(t.Sym))
		if intraOff < 0 {
			// for Go code, this is very common, since
			// ctags barfs on multi-line declarations
			// log.Printf("symbol %s not found in line
			// %q", t.Sym, line)
			continue
		}
		symOffsets = append(symOffsets, zoekt.DocumentSection{
			Start: lineOff + uint32(intraOff),
			End:   lineOff + uint32(intraOff) + uint32(len(t.Sym)),
		})
	}

	return symOffsets, nil
}

func newLinesIndices(in []byte) []uint32 {
	out := make([]uint32, 0, len(in)/30)
	for i, c := range in {
		if c == '\n' {
			out = append(out, uint32(i))
		}
	}
	return out
}
<|endoftext|>