<commit_before>/*package density interpolates sequences of particle positions onto a density
grid.
*/
package density

import (
	"fmt"
	"math"

	"github.com/phil-mansfield/gotetra/geom"
)

// Interpolator creates a grid-based density distribution from seqeunces of
// positions.
type Interpolator interface {
	// Interpolate adds the density distribution implied by points to the
	// density grid used by the Interpolator. Particles should all be within
	// the bounds of the bounding grid and points not within the interpolation
	// grid will be ignored.
	Interpolate(mass float64, pts []geom.Vec)
}

// Flag indicates the interpolation scheme that should be used to assign
// densities.
type Flag int

type cic struct {
	g, bg      geom.Grid
	cellWidth  float64
	cellVolume float64
	rhos       []float64
}

type ngp struct {
	g          geom.Grid
	cellWidth  float64
	cellVolume float64
	rhos       []float64
}

const (
	CloudInCell Flag = iota
	NearestGridPoint
)

// Bounds returns a large bounding grid and a smaller interpolation Grid
// which acts as a single subcell of the bounding Grid. cells gives the number
// of cells in the interpolation Grid, and gridWidth gives the number of
// interpolation Grids within the bounding grid [on one side].
func Bounds(cells, gridWidth, gx, gy, gz int) (g, bg *geom.Grid) {
	g = geom.NewGrid(&[3]int{gx * cells, gy * cells, gz * cells}, cells)
	bg = geom.NewGrid(&[3]int{0, 0, 0}, cells*gridWidth)
	return g, bg
}

// NewInterpolator creates an Interpolator instance using the given
// interpolation scheme which adds to the grid rhos. rhos has boundaries
// defined by the Grid g which is embedded in the bounding Grid bg. These two
// grids will almost always be possible to create through a call to Bounds. The
// variable width refers to the interpolation grid, not the bounding grid.
func NewInterpolator(
	flag Flag, g, bg *geom.Grid,
	width float64, rhos []float64,
) Interpolator {
	if g.Volume != len(rhos) {
		panic(fmt.Sprintf(
			"Volume of grid, %d, does not equal length of rhos, %d.",
			g.Volume, len(rhos),
		))
	}

	cellWidth := width / float64(g.Width)
	cellVolume := 1.0 / (cellWidth * cellWidth * cellWidth)

	switch flag {
	case CloudInCell:
		return &cic{*g, *bg, cellWidth, cellVolume, rhos}
	case NearestGridPoint:
		return &ngp{*g, cellWidth, cellVolume, rhos}
	}
	panic(fmt.Sprintf("Unknown flag %d", flag))
}

func (intr *ngp) Interpolate(mass float64, pts []geom.Vec) {
	frac := mass / intr.cellVolume
	for _, pt := range pts {
		xp, yp, zp := float64(pt[0]), float64(pt[1]), float64(pt[2])
		xc, yc, zc := cellPoints(xp, yp, zp, intr.cellWidth)
		i, j, k := int(xc), int(yc), int(zc)

		if idx, ok := intr.g.IdxCheck(i, j, k); ok {
			intr.rhos[idx] += frac
		}
	}
}

func (intr *cic) Interpolate(mass float64, pts []geom.Vec) {
	frac := mass / intr.cellVolume
	for _, pt := range pts {
		xp, yp, zp := float64(pt[0]), float64(pt[1]), float64(pt[2])
		xc, yc, zc := cellPoints(xp, yp, zp, intr.cellWidth)
		dx, dy, dz := xp-xc, yp-yc, zp-zc
		tx, ty, tz := intr.cellWidth-dx, intr.cellWidth-dy, intr.cellWidth-dz

		i0, i1 := intr.nbrs(int(xc))
		j0, j1 := intr.nbrs(int(yc))
		k0, k1 := intr.nbrs(int(zc))

		intr.incr(i0, j0, k0, tx*ty*tz*frac)
		intr.incr(i1, j0, k0, dx*ty*tz*frac)
		intr.incr(i0, j1, k0, tx*dy*tz*frac)
		intr.incr(i1, j1, k0, dx*dy*tz*frac)
		intr.incr(i0, j0, k1, tx*ty*dz*frac)
		intr.incr(i1, j0, k1, dx*ty*dz*frac)
		intr.incr(i0, j1, k1, tx*dy*dz*frac)
		intr.incr(i1, j1, k1, dx*dy*dz*frac)
	}
}

func (intr *cic) nbrs(i int) (i0, i1 int) {
	if i+1 == intr.bg.Width {
		return i, 0
	}
	return i, i + 1
}

func (intr *cic) incr(i, j, k int, frac float64) {
	if idx, ok := intr.g.IdxCheck(i, j, k); ok {
		intr.rhos[idx] += frac
	}
}

func cellPoints(x, y, z, cw float64) (xc, yc, zc float64) {
	return math.Floor(x / cw), math.Floor(y / cw), math.Floor(z / cw)
}
<commit_msg>Fixed bug which inverted volume elements in density.go<commit_after>/*package density interpolates sequences of particle positions onto a density
grid.
*/
package density

import (
	"fmt"
	"math"

	"github.com/phil-mansfield/gotetra/geom"
)

// Interpolator creates a grid-based density distribution from seqeunces of
// positions.
type Interpolator interface {
	// Interpolate adds the density distribution implied by points to the
	// density grid used by the Interpolator. Particles should all be within
	// the bounds of the bounding grid and points not within the interpolation
	// grid will be ignored.
	Interpolate(mass float64, pts []geom.Vec)
}

// Flag indicates the interpolation scheme that should be used to assign
// densities.
type Flag int

type cic struct {
	g, bg      geom.Grid
	cellWidth  float64
	cellVolume float64
	rhos       []float64
}

type ngp struct {
	g          geom.Grid
	cellWidth  float64
	cellVolume float64
	rhos       []float64
}

const (
	CloudInCell Flag = iota
	NearestGridPoint
)

// Bounds returns a large bounding grid and a smaller interpolation Grid
// which acts as a single subcell of the bounding Grid. cells gives the number
// of cells in the interpolation Grid, and gridWidth gives the number of
// interpolation Grids within the bounding grid [on one side].
func Bounds(cells, gridWidth, gx, gy, gz int) (g, bg *geom.Grid) {
	g = geom.NewGrid(&[3]int{gx * cells, gy * cells, gz * cells}, cells)
	bg = geom.NewGrid(&[3]int{0, 0, 0}, cells*gridWidth)
	return g, bg
}

// NewInterpolator creates an Interpolator instance using the given
// interpolation scheme which adds to the grid rhos. rhos has boundaries
// defined by the Grid g which is embedded in the bounding Grid bg. These two
// grids will almost always be possible to create through a call to Bounds. The
// variable width refers to the interpolation grid, not the bounding grid.
func NewInterpolator(
	flag Flag, g, bg *geom.Grid,
	width float64, rhos []float64,
) Interpolator {
	if g.Volume != len(rhos) {
		panic(fmt.Sprintf(
			"Volume of grid, %d, does not equal length of rhos, %d.",
			g.Volume, len(rhos),
		))
	}

	cellWidth := width / float64(g.Width)
	cellVolume := cellWidth * cellWidth * cellWidth

	switch flag {
	case CloudInCell:
		return &cic{*g, *bg, cellWidth, cellVolume, rhos}
	case NearestGridPoint:
		return &ngp{*g, cellWidth, cellVolume, rhos}
	}
	panic(fmt.Sprintf("Unknown flag %d", flag))
}

// Interpolate interpolates a sequence of particles onto a density grid via a
// nearest grid point scheme.
func (intr *ngp) Interpolate(mass float64, pts []geom.Vec) {
	frac := mass / intr.cellVolume
	for _, pt := range pts {
		xp, yp, zp := float64(pt[0]), float64(pt[1]), float64(pt[2])
		xc, yc, zc := cellPoints(xp, yp, zp, intr.cellWidth)
		i, j, k := int(xc), int(yc), int(zc)

		if idx, ok := intr.g.IdxCheck(i, j, k); ok {
			intr.rhos[idx] += frac
		}
	}
}

// Interpolate interpolates a sequence of particles onto a density grid via a
// cloud in cell scheme.
func (intr *cic) Interpolate(mass float64, pts []geom.Vec) {
	frac := mass / intr.cellVolume
	for _, pt := range pts {
		xp, yp, zp := float64(pt[0]), float64(pt[1]), float64(pt[2])
		xc, yc, zc := cellPoints(xp, yp, zp, intr.cellWidth)
		dx, dy, dz := xp-xc, yp-yc, zp-zc
		tx, ty, tz := intr.cellWidth-dx, intr.cellWidth-dy, intr.cellWidth-dz

		i0, i1 := intr.nbrs(int(xc))
		j0, j1 := intr.nbrs(int(yc))
		k0, k1 := intr.nbrs(int(zc))

		intr.incr(i0, j0, k0, tx*ty*tz*frac)
		intr.incr(i1, j0, k0, dx*ty*tz*frac)
		intr.incr(i0, j1, k0, tx*dy*tz*frac)
		intr.incr(i1, j1, k0, dx*dy*tz*frac)
		intr.incr(i0, j0, k1, tx*ty*dz*frac)
		intr.incr(i1, j0, k1, dx*ty*dz*frac)
		intr.incr(i0, j1, k1, tx*dy*dz*frac)
		intr.incr(i1, j1, k1, dx*dy*dz*frac)
	}
}

func (intr *cic) nbrs(i int) (i0, i1 int) {
	if i+1 == intr.bg.Width {
		return i, 0
	}
	return i, i + 1
}

func (intr *cic) incr(i, j, k int, frac float64) {
	if idx, ok := intr.g.IdxCheck(i, j, k); ok {
		intr.rhos[idx] += frac
	}
}

func cellPoints(x, y, z, cw float64) (xc, yc, zc float64) {
	return math.Floor(x / cw), math.Floor(y / cw), math.Floor(z / cw)
}
<|endoftext|>


<commit_before>//
// Copyright 2019, Matej Velikonja
//
// 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 gitlab

import (
	"fmt"
	"net/url"
	"time"
)

// ProjectClustersService handles communication with the
// project clusters related methods of the GitLab API.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/project_clusters.html
type ProjectClustersService struct {
	client *Client
}

// ProjectCluster represents a GitLab Project Cluster.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/project_clusters.html
type ProjectCluster struct {
	ID                 int                 `json:"id"`
	Name               string              `json:"name"`
	CreatedAt          *time.Time          `json:"created_at"`
	ProviderType       string              `json:"provider_type"`
	PlatformType       string              `json:"platform_type"`
	EnvironmentScope   string              `json:"environment_scope"`
	ClusterType        string              `json:"cluster_type"`
	User               *User               `json:"user"`
	PlatformKubernetes *PlatformKubernetes `json:"platform_kubernetes"`
	Project            *Project            `json:"project"`
}

func (v ProjectCluster) String() string {
	return Stringify(v)
}

// PlatformKubernetes represents a GitLab Project Cluster PlatformKubernetes.
type PlatformKubernetes struct {
	APIURL            string `json:"api_url"`
	Token             string `json:"token"`
	CaCert            string `json:"ca_cert"`
	Namespace         string `json:"namespace"`
	AuthorizationType string `json:"authorization_type"`
}

// ListClusters gets a list of all clusters in a project.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/project_clusters.html#list-project-clusters
func (s *ProjectClustersService) ListClusters(pid interface{}, options ...OptionFunc) ([]*ProjectCluster, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/clusters", url.QueryEscape(project))

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	var pc []*ProjectCluster
	resp, err := s.client.Do(req, &pc)
	if err != nil {
		return nil, resp, err
	}

	return pc, resp, err
}

// GetCluster gets a cluster.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/project_clusters.html#get-a-single-project-cluster
func (s *ProjectClustersService) GetCluster(pid interface{}, cluster int, options ...OptionFunc) (*ProjectCluster, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/clusters/%d", url.QueryEscape(project), cluster)

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	var pc *ProjectCluster
	resp, err := s.client.Do(req, &pc)
	if err != nil {
		return nil, resp, err
	}

	return pc, resp, err
}

// AddClusterOptions represents the available AddCluster() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/project_clusters.html#add-existing-cluster-to-project
type AddClusterOptions struct {
	Name               string              `url:"name,omitempty" json:"name,omitempty"`
	Enabled            *bool               `url:"enabled,omitempty" json:"enabled,omitempty"`
	EnvironmentScope   string              `url:"environment_scope,omitempty" json:"environment_scope,omitempty"`
	PlatformKubernetes *PlatformKubernetes `url:"platform_kubernetes_attributes,omitempty" json:"platform_kubernetes_attributes,omitempty"`
}

// AddCluster adds an existing cluster to the project.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/project_clusters.html#add-existing-cluster-to-project
func (s *ProjectClustersService) AddCluster(pid interface{}, opt *AddClusterOptions, options ...OptionFunc) (*ProjectCluster, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/clusters/user", url.QueryEscape(project))

	req, err := s.client.NewRequest("POST", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	pc := new(ProjectCluster)
	resp, err := s.client.Do(req, pc)
	if err != nil {
		return nil, resp, err
	}

	return pc, resp, err
}

// EditClusterOptions represents the available EditCluster() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/project_clusters.html#edit-project-cluster
type EditClusterOptions struct {
	Name               string              `url:"name,omitempty" json:"name,omitempty"`
	EnvironmentScope   string              `url:"environment_scope,omitempty" json:"environment_scope,omitempty"`
	PlatformKubernetes *PlatformKubernetes `url:"platform_kubernetes_attributes,omitempty" json:"platform_kubernetes_attributes,omitempty"`
}

// EditCluster updates an existing project cluster.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/project_clusters.html#edit-project-cluster
func (s *ProjectClustersService) EditCluster(pid interface{}, cluster int, opt *EditClusterOptions, options ...OptionFunc) (*ProjectCluster, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/clusters/%d", url.QueryEscape(project), cluster)

	req, err := s.client.NewRequest("PUT", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	pc := new(ProjectCluster)
	resp, err := s.client.Do(req, pc)
	if err != nil {
		return nil, resp, err
	}

	return pc, resp, err
}

// DeleteCluster deletes an existing project cluster.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/project_clusters.html#delete-project-cluster
func (s *ProjectClustersService) DeleteCluster(pid interface{}, cluster int, options ...OptionFunc) (*Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("projects/%s/clusters/%d", url.QueryEscape(project), cluster)

	req, err := s.client.NewRequest("DELETE", u, nil, options)
	if err != nil {
		return nil, err
	}

	return s.client.Do(req, nil)
}
<commit_msg>option struct fields to pointers<commit_after>//
// Copyright 2019, Matej Velikonja
//
// 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 gitlab

import (
	"fmt"
	"net/url"
	"time"
)

// ProjectClustersService handles communication with the
// project clusters related methods of the GitLab API.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/project_clusters.html
type ProjectClustersService struct {
	client *Client
}

// ProjectCluster represents a GitLab Project Cluster.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/project_clusters.html
type ProjectCluster struct {
	ID                 int                 `json:"id"`
	Name               string              `json:"name"`
	CreatedAt          *time.Time          `json:"created_at"`
	ProviderType       string              `json:"provider_type"`
	PlatformType       string              `json:"platform_type"`
	EnvironmentScope   string              `json:"environment_scope"`
	ClusterType        string              `json:"cluster_type"`
	User               *User               `json:"user"`
	PlatformKubernetes *PlatformKubernetes `json:"platform_kubernetes"`
	Project            *Project            `json:"project"`
}

func (v ProjectCluster) String() string {
	return Stringify(v)
}

// PlatformKubernetes represents a GitLab Project Cluster PlatformKubernetes.
type PlatformKubernetes struct {
	APIURL            string `json:"api_url"`
	Token             string `json:"token"`
	CaCert            string `json:"ca_cert"`
	Namespace         string `json:"namespace"`
	AuthorizationType string `json:"authorization_type"`
}

// ListClusters gets a list of all clusters in a project.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/project_clusters.html#list-project-clusters
func (s *ProjectClustersService) ListClusters(pid interface{}, options ...OptionFunc) ([]*ProjectCluster, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/clusters", url.QueryEscape(project))

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	var pc []*ProjectCluster
	resp, err := s.client.Do(req, &pc)
	if err != nil {
		return nil, resp, err
	}

	return pc, resp, err
}

// GetCluster gets a cluster.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/project_clusters.html#get-a-single-project-cluster
func (s *ProjectClustersService) GetCluster(pid interface{}, cluster int, options ...OptionFunc) (*ProjectCluster, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/clusters/%d", url.QueryEscape(project), cluster)

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	var pc *ProjectCluster
	resp, err := s.client.Do(req, &pc)
	if err != nil {
		return nil, resp, err
	}

	return pc, resp, err
}

// AddClusterOptions represents the available AddCluster() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/project_clusters.html#add-existing-cluster-to-project
type AddClusterOptions struct {
	Name               *string             `url:"name,omitempty" json:"name,omitempty"`
	Enabled            *bool               `url:"enabled,omitempty" json:"enabled,omitempty"`
	EnvironmentScope   *string             `url:"environment_scope,omitempty" json:"environment_scope,omitempty"`
	PlatformKubernetes *PlatformKubernetes `url:"platform_kubernetes_attributes,omitempty" json:"platform_kubernetes_attributes,omitempty"`
}

// AddCluster adds an existing cluster to the project.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/project_clusters.html#add-existing-cluster-to-project
func (s *ProjectClustersService) AddCluster(pid interface{}, opt *AddClusterOptions, options ...OptionFunc) (*ProjectCluster, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/clusters/user", url.QueryEscape(project))

	req, err := s.client.NewRequest("POST", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	pc := new(ProjectCluster)
	resp, err := s.client.Do(req, pc)
	if err != nil {
		return nil, resp, err
	}

	return pc, resp, err
}

// EditClusterOptions represents the available EditCluster() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/project_clusters.html#edit-project-cluster
type EditClusterOptions struct {
	Name               *string             `url:"name,omitempty" json:"name,omitempty"`
	EnvironmentScope   *string             `url:"environment_scope,omitempty" json:"environment_scope,omitempty"`
	PlatformKubernetes *PlatformKubernetes `url:"platform_kubernetes_attributes,omitempty" json:"platform_kubernetes_attributes,omitempty"`
}

// EditCluster updates an existing project cluster.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/project_clusters.html#edit-project-cluster
func (s *ProjectClustersService) EditCluster(pid interface{}, cluster int, opt *EditClusterOptions, options ...OptionFunc) (*ProjectCluster, *Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("projects/%s/clusters/%d", url.QueryEscape(project), cluster)

	req, err := s.client.NewRequest("PUT", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	pc := new(ProjectCluster)
	resp, err := s.client.Do(req, pc)
	if err != nil {
		return nil, resp, err
	}

	return pc, resp, err
}

// DeleteCluster deletes an existing project cluster.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/project_clusters.html#delete-project-cluster
func (s *ProjectClustersService) DeleteCluster(pid interface{}, cluster int, options ...OptionFunc) (*Response, error) {
	project, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("projects/%s/clusters/%d", url.QueryEscape(project), cluster)

	req, err := s.client.NewRequest("DELETE", u, nil, options)
	if err != nil {
		return nil, err
	}

	return s.client.Do(req, nil)
}
<|endoftext|>


<commit_before>package flint

import (
	"github.com/stretchr/testify/assert"
	"testing"
)

func TestRemoteProjectFetchRequiresFullName(t *testing.T) {
	project := &RemoteProject{}
	fetcher := &FakeProjectFetcher{}
	err := project.Fetch(fetcher)
	if assert.NotNil(t, err) {
		assert.Equal(t, "Must supply FullName as owner/repository", err.Error())
	}
}

func TestRemoteProjectPopulatesProjectInfo(t *testing.T) {
	project := &RemoteProject{FullName: "octokit/octokit.rb"}
	fetcher := &FakeProjectFetcher{}
	err := project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.Equal(t, "Ruby toolkit for the GitHub API", project.Description)
	assert.Equal(t, "http://octokit.github.io/octokit.rb/", project.Homepage)
}

func TestRemoteProjectPopulatesTree(t *testing.T) {
	project := &RemoteProject{FullName: "octokit/octokit.rb"}
	fetcher := &FakeProjectFetcher{}
	err := project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.True(t, project.CheckReadme())
}

func TestRemoteProjectCheckReadme(t *testing.T) {
	project := &RemoteProject{FullName: "octokit/octokit.rb"}
	fetcher := &FakeProjectFetcher{}
	err := project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.True(t, project.CheckReadme())

	project = &RemoteProject{FullName: "projects/lowercase-names"}
	err = project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.False(t, project.CheckReadme())
}

func TestRemoteProjectCheckContributing(t *testing.T) {
	project := &RemoteProject{FullName: "octokit/octokit.rb"}
	fetcher := &FakeProjectFetcher{}
	err := project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.True(t, project.CheckContributing())

	project = &RemoteProject{FullName: "projects/lowercase-names"}
	err = project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.False(t, project.CheckContributing())
}

func TestRemoteProjectCheckLicense(t *testing.T) {
	project := &RemoteProject{FullName: "octokit/octokit.rb"}
	fetcher := &FakeProjectFetcher{}
	err := project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.True(t, project.CheckLicense())

	project = &RemoteProject{FullName: "projects/lowercase-names"}
	err = project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.False(t, project.CheckLicense())
}

func TestRemoteProjectCheckBootstrap(t *testing.T) {
	project := &RemoteProject{FullName: "octokit/octokit.rb"}
	fetcher := &FakeProjectFetcher{}
	err := project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.True(t, project.CheckBootstrap())

	project = &RemoteProject{FullName: "projects/lowercase-names"}
	err = project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.True(t, project.CheckBootstrap())

	project = &RemoteProject{FullName: "projects/no-files"}
	err = project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.False(t, project.CheckBootstrap())
}

func TestRemoteProjectCheckTestScript(t *testing.T) {
	project := &RemoteProject{FullName: "octokit/octokit.rb"}
	fetcher := &FakeProjectFetcher{}
	err := project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.True(t, project.CheckTestScript())

	project = &RemoteProject{FullName: "projects/lowercase-names"}
	err = project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.True(t, project.CheckTestScript())

	project = &RemoteProject{FullName: "projects/no-files"}
	err = project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.False(t, project.CheckTestScript())
}

type FakeProjectFetcher struct {
}

func (f *FakeProjectFetcher) FetchRepository(nwo string) (repository *Repository, err error) {
	repository = &Repository{}
	switch nwo {
	case "octokit/octokit.rb":
		repository = &Repository{
			"Ruby toolkit for the GitHub API",
			"http://octokit.github.io/octokit.rb/",
		}
	}

	return repository, nil
}

func (f *FakeProjectFetcher) FetchTree(nwo string) (paths []string, err error) {
	switch nwo {
	case "octokit/octokit.rb":
		paths = []string{
			"CONTRIBUTING.md",
			"LICENSE.md",
			"README.md",
			"lib",
			"lib/octokit.rb",
			"script/bootstrap",
			"script/test",
		}
	case "projects/lowercase-names":
		paths = []string{
			"contributing",
			"license",
			"readme",
			"script/bootstrap",
			"script/test",
		}
	case "projects/no-files":
		paths = []string{}
	}
	return paths, nil
}
<commit_msg>Failing test for finding remote COPYING as license<commit_after>package flint

import (
	"github.com/stretchr/testify/assert"
	"testing"
)

func TestRemoteProjectFetchRequiresFullName(t *testing.T) {
	project := &RemoteProject{}
	fetcher := &FakeProjectFetcher{}
	err := project.Fetch(fetcher)
	if assert.NotNil(t, err) {
		assert.Equal(t, "Must supply FullName as owner/repository", err.Error())
	}
}

func TestRemoteProjectPopulatesProjectInfo(t *testing.T) {
	project := &RemoteProject{FullName: "octokit/octokit.rb"}
	fetcher := &FakeProjectFetcher{}
	err := project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.Equal(t, "Ruby toolkit for the GitHub API", project.Description)
	assert.Equal(t, "http://octokit.github.io/octokit.rb/", project.Homepage)
}

func TestRemoteProjectPopulatesTree(t *testing.T) {
	project := &RemoteProject{FullName: "octokit/octokit.rb"}
	fetcher := &FakeProjectFetcher{}
	err := project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.True(t, project.CheckReadme())
}

func TestRemoteProjectCheckReadme(t *testing.T) {
	project := &RemoteProject{FullName: "octokit/octokit.rb"}
	fetcher := &FakeProjectFetcher{}
	err := project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.True(t, project.CheckReadme())

	project = &RemoteProject{FullName: "projects/lowercase-names"}
	err = project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.False(t, project.CheckReadme())
}

func TestRemoteProjectCheckContributing(t *testing.T) {
	project := &RemoteProject{FullName: "octokit/octokit.rb"}
	fetcher := &FakeProjectFetcher{}
	err := project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.True(t, project.CheckContributing())

	project = &RemoteProject{FullName: "projects/lowercase-names"}
	err = project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.False(t, project.CheckContributing())
}

func TestRemoteProjectCheckLicense(t *testing.T) {
	project := &RemoteProject{FullName: "octokit/octokit.rb"}
	fetcher := &FakeProjectFetcher{}
	err := project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.True(t, project.CheckLicense())

	project = &RemoteProject{FullName: "projects/lowercase-names"}
	err = project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.False(t, project.CheckLicense())
}

func TestRemoteProjectCheckCopying(t *testing.T) {
	project := &RemoteProject{FullName: "projects/copying"}
	fetcher := &FakeProjectFetcher{}
	err := project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.True(t, project.CheckLicense())
}

func TestRemoteProjectCheckBootstrap(t *testing.T) {
	project := &RemoteProject{FullName: "octokit/octokit.rb"}
	fetcher := &FakeProjectFetcher{}
	err := project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.True(t, project.CheckBootstrap())

	project = &RemoteProject{FullName: "projects/lowercase-names"}
	err = project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.True(t, project.CheckBootstrap())

	project = &RemoteProject{FullName: "projects/no-files"}
	err = project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.False(t, project.CheckBootstrap())
}

func TestRemoteProjectCheckTestScript(t *testing.T) {
	project := &RemoteProject{FullName: "octokit/octokit.rb"}
	fetcher := &FakeProjectFetcher{}
	err := project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.True(t, project.CheckTestScript())

	project = &RemoteProject{FullName: "projects/lowercase-names"}
	err = project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.True(t, project.CheckTestScript())

	project = &RemoteProject{FullName: "projects/no-files"}
	err = project.Fetch(fetcher)
	assert.Nil(t, err)
	assert.False(t, project.CheckTestScript())
}

type FakeProjectFetcher struct {
}

func (f *FakeProjectFetcher) FetchRepository(nwo string) (repository *Repository, err error) {
	repository = &Repository{}
	switch nwo {
	case "octokit/octokit.rb":
		repository = &Repository{
			"Ruby toolkit for the GitHub API",
			"http://octokit.github.io/octokit.rb/",
		}
	}

	return repository, nil
}

func (f *FakeProjectFetcher) FetchTree(nwo string) (paths []string, err error) {
	switch nwo {
	case "octokit/octokit.rb":
		paths = []string{
			"CONTRIBUTING.md",
			"LICENSE.md",
			"README.md",
			"lib",
			"lib/octokit.rb",
			"script/bootstrap",
			"script/test",
		}
	case "projects/lowercase-names":
		paths = []string{
			"contributing",
			"license",
			"readme",
			"script/bootstrap",
			"script/test",
		}
	case "projects/no-files":
		paths = []string{}
	case "projects/copying":
		paths = []string{
			"COPYING",
			"contributing",
			"readme",
			"script/bootstrap",
			"script/test",
		}
	}
	return paths, nil
}
<|endoftext|>


<commit_before>package goleg

import (
	"bytes"
	"io/ioutil"
	"os"
	"strconv"
	"testing"
)

func openRandomDB(features int) (Database, string, error) {
	name, err := ioutil.TempDir("/tmp", "goleg")
	if err != nil {
		return Database{}, "", err
	}

	//F_APPENDONLY|F_AOL_FFLUSH|F_LZ4|F_SPLAYTREE
	database, err := Open(name, "test", features)
	if err != nil {
		return Database{}, "", err
	}

	return database, name, nil
}

func cleanTemp(dir string) {
	os.RemoveAll(dir)
}

func TestOpen(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping in short mode")
	}

	database, dir, err := openRandomDB(F_APPENDONLY)
	if err != nil {
		t.Fatalf("Can't open database: %s", err.Error())
	}

	database.Close()
	cleanTemp(dir)
}

const JARN = 10

func TestJar(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping in short mode")
	}

	database, dir, err := openRandomDB(F_LZ4 | F_SPLAYTREE)
	if err != nil {
		t.Fatalf("Can't open database: %s", err.Error())
	}

	for i := 0; i < JARN; i++ {
		if database.Jar("record"+strconv.Itoa(i), []byte("value"+strconv.Itoa(i))) != 0 {
			t.Fatalf("Can't jar value #%d", i)
		}
	}

	database.Close()
	cleanTemp(dir)
}

func TestUnjar(t *testing.T) {
	database, dir, err := openRandomDB(F_LZ4 | F_SPLAYTREE)
	if err != nil {
		t.Fatalf("Can't open database: %s", err.Error())
	}

	for i := 0; i < JARN; i++ {
		if database.Jar("record"+strconv.Itoa(i), []byte("value"+strconv.Itoa(i))) != 0 {
			t.Fatalf("Can't jar value #%d", i)
		}
	}

	for i := 0; i < JARN; i++ {
		val := database.Unjar("record" + strconv.Itoa(i))
		if !bytes.Equal(val, []byte("value"+strconv.Itoa(i))) {
			t.Errorf("Value #%d doesn't match", i)
		}
	}

	database.Close()
	cleanTemp(dir)
}

func TestFullKeyDump(t *testing.T) {
	database, _, err := openRandomDB(F_LZ4 | F_SPLAYTREE)
	if err != nil {
		t.Fatalf("Can't open database: %s", err.Error())
	}

	for i := 0; i < JARN; i++ {
		if database.Jar("record"+strconv.Itoa(i), []byte("value"+strconv.Itoa(i))) != 0 {
			t.Fatalf("Can't jar value #%d", i)
		}
	}

	gotKeys, keys := database.DumpKeys()

	if !gotKeys {
		t.Fatal("Didn't get keys and should have")
	}

	var j int
	for i := 0; i <= JARN; i++ {
		for _, key := range keys {
			if key == "record"+strconv.Itoa(i) {
				j++
			}
		}
	}
	if j != JARN {
		t.Fatal("One or more keys did not dump")
	}
}
<commit_msg>Adding test for BulkUnjar<commit_after>package goleg

import (
	"bytes"
	"io/ioutil"
	"os"
	"strconv"
	"testing"
)

func openRandomDB(features int) (Database, string, error) {
	name, err := ioutil.TempDir("/tmp", "goleg")
	if err != nil {
		return Database{}, "", err
	}

	//F_APPENDONLY|F_AOL_FFLUSH|F_LZ4|F_SPLAYTREE
	database, err := Open(name, "test", features)
	if err != nil {
		return Database{}, "", err
	}

	return database, name, nil
}

func cleanTemp(dir string) {
	os.RemoveAll(dir)
}

func TestOpen(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping in short mode")
	}

	database, dir, err := openRandomDB(F_APPENDONLY)
	if err != nil {
		t.Fatalf("Can't open database: %s", err.Error())
	}

	database.Close()
	cleanTemp(dir)
}

const JARN = 10

func TestJar(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping in short mode")
	}

	database, dir, err := openRandomDB(F_LZ4 | F_SPLAYTREE)
	if err != nil {
		t.Fatalf("Can't open database: %s", err.Error())
	}

	for i := 0; i < JARN; i++ {
		if database.Jar("record"+strconv.Itoa(i), []byte("value"+strconv.Itoa(i))) != 0 {
			t.Fatalf("Can't jar value #%d", i)
		}
	}

	database.Close()
	cleanTemp(dir)
}

func TestUnjar(t *testing.T) {
	database, dir, err := openRandomDB(F_LZ4 | F_SPLAYTREE)
	if err != nil {
		t.Fatalf("Can't open database: %s", err.Error())
	}

	for i := 0; i < JARN; i++ {
		if database.Jar("record"+strconv.Itoa(i), []byte("value"+strconv.Itoa(i))) != 0 {
			t.Fatalf("Can't jar value #%d", i)
		}
	}

	for i := 0; i < JARN; i++ {
		val := database.Unjar("record" + strconv.Itoa(i))
		if !bytes.Equal(val, []byte("value"+strconv.Itoa(i))) {
			t.Errorf("Value #%d doesn't match", i)
		}
	}

	database.Close()
	cleanTemp(dir)
}

func TestFullKeyDump(t *testing.T) {
	database, _, err := openRandomDB(F_LZ4 | F_SPLAYTREE)
	if err != nil {
		t.Fatalf("Can't open database: %s", err.Error())
	}

	for i := 0; i < JARN; i++ {
		if database.Jar("record"+strconv.Itoa(i), []byte("value"+strconv.Itoa(i))) != 0 {
			t.Fatalf("Can't jar value #%d", i)
		}
	}

	gotKeys, keys := database.DumpKeys()

	if !gotKeys {
		t.Fatal("Didn't get keys and should have")
	}

	var j int
	for i := 0; i <= JARN; i++ {
		for _, key := range keys {
			if key == "record"+strconv.Itoa(i) {
				j++
			}
		}
	}
	if j != JARN {
		t.Fatal("One or more keys did not dump")
	}
}

func TestBulkUnjarOnlyReturnsKeysWeGiveIt(t *testing.T) {
	database, _, err := openRandomDB(F_LZ4 | F_SPLAYTREE)
	if err != nil {
		t.Fatalf("Can't open database: %s", err.Error())
	}

	keys := []string{"key0", "key1", "key2", "key3"}

	for i, key := range keys {
		if database.Jar(key, []byte("value"+strconv.Itoa(i))) != 0 {
			t.Fatalf("Can't jar value #%d", i)
		}
	}

	subset := keys[1:] //sans key0

	values := database.BulkUnjar(subset)

	if l := len(values); l != 3 {
		t.Fatalf("Expected a length of 3, got %d", l)
	}

	for i, value := range values {
		if subset[i][3] != string(value)[5] {
			t.Fatalf("Expected %s, got %s", subset[i][3], string(value)[5])
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"runtime"
	"strconv"
	"time"

	"github.com/parnurzeal/gorequest"
)

type Edge struct {
	I      int
	J      int
	Weight int
}

type graph struct {
	edges    []Edge
	vertices int
}

type builder struct {
	data        map[int]map[int]int
	edgesAmount int
}

func buildGraph(builder builder) graph {
	graph := graph{[]Edge{}, len(builder.data)}
	for source, neighbors := range builder.data {
		for target, weight := range neighbors {
			graph.edges = append(graph.edges, Edge{source, target, weight})
		}
	}
	return graph
}

func fetchEdgesAmount(client *gorequest.SuperAgent) int {
	_, body, _ := client.Get("http://localhost:8080/api/graph/edges-quantity").End()
	edgesAmount, _ := strconv.ParseInt(body, 10, 32)
	return int(edgesAmount)
}

func fetchEdges(offset int, limit int, channel chan<- []Edge, client *gorequest.SuperAgent) {
	var edges []Edge
	time.Sleep(2 * time.Second)
	resp, err := http.Get(fmt.Sprintf(
		"http://localhost:8080/api/graph?offset=%d&limit=%d",
		offset, limit))
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(0)
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(0)
	}
	err = json.Unmarshal(body, &edges)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(0)
	}
	channel <- edges
}

func main() {
	begin := time.Now()
	httpClient := gorequest.New()

	edgesAmount, limit := fetchEdgesAmount(httpClient), 1000
	batches := edgesAmount / limit
	if edgesAmount%limit > 0 {
		batches++
	}
	edgesRange := make(chan []Edge, runtime.NumCPU()*8)
	for i := 0; i < batches; i++ {
		go fetchEdges(i*limit, limit, edgesRange, httpClient)
	}
	builder := builder{map[int]map[int]int{}, 0}
	for i := 0; i < batches; i++ {
		edges := <-edgesRange
		for _, edge := range edges {
			neighbors, contains := builder.data[edge.I]
			if !contains {
				builder.data[edge.I] = map[int]int{}
				neighbors = builder.data[edge.I]
			}
			neighbors[edge.J] = edge.Weight
		}
	}

	graph := buildGraph(builder)
	fmt.Println("Vertices:", graph.vertices)
	fmt.Println("Edges:", len(graph.edges))
	fmt.Println("Milliseconds taken:", int(time.Since(begin).Nanoseconds()/1000000))
}
<commit_msg>Go client now retries requests on failure<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"runtime"
	"strconv"
	"time"

	"github.com/parnurzeal/gorequest"
)

type Edge struct {
	I      int
	J      int
	Weight int
}

type graph struct {
	edges    []Edge
	vertices int
}

type builder struct {
	data        map[int]map[int]int
	edgesAmount int
}

func buildGraph(builder builder) graph {
	graph := graph{[]Edge{}, len(builder.data)}
	for source, neighbors := range builder.data {
		for target, weight := range neighbors {
			graph.edges = append(graph.edges, Edge{source, target, weight})
		}
	}
	return graph
}

func fetchEdgesAmount(client *gorequest.SuperAgent) int {
	_, body, _ := client.Get("http://localhost:8080/api/graph/edges-quantity").End()
	edgesAmount, _ := strconv.ParseInt(body, 10, 32)
	return int(edgesAmount)
}

func fetchEdges(offset int, limit int, channel chan<- []Edge, client *gorequest.SuperAgent) {
	var edges []Edge
	done, url := false, fmt.Sprintf(
		"http://localhost:8080/api/graph?offset=%d&limit=%d",
		offset, limit)
	for resp, err := http.Get(url); !done; resp, err = http.Get(url) {
		if err != nil {
			fmt.Println(err.Error())
			os.Exit(0)
		}
		done = func() bool {
			defer resp.Body.Close()
			if resp.StatusCode == 200 {
				body, err := ioutil.ReadAll(resp.Body)
				if err != nil {
					fmt.Println(err.Error())
					os.Exit(0)
				}
				err = json.Unmarshal(body, &edges)
				if err != nil {
					fmt.Println(err.Error())
					os.Exit(0)
				}
				channel <- edges
			}
			return resp.StatusCode == 200
		}()
	}
}

func main() {
	begin := time.Now()
	httpClient := gorequest.New()

	edgesAmount, limit := fetchEdgesAmount(httpClient), 1000
	batches := edgesAmount / limit
	if edgesAmount%limit > 0 {
		batches++
	}
	edgesRange := make(chan []Edge, runtime.NumCPU()*8)
	for i := 0; i < batches; i++ {
		go fetchEdges(i*limit, limit, edgesRange, httpClient)
	}
	builder := builder{map[int]map[int]int{}, 0}
	for i := 0; i < batches; i++ {
		edges := <-edgesRange
		for _, edge := range edges {
			neighbors, contains := builder.data[edge.I]
			if !contains {
				builder.data[edge.I] = map[int]int{}
				neighbors = builder.data[edge.I]
			}
			neighbors[edge.J] = edge.Weight
		}
	}

	graph := buildGraph(builder)
	fmt.Println("Vertices:", graph.vertices)
	fmt.Println("Edges:", len(graph.edges))
	fmt.Println("Milliseconds taken:", int(time.Since(begin).Nanoseconds()/1000000))
}
<|endoftext|>


<commit_before>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

// +build darwin

package client

import (
	"encoding/json"
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/keybase/cli"
	"github.com/keybase/client/go/install"
	"github.com/keybase/client/go/launchd"
	"github.com/keybase/client/go/libcmdline"
	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
)

func NewCmdInstall(cl *libcmdline.CommandLine, g *libkb.GlobalContext) cli.Command {
	return cli.Command{
		Name: "install",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "f, force",
				Usage: "Force install actions.",
			},
			cli.StringFlag{
				Name:  "o, format",
				Usage: "Format for output. Specify 'json' for JSON or blank for default.",
			},
			cli.StringFlag{
				Name:  "b, bin-path",
				Usage: "Full path to the executable, if it would be ambiguous otherwise.",
			},
			cli.StringFlag{
				Name:  "i, installer",
				Usage: "Installer to use.",
			},
			cli.StringFlag{
				Name:  "c, components",
				Usage: fmt.Sprintf("Components to install, comma separated (%q)", install.ComponentNames),
			},
			cli.DurationFlag{
				Name:  "t, timeout",
				Usage: "Timeout as duration, such as '10s' or '1m'.",
			},
			cli.StringFlag{
				Name:  "source-path",
				Usage: "Source path to app bundle.",
			},
		},
		ArgumentHelp: "",
		Usage:        "Installs Keybase components",
		Action: func(c *cli.Context) {
			cl.SetLogForward(libcmdline.LogForwardNone)
			cl.SetForkCmd(libcmdline.NoFork)
			cl.ChooseCommand(NewCmdInstallRunner(g), "install", c)
		},
	}
}

type CmdInstall struct {
	libkb.Contextified
	force      bool
	format     string
	binPath    string
	installer  string
	sourcePath string
	timeout    time.Duration
	components []string
}

func NewCmdInstallRunner(g *libkb.GlobalContext) *CmdInstall {
	return &CmdInstall{
		Contextified: libkb.NewContextified(g),
	}
}

func (v *CmdInstall) GetUsage() libkb.Usage {
	return libkb.Usage{}
}

var defaultInstallComponents = []string{
	install.ComponentNameUpdater.String(),
	install.ComponentNameService.String(),
	install.ComponentNameCLI.String(),
	install.ComponentNameHelper.String(),
	install.ComponentNameFuse.String(),
	install.ComponentNameMountDir.String(),
	install.ComponentNameKBFS.String(),
	install.ComponentNameKBNM.String(),
}

func (v *CmdInstall) ParseArgv(ctx *cli.Context) error {
	v.force = ctx.Bool("force")
	v.format = ctx.String("format")
	v.binPath = ctx.String("bin-path")
	v.installer = ctx.String("installer")
	v.timeout = ctx.Duration("timeout")
	v.sourcePath = ctx.String("source-path")
	if v.timeout == 0 {
		v.timeout = 11 * time.Second
	}
	if ctx.String("components") == "" {
		v.components = defaultInstallComponents
	} else {
		v.components = strings.Split(ctx.String("components"), ",")
	}

	// Brew uses the auto installer by default
	if libkb.IsBrewBuild && v.installer == "" {
		v.installer = "auto"
	}

	return nil
}

func (v *CmdInstall) runInstall() keybase1.InstallResult {
	err := install.CheckIfValidLocation()
	if err != nil {
		v.G().Log.Errorf("%s", err)
		return keybase1.InstallResult{Status: err.Status(), Fatal: true}
	}

	if v.installer == "auto" {
		return install.AutoInstallWithStatus(v.G(), v.binPath, v.force, v.timeout, v.G().Log)
	} else if v.installer == "" {
		return install.Install(v.G(), v.binPath, v.sourcePath, v.components, v.force, v.timeout, v.G().Log)
	}

	return keybase1.InstallResult{Status: keybase1.StatusFromCode(keybase1.StatusCode_SCInstallError, fmt.Sprintf("Invalid installer: %s", v.installer))}
}

func (v *CmdInstall) Run() error {
	result := v.runInstall()
	if v.format == "json" {
		out, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return err
		}
		fmt.Fprintf(os.Stdout, "%s\n", out)
	}
	exitOnError(result)
	return nil
}

func exitOnError(result keybase1.InstallResult) {
	if result.Fatal {
		os.Exit(1)
	}
	for _, r := range result.ComponentResults {
		if r.Status.Code != 0 {
			os.Exit(2)
		}
	}
}

var defaultUninstallComponents = []string{
	install.ComponentNameService.String(),
	install.ComponentNameKBFS.String(),
	install.ComponentNameKBNM.String(),
	install.ComponentNameMountDir.String(),
	install.ComponentNameUpdater.String(),
	install.ComponentNameFuse.String(),
	install.ComponentNameHelper.String(),
	install.ComponentNameCLI.String(),
}

func NewCmdUninstall(cl *libcmdline.CommandLine, g *libkb.GlobalContext) cli.Command {
	return cli.Command{
		Name: "uninstall",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "o, format",
				Usage: "Format for output. Specify 'json' for JSON or blank for default.",
			},
			cli.StringFlag{
				Name:  "c, components",
				Usage: fmt.Sprintf("Components to uninstall, comma separated (%q)", install.ComponentNames),
			},
		},
		ArgumentHelp: "",
		Usage:        "Uninstalls Keybase components",
		Action: func(c *cli.Context) {
			cl.SetLogForward(libcmdline.LogForwardNone)
			cl.SetForkCmd(libcmdline.NoFork)
			cl.ChooseCommand(NewCmdUninstallRunner(g), "uninstall", c)
		},
	}
}

type CmdUninstall struct {
	libkb.Contextified
	format     string
	components []string
	isDefault  bool
}

func NewCmdUninstallRunner(g *libkb.GlobalContext) *CmdUninstall {
	return &CmdUninstall{
		Contextified: libkb.NewContextified(g),
	}
}

func (v *CmdUninstall) GetUsage() libkb.Usage {
	return libkb.Usage{}
}

func (v *CmdUninstall) ParseArgv(ctx *cli.Context) error {
	v.format = ctx.String("format")
	if ctx.String("components") == "" {
		v.isDefault = true
		if libkb.IsBrewBuild {
			v.components = []string{"service"}
		} else {
			v.components = defaultUninstallComponents
		}
	} else {
		v.components = strings.Split(ctx.String("components"), ",")
	}
	return nil
}

func (v *CmdUninstall) Run() error {
	bundlePath, err := install.AppBundleForPath()
	if err != nil {
		return err
	}
	result := install.Uninstall(v.G(), v.components, v.G().Log)
	if v.format == "json" {
		out, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return err
		}
		fmt.Fprintf(os.Stdout, "%s\n", out)
	} else {
		if v.isDefault {
			t := v.G().UI.GetTerminalUI()
			t.Printf("\nYou can now remove %s to complete your uninstall.\n", bundlePath)
		}
	}
	return nil
}

func DiagnoseSocketError(ui libkb.UI, err error) {
	t := ui.GetTerminalUI()
	services, err := launchd.ListServices([]string{"keybase.service.", "homebrew.mxcl.keybase"})
	if err != nil {
		t.Printf("Error checking launchd services: %s\n\n", err)
		return
	}

	if len(services) == 0 {
		if libkb.IsBrewBuild {
			t.Printf("\nThere are no Keybase services installed, you might try running:\n\n\tkeybase install\n\n")
		} else {
			bundlePath, err := install.AppBundleForPath()
			if err != nil {
				t.Printf("No app bundle: %s\n\n", err)
				return
			}
			t.Printf("\nKeybase isn't running. To start, you can run:\n\n\topen %s\n\n", bundlePath)
		}
	} else if len(services) > 1 {
		t.Printf("\nWe found multiple services:\n")
		for _, service := range services {
			t.Printf("  " + service.StatusDescription() + "\n")
		}
		t.Printf("\n")
	} else if len(services) == 1 {
		service := services[0]
		status, err := service.LoadStatus()
		if err != nil {
			t.Printf("Error checking service status(%s): %v\n\n", service.Label(), err)
		} else {
			if status == nil || !status.IsRunning() {
				t.Printf("\nWe found a Keybase service (%s) but it's not running.\n", service.Label())
				cmd := fmt.Sprintf("keybase launchd start %s", service.Label())
				t.Printf("You might try starting it: " + cmd + "\n\n")
			} else {
				t.Printf("\nWe couldn't connect but there is a Keybase service (%s) running (%s).\n\n", status.Label(), status.Pid())
				cmd := fmt.Sprintf("keybase launchd restart %s", service.Label())
				t.Printf("You might try restarting it: " + cmd + "\n\n")
			}
		}
	}
}

func newCmdInstallAuto(cl *libcmdline.CommandLine, g *libkb.GlobalContext) cli.Command {
	return cli.Command{
		Name: "install-auto",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "b, bin-path",
				Usage: "Full path to the executable, if it would be ambiguous otherwise.",
			},
			cli.DurationFlag{
				Name:  "t, timeout",
				Usage: "Timeout as duration, such as '10s' or '1m'.",
			},
			cli.StringFlag{
				Name:  "source-path",
				Usage: "Source path to app bundle.",
			},
			cli.StringFlag{
				Name:  "o, format",
				Usage: "Format for output. Specify 'json' for JSON or blank for default.",
			},
		},
		ArgumentHelp: "",
		Usage:        "Installs Keybase by choosing automatically which components to install",
		Action: func(c *cli.Context) {
			cl.SetLogForward(libcmdline.LogForwardNone)
			cl.SetForkCmd(libcmdline.NoFork)
			cl.ChooseCommand(newCmdInstallAutoRunner(g), "install-auto", c)
		},
	}
}

type cmdInstallAuto struct {
	libkb.Contextified
	binPath    string
	sourcePath string
	format     string
	timeout    time.Duration
}

func newCmdInstallAutoRunner(g *libkb.GlobalContext) *cmdInstallAuto {
	return &cmdInstallAuto{
		Contextified: libkb.NewContextified(g),
	}
}

func (v *cmdInstallAuto) GetUsage() libkb.Usage {
	return libkb.Usage{}
}

func (v *cmdInstallAuto) ParseArgv(ctx *cli.Context) error {
	v.binPath = ctx.String("bin-path")
	v.timeout = ctx.Duration("timeout")
	v.sourcePath = ctx.String("source-path")
	v.format = ctx.String("format")
	if v.timeout == 0 {
		v.timeout = 11 * time.Second
	}
	return nil
}

func (v *cmdInstallAuto) Run() error {
	result := install.InstallAuto(v.G(), v.binPath, v.sourcePath, v.timeout, v.G().Log)
	if v.format == "json" {
		out, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return err
		}
		fmt.Fprintf(os.Stdout, "%s\n", out)
	}
	return nil
}
<commit_msg>Hide osx internal installer commands<commit_after>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

// +build darwin

package client

import (
	"encoding/json"
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/keybase/cli"
	"github.com/keybase/client/go/install"
	"github.com/keybase/client/go/launchd"
	"github.com/keybase/client/go/libcmdline"
	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
)

func NewCmdInstall(cl *libcmdline.CommandLine, g *libkb.GlobalContext) cli.Command {
	return cli.Command{
		Name: "install",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "f, force",
				Usage: "Force install actions.",
			},
			cli.StringFlag{
				Name:  "o, format",
				Usage: "Format for output. Specify 'json' for JSON or blank for default.",
			},
			cli.StringFlag{
				Name:  "b, bin-path",
				Usage: "Full path to the executable, if it would be ambiguous otherwise.",
			},
			cli.StringFlag{
				Name:  "i, installer",
				Usage: "Installer to use.",
			},
			cli.StringFlag{
				Name:  "c, components",
				Usage: fmt.Sprintf("Components to install, comma separated (%q)", install.ComponentNames),
			},
			cli.DurationFlag{
				Name:  "t, timeout",
				Usage: "Timeout as duration, such as '10s' or '1m'.",
			},
			cli.StringFlag{
				Name:  "source-path",
				Usage: "Source path to app bundle.",
			},
		},
		ArgumentHelp: "",
		Action: func(c *cli.Context) {
			cl.SetLogForward(libcmdline.LogForwardNone)
			cl.SetForkCmd(libcmdline.NoFork)
			cl.ChooseCommand(NewCmdInstallRunner(g), "install", c)
		},
	}
}

type CmdInstall struct {
	libkb.Contextified
	force      bool
	format     string
	binPath    string
	installer  string
	sourcePath string
	timeout    time.Duration
	components []string
}

func NewCmdInstallRunner(g *libkb.GlobalContext) *CmdInstall {
	return &CmdInstall{
		Contextified: libkb.NewContextified(g),
	}
}

func (v *CmdInstall) GetUsage() libkb.Usage {
	return libkb.Usage{}
}

var defaultInstallComponents = []string{
	install.ComponentNameUpdater.String(),
	install.ComponentNameService.String(),
	install.ComponentNameCLI.String(),
	install.ComponentNameHelper.String(),
	install.ComponentNameFuse.String(),
	install.ComponentNameMountDir.String(),
	install.ComponentNameKBFS.String(),
	install.ComponentNameKBNM.String(),
}

func (v *CmdInstall) ParseArgv(ctx *cli.Context) error {
	v.force = ctx.Bool("force")
	v.format = ctx.String("format")
	v.binPath = ctx.String("bin-path")
	v.installer = ctx.String("installer")
	v.timeout = ctx.Duration("timeout")
	v.sourcePath = ctx.String("source-path")
	if v.timeout == 0 {
		v.timeout = 11 * time.Second
	}
	if ctx.String("components") == "" {
		v.components = defaultInstallComponents
	} else {
		v.components = strings.Split(ctx.String("components"), ",")
	}

	// Brew uses the auto installer by default
	if libkb.IsBrewBuild && v.installer == "" {
		v.installer = "auto"
	}

	return nil
}

func (v *CmdInstall) runInstall() keybase1.InstallResult {
	err := install.CheckIfValidLocation()
	if err != nil {
		v.G().Log.Errorf("%s", err)
		return keybase1.InstallResult{Status: err.Status(), Fatal: true}
	}

	if v.installer == "auto" {
		return install.AutoInstallWithStatus(v.G(), v.binPath, v.force, v.timeout, v.G().Log)
	} else if v.installer == "" {
		return install.Install(v.G(), v.binPath, v.sourcePath, v.components, v.force, v.timeout, v.G().Log)
	}

	return keybase1.InstallResult{Status: keybase1.StatusFromCode(keybase1.StatusCode_SCInstallError, fmt.Sprintf("Invalid installer: %s", v.installer))}
}

func (v *CmdInstall) Run() error {
	result := v.runInstall()
	if v.format == "json" {
		out, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return err
		}
		fmt.Fprintf(os.Stdout, "%s\n", out)
	}
	exitOnError(result)
	return nil
}

func exitOnError(result keybase1.InstallResult) {
	if result.Fatal {
		os.Exit(1)
	}
	for _, r := range result.ComponentResults {
		if r.Status.Code != 0 {
			os.Exit(2)
		}
	}
}

var defaultUninstallComponents = []string{
	install.ComponentNameService.String(),
	install.ComponentNameKBFS.String(),
	install.ComponentNameKBNM.String(),
	install.ComponentNameMountDir.String(),
	install.ComponentNameUpdater.String(),
	install.ComponentNameFuse.String(),
	install.ComponentNameHelper.String(),
	install.ComponentNameCLI.String(),
}

func NewCmdUninstall(cl *libcmdline.CommandLine, g *libkb.GlobalContext) cli.Command {
	return cli.Command{
		Name: "uninstall",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "o, format",
				Usage: "Format for output. Specify 'json' for JSON or blank for default.",
			},
			cli.StringFlag{
				Name:  "c, components",
				Usage: fmt.Sprintf("Components to uninstall, comma separated (%q)", install.ComponentNames),
			},
		},
		ArgumentHelp: "",
		Action: func(c *cli.Context) {
			cl.SetLogForward(libcmdline.LogForwardNone)
			cl.SetForkCmd(libcmdline.NoFork)
			cl.ChooseCommand(NewCmdUninstallRunner(g), "uninstall", c)
		},
	}
}

type CmdUninstall struct {
	libkb.Contextified
	format     string
	components []string
	isDefault  bool
}

func NewCmdUninstallRunner(g *libkb.GlobalContext) *CmdUninstall {
	return &CmdUninstall{
		Contextified: libkb.NewContextified(g),
	}
}

func (v *CmdUninstall) GetUsage() libkb.Usage {
	return libkb.Usage{}
}

func (v *CmdUninstall) ParseArgv(ctx *cli.Context) error {
	v.format = ctx.String("format")
	if ctx.String("components") == "" {
		v.isDefault = true
		if libkb.IsBrewBuild {
			v.components = []string{"service"}
		} else {
			v.components = defaultUninstallComponents
		}
	} else {
		v.components = strings.Split(ctx.String("components"), ",")
	}
	return nil
}

func (v *CmdUninstall) Run() error {
	bundlePath, err := install.AppBundleForPath()
	if err != nil {
		return err
	}
	result := install.Uninstall(v.G(), v.components, v.G().Log)
	if v.format == "json" {
		out, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return err
		}
		fmt.Fprintf(os.Stdout, "%s\n", out)
	} else {
		if v.isDefault {
			t := v.G().UI.GetTerminalUI()
			t.Printf("\nYou can now remove %s to complete your uninstall.\n", bundlePath)
		}
	}
	return nil
}

func DiagnoseSocketError(ui libkb.UI, err error) {
	t := ui.GetTerminalUI()
	services, err := launchd.ListServices([]string{"keybase.service.", "homebrew.mxcl.keybase"})
	if err != nil {
		t.Printf("Error checking launchd services: %s\n\n", err)
		return
	}

	if len(services) == 0 {
		if libkb.IsBrewBuild {
			t.Printf("\nThere are no Keybase services installed, you might try running:\n\n\tkeybase install\n\n")
		} else {
			bundlePath, err := install.AppBundleForPath()
			if err != nil {
				t.Printf("No app bundle: %s\n\n", err)
				return
			}
			t.Printf("\nKeybase isn't running. To start, you can run:\n\n\topen %s\n\n", bundlePath)
		}
	} else if len(services) > 1 {
		t.Printf("\nWe found multiple services:\n")
		for _, service := range services {
			t.Printf("  " + service.StatusDescription() + "\n")
		}
		t.Printf("\n")
	} else if len(services) == 1 {
		service := services[0]
		status, err := service.LoadStatus()
		if err != nil {
			t.Printf("Error checking service status(%s): %v\n\n", service.Label(), err)
		} else {
			if status == nil || !status.IsRunning() {
				t.Printf("\nWe found a Keybase service (%s) but it's not running.\n", service.Label())
				cmd := fmt.Sprintf("keybase launchd start %s", service.Label())
				t.Printf("You might try starting it: " + cmd + "\n\n")
			} else {
				t.Printf("\nWe couldn't connect but there is a Keybase service (%s) running (%s).\n\n", status.Label(), status.Pid())
				cmd := fmt.Sprintf("keybase launchd restart %s", service.Label())
				t.Printf("You might try restarting it: " + cmd + "\n\n")
			}
		}
	}
}

func newCmdInstallAuto(cl *libcmdline.CommandLine, g *libkb.GlobalContext) cli.Command {
	return cli.Command{
		Name: "install-auto",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "b, bin-path",
				Usage: "Full path to the executable, if it would be ambiguous otherwise.",
			},
			cli.DurationFlag{
				Name:  "t, timeout",
				Usage: "Timeout as duration, such as '10s' or '1m'.",
			},
			cli.StringFlag{
				Name:  "source-path",
				Usage: "Source path to app bundle.",
			},
			cli.StringFlag{
				Name:  "o, format",
				Usage: "Format for output. Specify 'json' for JSON or blank for default.",
			},
		},
		ArgumentHelp: "",
		Action: func(c *cli.Context) {
			cl.SetLogForward(libcmdline.LogForwardNone)
			cl.SetForkCmd(libcmdline.NoFork)
			cl.ChooseCommand(newCmdInstallAutoRunner(g), "install-auto", c)
		},
	}
}

type cmdInstallAuto struct {
	libkb.Contextified
	binPath    string
	sourcePath string
	format     string
	timeout    time.Duration
}

func newCmdInstallAutoRunner(g *libkb.GlobalContext) *cmdInstallAuto {
	return &cmdInstallAuto{
		Contextified: libkb.NewContextified(g),
	}
}

func (v *cmdInstallAuto) GetUsage() libkb.Usage {
	return libkb.Usage{}
}

func (v *cmdInstallAuto) ParseArgv(ctx *cli.Context) error {
	v.binPath = ctx.String("bin-path")
	v.timeout = ctx.Duration("timeout")
	v.sourcePath = ctx.String("source-path")
	v.format = ctx.String("format")
	if v.timeout == 0 {
		v.timeout = 11 * time.Second
	}
	return nil
}

func (v *cmdInstallAuto) Run() error {
	result := install.InstallAuto(v.G(), v.binPath, v.sourcePath, v.timeout, v.G().Log)
	if v.format == "json" {
		out, err := json.MarshalIndent(result, "", "  ")
		if err != nil {
			return err
		}
		fmt.Fprintf(os.Stdout, "%s\n", out)
	}
	return nil
}
<|endoftext|>


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

package main

import (
	"archive/zip"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
)

type mode int

const (
	invalidMode mode = iota
	archiveMode
	copyMode
	linkMode
)

func modeFromString(s string) (mode, error) {
	switch s {
	case "archive":
		return archiveMode, nil
	case "copy":
		return copyMode, nil
	case "link":
		return linkMode, nil
	default:
		return invalidMode, fmt.Errorf("invalid mode: %s", s)
	}
}

type manifestEntry struct {
	Src, Dst string
}

func main() {
	log.SetPrefix("GoPath: ")
	log.SetFlags(0)
	if err := run(os.Args[1:]); err != nil {
		log.Fatal(err)
	}
}

func run(args []string) error {
	var manifest, out string
	flags := flag.NewFlagSet("go_path", flag.ContinueOnError)
	flags.StringVar(&manifest, "manifest", "", "name of json file listing files to include")
	flags.StringVar(&out, "out", "", "output file or directory")
	modeFlag := flags.String("mode", "", "copy, link, or archive")
	if err := flags.Parse(args); err != nil {
		return err
	}
	if manifest == "" {
		return errors.New("-manifest not set")
	}
	if out == "" {
		return errors.New("-out not set")
	}
	if *modeFlag == "" {
		return errors.New("-mode not set")
	}
	mode, err := modeFromString(*modeFlag)
	if err != nil {
		return err
	}

	entries, err := readManifest(manifest)
	if err != nil {
		return err
	}

	switch mode {
	case archiveMode:
		err = archivePath(out, entries)
	case copyMode:
		err = copyPath(out, entries)
	case linkMode:
		err = linkPath(out, entries)
	}
	return err
}

func readManifest(path string) ([]manifestEntry, error) {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, fmt.Errorf("error reading manifest: %v", err)
	}
	var entries []manifestEntry
	if err := json.Unmarshal(data, &entries); err != nil {
		return nil, fmt.Errorf("error unmarshalling manifest %s: %v", path, err)
	}
	return entries, nil
}

func archivePath(out string, manifest []manifestEntry) (err error) {
	outFile, err := os.Create(out)
	if err != nil {
		return err
	}
	defer func() {
		if e := outFile.Close(); err == nil && e != nil {
			err = fmt.Errorf("error closing archive %s: %v", out, e)
		}
	}()
	outZip := zip.NewWriter(outFile)

	for _, entry := range manifest {
		srcFile, err := os.Open(abs(filepath.FromSlash(entry.Src)))
		if err != nil {
			return err
		}
		w, err := outZip.Create(entry.Dst)
		if err != nil {
			srcFile.Close()
			return err
		}
		if _, err := io.Copy(w, srcFile); err != nil {
			srcFile.Close()
			return err
		}
		if err := srcFile.Close(); err != nil {
			return err
		}
	}

	if err := outZip.Close(); err != nil {
		return fmt.Errorf("error constructing archive %s: %v", out, err)
	}
	return nil
}

func copyPath(out string, manifest []manifestEntry) error {
	if err := os.MkdirAll(out, 0777); err != nil {
		return err
	}
	for _, entry := range manifest {
		dst := filepath.Join(out, filepath.FromSlash(entry.Dst))
		if err := os.MkdirAll(filepath.Dir(dst), 0777); err != nil {
			return err
		}
		srcFile, err := os.Open(abs(filepath.FromSlash(entry.Src)))
		if err != nil {
			return err
		}
		dstFile, err := os.Create(dst)
		if err != nil {
			srcFile.Close()
			return err
		}
		if _, err := io.Copy(dstFile, srcFile); err != nil {
			dstFile.Close()
			srcFile.Close()
			return err
		}
		srcFile.Close()
		if err := dstFile.Close(); err != nil {
			return err
		}
	}
	return nil
}

func linkPath(out string, manifest []manifestEntry) error {
	// out directory may already exist and may contain old symlinks. Delete.
	if err := os.RemoveAll(out); err != nil {
		return err
	}
	if err := os.MkdirAll(out, 0777); err != nil {
		return err
	}
	for _, entry := range manifest {
		dst := filepath.Join(out, filepath.FromSlash(entry.Dst))
		dstDir := filepath.Dir(dst)
		src, _ := filepath.Rel(dstDir, entry.Src)
		if err := os.MkdirAll(dstDir, 0777); err != nil {
			return err
		}
		if err := os.Symlink(src, dst); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>Use absolute destination path so that the longpath windows code in stdlib can do its work (#2854)<commit_after>// Copyright 2018 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"archive/zip"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
)

type mode int

const (
	invalidMode mode = iota
	archiveMode
	copyMode
	linkMode
)

func modeFromString(s string) (mode, error) {
	switch s {
	case "archive":
		return archiveMode, nil
	case "copy":
		return copyMode, nil
	case "link":
		return linkMode, nil
	default:
		return invalidMode, fmt.Errorf("invalid mode: %s", s)
	}
}

type manifestEntry struct {
	Src, Dst string
}

func main() {
	log.SetPrefix("GoPath: ")
	log.SetFlags(0)
	if err := run(os.Args[1:]); err != nil {
		log.Fatal(err)
	}
}

func run(args []string) error {
	var manifest, out string
	flags := flag.NewFlagSet("go_path", flag.ContinueOnError)
	flags.StringVar(&manifest, "manifest", "", "name of json file listing files to include")
	flags.StringVar(&out, "out", "", "output file or directory")
	modeFlag := flags.String("mode", "", "copy, link, or archive")
	if err := flags.Parse(args); err != nil {
		return err
	}
	if manifest == "" {
		return errors.New("-manifest not set")
	}
	if out == "" {
		return errors.New("-out not set")
	}
	if *modeFlag == "" {
		return errors.New("-mode not set")
	}
	mode, err := modeFromString(*modeFlag)
	if err != nil {
		return err
	}

	entries, err := readManifest(manifest)
	if err != nil {
		return err
	}

	switch mode {
	case archiveMode:
		err = archivePath(out, entries)
	case copyMode:
		err = copyPath(out, entries)
	case linkMode:
		err = linkPath(out, entries)
	}
	return err
}

func readManifest(path string) ([]manifestEntry, error) {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, fmt.Errorf("error reading manifest: %v", err)
	}
	var entries []manifestEntry
	if err := json.Unmarshal(data, &entries); err != nil {
		return nil, fmt.Errorf("error unmarshalling manifest %s: %v", path, err)
	}
	return entries, nil
}

func archivePath(out string, manifest []manifestEntry) (err error) {
	outFile, err := os.Create(out)
	if err != nil {
		return err
	}
	defer func() {
		if e := outFile.Close(); err == nil && e != nil {
			err = fmt.Errorf("error closing archive %s: %v", out, e)
		}
	}()
	outZip := zip.NewWriter(outFile)

	for _, entry := range manifest {
		srcFile, err := os.Open(abs(filepath.FromSlash(entry.Src)))
		if err != nil {
			return err
		}
		w, err := outZip.Create(entry.Dst)
		if err != nil {
			srcFile.Close()
			return err
		}
		if _, err := io.Copy(w, srcFile); err != nil {
			srcFile.Close()
			return err
		}
		if err := srcFile.Close(); err != nil {
			return err
		}
	}

	if err := outZip.Close(); err != nil {
		return fmt.Errorf("error constructing archive %s: %v", out, err)
	}
	return nil
}

func copyPath(out string, manifest []manifestEntry) error {
	if err := os.MkdirAll(out, 0777); err != nil {
		return err
	}
	for _, entry := range manifest {
		dst := abs(filepath.Join(out, filepath.FromSlash(entry.Dst)))
		if err := os.MkdirAll(filepath.Dir(dst), 0777); err != nil {
			return err
		}
		srcFile, err := os.Open(abs(filepath.FromSlash(entry.Src)))
		if err != nil {
			return err
		}
		dstFile, err := os.Create(dst)
		if err != nil {
			srcFile.Close()
			return err
		}
		if _, err := io.Copy(dstFile, srcFile); err != nil {
			dstFile.Close()
			srcFile.Close()
			return err
		}
		srcFile.Close()
		if err := dstFile.Close(); err != nil {
			return err
		}
	}
	return nil
}

func linkPath(out string, manifest []manifestEntry) error {
	// out directory may already exist and may contain old symlinks. Delete.
	if err := os.RemoveAll(out); err != nil {
		return err
	}
	if err := os.MkdirAll(out, 0777); err != nil {
		return err
	}
	for _, entry := range manifest {
		dst := filepath.Join(out, filepath.FromSlash(entry.Dst))
		dstDir := filepath.Dir(dst)
		src, _ := filepath.Rel(dstDir, entry.Src)
		if err := os.MkdirAll(dstDir, 0777); err != nil {
			return err
		}
		if err := os.Symlink(src, dst); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Vitess Authors.

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

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

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

package vitessdriver

import (
	"context"
	"database/sql"
	"database/sql/driver"
	"encoding/json"
	"errors"

	"google.golang.org/grpc"

	"vitess.io/vitess/go/vt/vtgate/grpcvtgateconn"
	"vitess.io/vitess/go/vt/vtgate/vtgateconn"
)

var (
	errNoIntermixing        = errors.New("named and positional arguments intermixing disallowed")
	errIsolationUnsupported = errors.New("isolation levels are not supported")
)

// Type-check interfaces.
var (
	_ driver.QueryerContext   = &conn{}
	_ driver.ExecerContext    = &conn{}
	_ driver.StmtQueryContext = &stmt{}
	_ driver.StmtExecContext  = &stmt{}
)

func init() {
	sql.Register("vitess", drv{})
}

// Open is a Vitess helper function for sql.Open().
//
// It opens a database connection to vtgate running at "address".
func Open(address, target string) (*sql.DB, error) {
	c := Configuration{
		Address: address,
		Target:  target,
	}
	return OpenWithConfiguration(c)
}

// OpenForStreaming is the same as Open() but uses streaming RPCs to retrieve
// the results.
//
// The streaming mode is recommended for large results.
func OpenForStreaming(address, target string) (*sql.DB, error) {
	c := Configuration{
		Address:   address,
		Target:    target,
		Streaming: true,
	}
	return OpenWithConfiguration(c)
}

// OpenWithConfiguration is the generic Vitess helper function for sql.Open().
//
// It allows to pass in a Configuration struct to control all possible
// settings of the Vitess Go SQL driver.
func OpenWithConfiguration(c Configuration) (*sql.DB, error) {
	c.setDefaults()

	json, err := c.toJSON()
	if err != nil {
		return nil, err
	}

	if len(c.GRPCDialOptions) != 0 {
		vtgateconn.RegisterDialer(c.Protocol, grpcvtgateconn.DialWithOpts(context.TODO(), c.GRPCDialOptions...))
	}

	return sql.Open(c.DriverName, json)
}

type drv struct {
}

// Open implements the database/sql/driver.Driver interface.
//
// For "name", the Vitess driver requires that a JSON object is passed in.
//
// Instead of using this call and passing in a hand-crafted JSON string, it's
// recommended to use the public Vitess helper functions like
// Open(), OpenShard() or OpenWithConfiguration() instead. These will generate
// the required JSON string behind the scenes for you.
//
// Example for a JSON string:
//
//   {"protocol": "grpc", "address": "localhost:1111", "target": "@master"}
//
// For a description of the available fields, see the Configuration struct.
func (d drv) Open(name string) (driver.Conn, error) {
	c := &conn{}
	err := json.Unmarshal([]byte(name), c)
	if err != nil {
		return nil, err
	}

	c.setDefaults()

	if c.convert, err = newConverter(&c.Configuration); err != nil {
		return nil, err
	}

	if err = c.dial(); err != nil {
		return nil, err
	}

	return c, nil
}

// Configuration holds all Vitess driver settings.
//
// Fields with documented default values do not have to be set explicitly.
type Configuration struct {
	// Protocol is the name of the vtgate RPC client implementation.
	// Note: In open-source "grpc" is the recommended implementation.
	//
	// Default: "grpc"
	Protocol string

	// Address must point to a vtgate instance.
	//
	// Format: hostname:port
	Address string

	// Target specifies the default target.
	Target string

	// Streaming is true when streaming RPCs are used.
	// Recommended for large results.
	// Default: false
	Streaming bool

	// DefaultLocation is the timezone string that will be used
	// when converting DATETIME and DATE into time.Time.
	// This setting has no effect if ConvertDatetime is not set.
	// Default: UTC
	DefaultLocation string

	// GRPCDialOptions registers a new vtgateconn dialer with these dial options using the
	// protocol as the key. This may overwrite the default grpcvtgateconn dial option
	// if a custom one hasn't been specified in the config.
	//
	// Default: none
	GRPCDialOptions []grpc.DialOption `json:"-"`

	// Driver is the name registered with the database/sql package. This override
	// is here in case you have wrapped the driver for stats or other interceptors.
	//
	// Default: "vitess"
	DriverName string `json:"-"`
}

// toJSON converts Configuration to the JSON string which is required by the
// Vitess driver. Default values for empty fields will be set.
func (c Configuration) toJSON() (string, error) {
	jsonBytes, err := json.Marshal(c)
	if err != nil {
		return "", err
	}
	return string(jsonBytes), nil
}

// setDefaults sets the default values for empty fields.
func (c *Configuration) setDefaults() {
	// if no protocol is provided default to grpc so the driver is in control
	// of the connection protocol and not the flag vtgateconn.VtgateProtocol
	if c.Protocol == "" {
		c.Protocol = "grpc"
	}

	if c.DriverName == "" {
		c.DriverName = "vitess"
	}
}

type conn struct {
	Configuration
	convert *converter
	conn    *vtgateconn.VTGateConn
	session *vtgateconn.VTGateSession
}

func (c *conn) dial() error {
	var err error
	c.conn, err = vtgateconn.DialProtocol(context.Background(), c.Protocol, c.Address)
	if err != nil {
		return err
	}
	c.session = c.conn.Session(c.Target, nil)
	return nil
}

func (c *conn) Prepare(query string) (driver.Stmt, error) {
	return &stmt{c: c, query: query}, nil
}

func (c *conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
	return c.Prepare(query)
}

func (c *conn) Close() error {
	c.conn.Close()
	return nil
}

func (c *conn) Begin() (driver.Tx, error) {
	if _, err := c.Exec("begin", nil); err != nil {
		return nil, err
	}
	return c, nil
}

func (c *conn) BeginTx(_ context.Context, opts driver.TxOptions) (driver.Tx, error) {
	// We don't use the context. The function signature accepts the context
	// to signal to the driver that it's allowed to call Rollback on Cancel.
	if opts.Isolation != driver.IsolationLevel(0) || opts.ReadOnly {
		return nil, errIsolationUnsupported
	}
	return c.Begin()
}

func (c *conn) Commit() error {
	_, err := c.Exec("commit", nil)
	return err
}

func (c *conn) Rollback() error {
	_, err := c.Exec("rollback", nil)
	return err
}

func (c *conn) Exec(query string, args []driver.Value) (driver.Result, error) {
	ctx := context.TODO()

	if c.Streaming {
		return nil, errors.New("Exec not allowed for streaming connections")
	}
	bindVars, err := c.convert.buildBindVars(args)
	if err != nil {
		return nil, err
	}

	qr, err := c.session.Execute(ctx, query, bindVars)
	if err != nil {
		return nil, err
	}
	return result{int64(qr.InsertID), int64(qr.RowsAffected)}, nil
}

func (c *conn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
	if c.Streaming {
		return nil, errors.New("Exec not allowed for streaming connections")
	}

	bv, err := c.convert.bindVarsFromNamedValues(args)
	if err != nil {
		return nil, err
	}
	qr, err := c.session.Execute(ctx, query, bv)
	if err != nil {
		return nil, err
	}
	return result{int64(qr.InsertID), int64(qr.RowsAffected)}, nil
}

func (c *conn) Query(query string, args []driver.Value) (driver.Rows, error) {
	ctx := context.TODO()
	bindVars, err := c.convert.buildBindVars(args)
	if err != nil {
		return nil, err
	}

	if c.Streaming {
		stream, err := c.session.StreamExecute(ctx, query, bindVars)
		if err != nil {
			return nil, err
		}
		return newStreamingRows(stream, c.convert), nil
	}

	qr, err := c.session.Execute(ctx, query, bindVars)
	if err != nil {
		return nil, err
	}
	return newRows(qr, c.convert), nil
}

func (c *conn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
	bv, err := c.convert.bindVarsFromNamedValues(args)
	if err != nil {
		return nil, err
	}

	if c.Streaming {
		stream, err := c.session.StreamExecute(ctx, query, bv)
		if err != nil {
			return nil, err
		}
		return newStreamingRows(stream, c.convert), nil
	}

	qr, err := c.session.Execute(ctx, query, bv)
	if err != nil {
		return nil, err
	}
	return newRows(qr, c.convert), nil
}

type stmt struct {
	c     *conn
	query string
}

func (s *stmt) Close() error {
	return nil
}

func (s *stmt) NumInput() int {
	// -1 = Golang sql won't sanity check argument counts before Exec or Query.
	return -1
}

func (s *stmt) Exec(args []driver.Value) (driver.Result, error) {
	return s.c.Exec(s.query, args)
}

func (s *stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
	return s.c.ExecContext(ctx, s.query, args)
}

func (s *stmt) Query(args []driver.Value) (driver.Rows, error) {
	return s.c.Query(s.query, args)
}

func (s *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
	return s.c.QueryContext(ctx, s.query, args)
}

type result struct {
	insertid, rowsaffected int64
}

func (r result) LastInsertId() (int64, error) {
	return r.insertid, nil
}

func (r result) RowsAffected() (int64, error) {
	return r.rowsaffected, nil
}
<commit_msg>Add driver.Pinger implementation to vitessdriver<commit_after>/*
Copyright 2019 The Vitess Authors.

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

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

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

package vitessdriver

import (
	"context"
	"database/sql"
	"database/sql/driver"
	"encoding/json"
	"errors"

	"google.golang.org/grpc"

	"vitess.io/vitess/go/vt/vtgate/grpcvtgateconn"
	"vitess.io/vitess/go/vt/vtgate/vtgateconn"
)

var (
	errNoIntermixing        = errors.New("named and positional arguments intermixing disallowed")
	errIsolationUnsupported = errors.New("isolation levels are not supported")
)

// Type-check interfaces.
var (
	_ driver.QueryerContext   = &conn{}
	_ driver.ExecerContext    = &conn{}
	_ driver.StmtQueryContext = &stmt{}
	_ driver.StmtExecContext  = &stmt{}
)

func init() {
	sql.Register("vitess", drv{})
}

// Open is a Vitess helper function for sql.Open().
//
// It opens a database connection to vtgate running at "address".
func Open(address, target string) (*sql.DB, error) {
	c := Configuration{
		Address: address,
		Target:  target,
	}
	return OpenWithConfiguration(c)
}

// OpenForStreaming is the same as Open() but uses streaming RPCs to retrieve
// the results.
//
// The streaming mode is recommended for large results.
func OpenForStreaming(address, target string) (*sql.DB, error) {
	c := Configuration{
		Address:   address,
		Target:    target,
		Streaming: true,
	}
	return OpenWithConfiguration(c)
}

// OpenWithConfiguration is the generic Vitess helper function for sql.Open().
//
// It allows to pass in a Configuration struct to control all possible
// settings of the Vitess Go SQL driver.
func OpenWithConfiguration(c Configuration) (*sql.DB, error) {
	c.setDefaults()

	json, err := c.toJSON()
	if err != nil {
		return nil, err
	}

	if len(c.GRPCDialOptions) != 0 {
		vtgateconn.RegisterDialer(c.Protocol, grpcvtgateconn.DialWithOpts(context.TODO(), c.GRPCDialOptions...))
	}

	return sql.Open(c.DriverName, json)
}

type drv struct {
}

// Open implements the database/sql/driver.Driver interface.
//
// For "name", the Vitess driver requires that a JSON object is passed in.
//
// Instead of using this call and passing in a hand-crafted JSON string, it's
// recommended to use the public Vitess helper functions like
// Open(), OpenShard() or OpenWithConfiguration() instead. These will generate
// the required JSON string behind the scenes for you.
//
// Example for a JSON string:
//
//   {"protocol": "grpc", "address": "localhost:1111", "target": "@master"}
//
// For a description of the available fields, see the Configuration struct.
func (d drv) Open(name string) (driver.Conn, error) {
	c := &conn{}
	err := json.Unmarshal([]byte(name), c)
	if err != nil {
		return nil, err
	}

	c.setDefaults()

	if c.convert, err = newConverter(&c.Configuration); err != nil {
		return nil, err
	}

	if err = c.dial(); err != nil {
		return nil, err
	}

	return c, nil
}

// Configuration holds all Vitess driver settings.
//
// Fields with documented default values do not have to be set explicitly.
type Configuration struct {
	// Protocol is the name of the vtgate RPC client implementation.
	// Note: In open-source "grpc" is the recommended implementation.
	//
	// Default: "grpc"
	Protocol string

	// Address must point to a vtgate instance.
	//
	// Format: hostname:port
	Address string

	// Target specifies the default target.
	Target string

	// Streaming is true when streaming RPCs are used.
	// Recommended for large results.
	// Default: false
	Streaming bool

	// DefaultLocation is the timezone string that will be used
	// when converting DATETIME and DATE into time.Time.
	// This setting has no effect if ConvertDatetime is not set.
	// Default: UTC
	DefaultLocation string

	// GRPCDialOptions registers a new vtgateconn dialer with these dial options using the
	// protocol as the key. This may overwrite the default grpcvtgateconn dial option
	// if a custom one hasn't been specified in the config.
	//
	// Default: none
	GRPCDialOptions []grpc.DialOption `json:"-"`

	// Driver is the name registered with the database/sql package. This override
	// is here in case you have wrapped the driver for stats or other interceptors.
	//
	// Default: "vitess"
	DriverName string `json:"-"`
}

// toJSON converts Configuration to the JSON string which is required by the
// Vitess driver. Default values for empty fields will be set.
func (c Configuration) toJSON() (string, error) {
	jsonBytes, err := json.Marshal(c)
	if err != nil {
		return "", err
	}
	return string(jsonBytes), nil
}

// setDefaults sets the default values for empty fields.
func (c *Configuration) setDefaults() {
	// if no protocol is provided default to grpc so the driver is in control
	// of the connection protocol and not the flag vtgateconn.VtgateProtocol
	if c.Protocol == "" {
		c.Protocol = "grpc"
	}

	if c.DriverName == "" {
		c.DriverName = "vitess"
	}
}

type conn struct {
	Configuration
	convert *converter
	conn    *vtgateconn.VTGateConn
	session *vtgateconn.VTGateSession
}

func (c *conn) dial() error {
	var err error
	c.conn, err = vtgateconn.DialProtocol(context.Background(), c.Protocol, c.Address)
	if err != nil {
		return err
	}
	c.session = c.conn.Session(c.Target, nil)
	return nil
}

func (c *conn) Ping(ctx context.Context) error {
	if c.Streaming {
		return errors.New("Ping not allowed for streaming connections")
	}

	_, err := c.ExecContext(ctx, "select 1", nil)
	return err
}

func (c *conn) Prepare(query string) (driver.Stmt, error) {
	return &stmt{c: c, query: query}, nil
}

func (c *conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
	return c.Prepare(query)
}

func (c *conn) Close() error {
	c.conn.Close()
	return nil
}

func (c *conn) Begin() (driver.Tx, error) {
	if _, err := c.Exec("begin", nil); err != nil {
		return nil, err
	}
	return c, nil
}

func (c *conn) BeginTx(_ context.Context, opts driver.TxOptions) (driver.Tx, error) {
	// We don't use the context. The function signature accepts the context
	// to signal to the driver that it's allowed to call Rollback on Cancel.
	if opts.Isolation != driver.IsolationLevel(0) || opts.ReadOnly {
		return nil, errIsolationUnsupported
	}
	return c.Begin()
}

func (c *conn) Commit() error {
	_, err := c.Exec("commit", nil)
	return err
}

func (c *conn) Rollback() error {
	_, err := c.Exec("rollback", nil)
	return err
}

func (c *conn) Exec(query string, args []driver.Value) (driver.Result, error) {
	ctx := context.TODO()

	if c.Streaming {
		return nil, errors.New("Exec not allowed for streaming connections")
	}
	bindVars, err := c.convert.buildBindVars(args)
	if err != nil {
		return nil, err
	}

	qr, err := c.session.Execute(ctx, query, bindVars)
	if err != nil {
		return nil, err
	}
	return result{int64(qr.InsertID), int64(qr.RowsAffected)}, nil
}

func (c *conn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
	if c.Streaming {
		return nil, errors.New("Exec not allowed for streaming connections")
	}

	bv, err := c.convert.bindVarsFromNamedValues(args)
	if err != nil {
		return nil, err
	}
	qr, err := c.session.Execute(ctx, query, bv)
	if err != nil {
		return nil, err
	}
	return result{int64(qr.InsertID), int64(qr.RowsAffected)}, nil
}

func (c *conn) Query(query string, args []driver.Value) (driver.Rows, error) {
	ctx := context.TODO()
	bindVars, err := c.convert.buildBindVars(args)
	if err != nil {
		return nil, err
	}

	if c.Streaming {
		stream, err := c.session.StreamExecute(ctx, query, bindVars)
		if err != nil {
			return nil, err
		}
		return newStreamingRows(stream, c.convert), nil
	}

	qr, err := c.session.Execute(ctx, query, bindVars)
	if err != nil {
		return nil, err
	}
	return newRows(qr, c.convert), nil
}

func (c *conn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
	bv, err := c.convert.bindVarsFromNamedValues(args)
	if err != nil {
		return nil, err
	}

	if c.Streaming {
		stream, err := c.session.StreamExecute(ctx, query, bv)
		if err != nil {
			return nil, err
		}
		return newStreamingRows(stream, c.convert), nil
	}

	qr, err := c.session.Execute(ctx, query, bv)
	if err != nil {
		return nil, err
	}
	return newRows(qr, c.convert), nil
}

type stmt struct {
	c     *conn
	query string
}

func (s *stmt) Close() error {
	return nil
}

func (s *stmt) NumInput() int {
	// -1 = Golang sql won't sanity check argument counts before Exec or Query.
	return -1
}

func (s *stmt) Exec(args []driver.Value) (driver.Result, error) {
	return s.c.Exec(s.query, args)
}

func (s *stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
	return s.c.ExecContext(ctx, s.query, args)
}

func (s *stmt) Query(args []driver.Value) (driver.Rows, error) {
	return s.c.Query(s.query, args)
}

func (s *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
	return s.c.QueryContext(ctx, s.query, args)
}

type result struct {
	insertid, rowsaffected int64
}

func (r result) LastInsertId() (int64, error) {
	return r.insertid, nil
}

func (r result) RowsAffected() (int64, error) {
	return r.rowsaffected, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Vitess Authors.

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

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

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

package ghost

import (
	"crypto/rand"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"io"
	"os/exec"

	"vitess.io/vitess/go/vt/log"
)

// execCmd searches the PATH for a command and runs it, logging the output.
// If input is not nil, pipe it to the command's stdin.
func execCmd(name string, args, env []string, dir string, input io.Reader, output io.Writer) (cmd *exec.Cmd, err error) {
	cmdPath, err := exec.LookPath(name)
	if err != nil {
		return cmd, err
	}
	log.Infof("execCmd: %v %v %v", name, cmdPath, args)

	cmd = exec.Command(cmdPath, args...)
	cmd.Env = env
	cmd.Dir = dir
	if input != nil {
		cmd.Stdin = input
	}
	if output != nil {
		cmd.Stdout = output
		cmd.Stderr = output
	}
	err = cmd.Run()
	if err != nil {
		err = fmt.Errorf("execCmd failed: %v, %v", name, err)
		log.Errorf(err.Error())
	}
	log.Infof("execCmd success: %v", name)
	return cmd, err
}

// RandomHash returns a 64 hex character random string
func RandomHash() string {
	size := 64
	rb := make([]byte, size)
	_, _ = rand.Read(rb)

	hasher := sha256.New()
	hasher.Write(rb)
	return hex.EncodeToString(hasher.Sum(nil))
}

// ShortRandomHash returns a 8 hex character random string
func ShortRandomHash() string {
	return RandomHash()[0:8]
}
<commit_msg>support crearin tempdir and file<commit_after>/*
Copyright 2019 The Vitess Authors.

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

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

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

package ghost

import (
	"crypto/rand"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"io"
	"io/ioutil"
	"os/exec"
	"path/filepath"

	"vitess.io/vitess/go/vt/log"
)

// execCmd searches the PATH for a command and runs it, logging the output.
// If input is not nil, pipe it to the command's stdin.
func execCmd(name string, args, env []string, dir string, input io.Reader, output io.Writer) (cmd *exec.Cmd, err error) {
	cmdPath, err := exec.LookPath(name)
	if err != nil {
		return cmd, err
	}
	log.Infof("execCmd: %v %v %v", name, cmdPath, args)

	cmd = exec.Command(cmdPath, args...)
	cmd.Env = env
	cmd.Dir = dir
	if input != nil {
		cmd.Stdin = input
	}
	if output != nil {
		cmd.Stdout = output
		cmd.Stderr = output
	}
	err = cmd.Run()
	if err != nil {
		err = fmt.Errorf("execCmd failed: %v, %v", name, err)
		log.Errorf(err.Error())
	}
	log.Infof("execCmd success: %v", name)
	return cmd, err
}

// createTempDir creates a temporary directory and returns its name
func createTempDir() (dirName string, err error) {
	return ioutil.TempDir("", "gh-ost-*")
}

// createTempFile creates a file in given directory and with given text as content.
func createTempFile(dirName, fileName, text string) (fullName string, err error) {
	fullName = filepath.Join(dirName, fileName)
	bytes := []byte(text)
	err = ioutil.WriteFile(fullName, bytes, 0644)
	return fullName, err
}

// RandomHash returns a 64 hex character random string
func RandomHash() string {
	size := 64
	rb := make([]byte, size)
	_, _ = rand.Read(rb)

	hasher := sha256.New()
	hasher.Write(rb)
	return hex.EncodeToString(hasher.Sum(nil))
}

// ShortRandomHash returns a 8 hex character random string
func ShortRandomHash() string {
	return RandomHash()[0:8]
}
<|endoftext|>