<commit_before>// Copyright 2018 The Kubeflow 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
//
// https://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 server

import (
	"encoding/json"
	"fmt"

	"github.com/golang/protobuf/ptypes/timestamp"
	api "github.com/kubeflow/pipelines/backend/api/v1beta1/go_client"
	"github.com/kubeflow/pipelines/backend/src/apiserver/common"
	"github.com/kubeflow/pipelines/backend/src/apiserver/model"
	"github.com/kubeflow/pipelines/backend/src/common/util"
	"google.golang.org/protobuf/types/known/structpb"
)

func ToApiExperiment(experiment *model.Experiment) *api.Experiment {
	resourceReferences := []*api.ResourceReference(nil)
	if common.IsMultiUserMode() {
		resourceReferences = []*api.ResourceReference{
			{
				Key: &api.ResourceKey{
					Type: api.ResourceType_NAMESPACE,
					Id:   experiment.Namespace,
				},
				Relationship: api.Relationship_OWNER,
			},
		}
	}
	return &api.Experiment{
		Id:                 experiment.UUID,
		Name:               experiment.Name,
		Description:        experiment.Description,
		CreatedAt:          &timestamp.Timestamp{Seconds: experiment.CreatedAtInSec},
		ResourceReferences: resourceReferences,
		StorageState:       api.Experiment_StorageState(api.Experiment_StorageState_value[experiment.StorageState]),
	}
}

func ToApiExperiments(experiments []*model.Experiment) []*api.Experiment {
	apiExperiments := make([]*api.Experiment, 0)
	for _, experiment := range experiments {
		apiExperiments = append(apiExperiments, ToApiExperiment(experiment))
	}
	return apiExperiments
}

func ToApiPipeline(pipeline *model.Pipeline) *api.Pipeline {
	params, err := toApiParameters(pipeline.Parameters)
	if err != nil {
		return &api.Pipeline{
			Id:    pipeline.UUID,
			Error: err.Error(),
		}
	}

	defaultVersion, err := ToApiPipelineVersion(pipeline.DefaultVersion)
	if err != nil {
		return &api.Pipeline{
			Id:    pipeline.UUID,
			Error: err.Error(),
		}
	}

	return &api.Pipeline{
		Id:             pipeline.UUID,
		CreatedAt:      &timestamp.Timestamp{Seconds: pipeline.CreatedAtInSec},
		Name:           pipeline.Name,
		Description:    pipeline.Description,
		Parameters:     params,
		DefaultVersion: defaultVersion,
	}
}

func ToApiPipelineVersion(version *model.PipelineVersion) (*api.PipelineVersion, error) {
	if version == nil {
		return nil, nil
	}
	params, err := toApiParameters(version.Parameters)
	if err != nil {
		return nil, err
	}

	return &api.PipelineVersion{
		Id:            version.UUID,
		Name:          version.Name,
		CreatedAt:     &timestamp.Timestamp{Seconds: version.CreatedAtInSec},
		Parameters:    params,
		Description:   version.Description,
		CodeSourceUrl: version.CodeSourceUrl,
		ResourceReferences: []*api.ResourceReference{
			{
				Key: &api.ResourceKey{
					Id:   version.PipelineId,
					Type: api.ResourceType_PIPELINE,
				},
				Relationship: api.Relationship_OWNER,
			},
		},
	}, nil
}

func ToApiPipelineVersions(versions []*model.PipelineVersion) ([]*api.PipelineVersion, error) {
	apiVersions := make([]*api.PipelineVersion, 0)
	for _, version := range versions {
		v, _ := ToApiPipelineVersion(version)
		apiVersions = append(apiVersions, v)
	}
	return apiVersions, nil
}

func ToApiPipelines(pipelines []*model.Pipeline) []*api.Pipeline {
	apiPipelines := make([]*api.Pipeline, 0)
	for _, pipeline := range pipelines {
		apiPipelines = append(apiPipelines, ToApiPipeline(pipeline))
	}
	return apiPipelines
}

func toApiParameters(paramsString string) ([]*api.Parameter, error) {
	if paramsString == "" {
		return nil, nil
	}
	params, err := util.UnmarshalParameters(util.ArgoWorkflow, paramsString)
	if err != nil {
		return nil, util.NewInternalServerError(err, "Parameter with wrong format is stored")
	}
	apiParams := make([]*api.Parameter, 0)
	for _, param := range params {
		var value string
		if param.Value != nil {
			value = *param.Value
		}
		apiParam := api.Parameter{
			Name:  param.Name,
			Value: value,
		}
		apiParams = append(apiParams, &apiParam)
	}
	return apiParams, nil
}

func toApiRuntimeConfig(modelRuntime model.RuntimeConfig) (*api.PipelineSpec_RuntimeConfig, error) {
	if modelRuntime.Parameters == "" && modelRuntime.PipelineRoot == "" {
		return nil, nil
	}
	var runtimeParams map[string]*structpb.Value
	if modelRuntime.Parameters != "" {
		err := json.Unmarshal([]byte(modelRuntime.Parameters), &runtimeParams)
		if err != nil {
			return nil, util.NewInternalServerError(err, fmt.Sprintf("Cannot unmarshal RuntimeConfig Parameter to map[string]*structpb.Value, string value: %+v", modelRuntime.Parameters))
		}
	}
	apiRuntimeConfig := &api.PipelineSpec_RuntimeConfig{
		Parameters:   runtimeParams,
		PipelineRoot: modelRuntime.PipelineRoot,
	}
	return apiRuntimeConfig, nil
}

func toApiRun(run *model.Run) *api.Run {
	// v1 parameters
	params, err := toApiParameters(run.Parameters)
	if err != nil {
		return &api.Run{
			Id:    run.UUID,
			Error: err.Error(),
		}
	}
	// v2 RuntimeConfig
	runtimeConfig, err := toApiRuntimeConfig(run.PipelineSpec.RuntimeConfig)
	if err != nil {
		return &api.Run{
			Id:    run.UUID,
			Error: err.Error(),
		}
	}
	var metrics []*api.RunMetric
	if run.Metrics != nil {
		for _, metric := range run.Metrics {
			metrics = append(metrics, ToApiRunMetric(metric))
		}
	}
	return &api.Run{
		CreatedAt:      &timestamp.Timestamp{Seconds: run.CreatedAtInSec},
		Id:             run.UUID,
		Metrics:        metrics,
		Name:           run.DisplayName,
		ServiceAccount: run.ServiceAccount,
		StorageState:   api.Run_StorageState(api.Run_StorageState_value[run.StorageState]),
		Description:    run.Description,
		ScheduledAt:    &timestamp.Timestamp{Seconds: run.ScheduledAtInSec},
		FinishedAt:     &timestamp.Timestamp{Seconds: run.FinishedAtInSec},
		Status:         run.Conditions,
		PipelineSpec: &api.PipelineSpec{
			PipelineId:       run.PipelineId,
			PipelineName:     run.PipelineName,
			WorkflowManifest: run.WorkflowSpecManifest,
			PipelineManifest: run.PipelineSpecManifest,
			Parameters:       params,
			RuntimeConfig:    runtimeConfig,
		},
		ResourceReferences: toApiResourceReferences(run.ResourceReferences),
	}
}

func ToApiRuns(runs []*model.Run) []*api.Run {
	apiRuns := make([]*api.Run, 0)
	for _, run := range runs {
		apiRuns = append(apiRuns, toApiRun(run))
	}
	return apiRuns
}

func ToApiRunDetail(run *model.RunDetail) *api.RunDetail {
	return &api.RunDetail{
		Run: toApiRun(&run.Run),
		PipelineRuntime: &api.PipelineRuntime{
			WorkflowManifest: run.WorkflowRuntimeManifest,
			PipelineManifest: run.PipelineRuntimeManifest,
		},
	}
}

func ToApiTask(task *model.Task) *api.Task {
	return &api.Task{
		Id:              task.UUID,
		Namespace:       task.Namespace,
		PipelineName:    task.PipelineName,
		RunId:           task.RunUUID,
		MlmdExecutionID: task.MLMDExecutionID,
		CreatedAt:       &timestamp.Timestamp{Seconds: task.CreatedTimestamp},
		FinishedAt:      &timestamp.Timestamp{Seconds: task.FinishedTimestamp},
		Fingerprint:     task.Fingerprint,
	}
}

func ToApiTasks(tasks []*model.Task) []*api.Task {
	apiTasks := make([]*api.Task, 0)
	for _, task := range tasks {
		apiTasks = append(apiTasks, ToApiTask(task))
	}
	return apiTasks
}
func ToApiJob(job *model.Job) *api.Job {
	// v1 parameters
	params, err := toApiParameters(job.Parameters)
	if err != nil {
		return &api.Job{
			Id:    job.UUID,
			Error: err.Error(),
		}
	}
	// v2 RuntimeConfig
	runtimeConfig, err := toApiRuntimeConfig(job.PipelineSpec.RuntimeConfig)
	if err != nil {
		return &api.Job{
			Id:    job.UUID,
			Error: err.Error(),
		}
	}
	return &api.Job{
		Id:             job.UUID,
		Name:           job.DisplayName,
		ServiceAccount: job.ServiceAccount,
		Description:    job.Description,
		Enabled:        job.Enabled,
		CreatedAt:      &timestamp.Timestamp{Seconds: job.CreatedAtInSec},
		UpdatedAt:      &timestamp.Timestamp{Seconds: job.UpdatedAtInSec},
		Status:         job.Conditions,
		MaxConcurrency: job.MaxConcurrency,
		NoCatchup:      job.NoCatchup,
		Trigger:        toApiTrigger(job.Trigger),
		PipelineSpec: &api.PipelineSpec{
			PipelineId:       job.PipelineId,
			PipelineName:     job.PipelineName,
			WorkflowManifest: job.WorkflowSpecManifest,
			PipelineManifest: job.PipelineSpecManifest,
			Parameters:       params,
			RuntimeConfig:    runtimeConfig,
		},
		ResourceReferences: toApiResourceReferences(job.ResourceReferences),
	}
}

func ToApiJobs(jobs []*model.Job) []*api.Job {
	apiJobs := make([]*api.Job, 0)
	for _, job := range jobs {
		apiJobs = append(apiJobs, ToApiJob(job))
	}
	return apiJobs
}

func ToApiRunMetric(metric *model.RunMetric) *api.RunMetric {
	return &api.RunMetric{
		Name:   metric.Name,
		NodeId: metric.NodeID,
		Value: &api.RunMetric_NumberValue{
			NumberValue: metric.NumberValue,
		},
		Format: api.RunMetric_Format(api.RunMetric_Format_value[metric.Format]),
	}
}

func toApiResourceReferences(references []*model.ResourceReference) []*api.ResourceReference {
	var apiReferences []*api.ResourceReference
	for _, ref := range references {
		apiReferences = append(apiReferences, &api.ResourceReference{
			Key: &api.ResourceKey{
				Type: toApiResourceType(ref.ReferenceType),
				Id:   ref.ReferenceUUID,
			},
			Name:         ref.ReferenceName,
			Relationship: toApiRelationship(ref.Relationship),
		})
	}
	return apiReferences
}

func toApiResourceType(modelType model.ResourceType) api.ResourceType {
	switch modelType {
	case common.Experiment:
		return api.ResourceType_EXPERIMENT
	case common.Job:
		return api.ResourceType_JOB
	case common.PipelineVersion:
		return api.ResourceType_PIPELINE_VERSION
	case common.Namespace:
		return api.ResourceType_NAMESPACE
	default:
		return api.ResourceType_UNKNOWN_RESOURCE_TYPE
	}
}

func toApiRelationship(r model.Relationship) api.Relationship {
	switch r {
	case common.Creator:
		return api.Relationship_CREATOR
	case common.Owner:
		return api.Relationship_OWNER
	default:
		return api.Relationship_UNKNOWN_RELATIONSHIP
	}
}

func toApiTrigger(trigger model.Trigger) *api.Trigger {
	if trigger.Cron != nil && *trigger.Cron != "" {
		var cronSchedule api.CronSchedule
		cronSchedule.Cron = *trigger.Cron
		if trigger.CronScheduleStartTimeInSec != nil {
			cronSchedule.StartTime = &timestamp.Timestamp{
				Seconds: *trigger.CronScheduleStartTimeInSec}
		}
		if trigger.CronScheduleEndTimeInSec != nil {
			cronSchedule.EndTime = &timestamp.Timestamp{
				Seconds: *trigger.CronScheduleEndTimeInSec}
		}
		return &api.Trigger{Trigger: &api.Trigger_CronSchedule{CronSchedule: &cronSchedule}}
	}

	if trigger.IntervalSecond != nil && *trigger.IntervalSecond != 0 {
		var periodicSchedule api.PeriodicSchedule
		periodicSchedule.IntervalSecond = *trigger.IntervalSecond
		if trigger.PeriodicScheduleStartTimeInSec != nil {
			periodicSchedule.StartTime = &timestamp.Timestamp{
				Seconds: *trigger.PeriodicScheduleStartTimeInSec}
		}
		if trigger.PeriodicScheduleEndTimeInSec != nil {
			periodicSchedule.EndTime = &timestamp.Timestamp{
				Seconds: *trigger.PeriodicScheduleEndTimeInSec}
		}
		return &api.Trigger{Trigger: &api.Trigger_PeriodicSchedule{PeriodicSchedule: &periodicSchedule}}
	}
	return &api.Trigger{}
}
<commit_msg>feat(backend): Include namespace in Pipeline API model. Part of #4197 (#8375)<commit_after>// Copyright 2018 The Kubeflow 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
//
// https://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 server

import (
	"encoding/json"
	"fmt"

	"github.com/golang/protobuf/ptypes/timestamp"
	api "github.com/kubeflow/pipelines/backend/api/v1beta1/go_client"
	"github.com/kubeflow/pipelines/backend/src/apiserver/common"
	"github.com/kubeflow/pipelines/backend/src/apiserver/model"
	"github.com/kubeflow/pipelines/backend/src/common/util"
	"google.golang.org/protobuf/types/known/structpb"
)

func ToApiExperiment(experiment *model.Experiment) *api.Experiment {
	resourceReferences := []*api.ResourceReference(nil)
	if common.IsMultiUserMode() {
		resourceReferences = []*api.ResourceReference{
			{
				Key: &api.ResourceKey{
					Type: api.ResourceType_NAMESPACE,
					Id:   experiment.Namespace,
				},
				Relationship: api.Relationship_OWNER,
			},
		}
	}
	return &api.Experiment{
		Id:                 experiment.UUID,
		Name:               experiment.Name,
		Description:        experiment.Description,
		CreatedAt:          &timestamp.Timestamp{Seconds: experiment.CreatedAtInSec},
		ResourceReferences: resourceReferences,
		StorageState:       api.Experiment_StorageState(api.Experiment_StorageState_value[experiment.StorageState]),
	}
}

func ToApiExperiments(experiments []*model.Experiment) []*api.Experiment {
	apiExperiments := make([]*api.Experiment, 0)
	for _, experiment := range experiments {
		apiExperiments = append(apiExperiments, ToApiExperiment(experiment))
	}
	return apiExperiments
}

func ToApiPipeline(pipeline *model.Pipeline) *api.Pipeline {
	params, err := toApiParameters(pipeline.Parameters)
	if err != nil {
		return &api.Pipeline{
			Id:    pipeline.UUID,
			Error: err.Error(),
		}
	}

	defaultVersion, err := ToApiPipelineVersion(pipeline.DefaultVersion)
	if err != nil {
		return &api.Pipeline{
			Id:    pipeline.UUID,
			Error: err.Error(),
		}
	}

	var resourceRefs []*api.ResourceReference
	if len(pipeline.Namespace) > 0 {
		resourceRefs = []*api.ResourceReference{
			{
				Key: &api.ResourceKey{
					Type: api.ResourceType_NAMESPACE,
					Id:   pipeline.Namespace,
				},
				Relationship: api.Relationship_OWNER,
			},
		}
	}

	return &api.Pipeline{
		Id:                 pipeline.UUID,
		CreatedAt:          &timestamp.Timestamp{Seconds: pipeline.CreatedAtInSec},
		Name:               pipeline.Name,
		Description:        pipeline.Description,
		Parameters:         params,
		DefaultVersion:     defaultVersion,
		ResourceReferences: resourceRefs,
	}
}

func ToApiPipelineVersion(version *model.PipelineVersion) (*api.PipelineVersion, error) {
	if version == nil {
		return nil, nil
	}
	params, err := toApiParameters(version.Parameters)
	if err != nil {
		return nil, err
	}

	return &api.PipelineVersion{
		Id:            version.UUID,
		Name:          version.Name,
		CreatedAt:     &timestamp.Timestamp{Seconds: version.CreatedAtInSec},
		Parameters:    params,
		Description:   version.Description,
		CodeSourceUrl: version.CodeSourceUrl,
		ResourceReferences: []*api.ResourceReference{
			{
				Key: &api.ResourceKey{
					Id:   version.PipelineId,
					Type: api.ResourceType_PIPELINE,
				},
				Relationship: api.Relationship_OWNER,
			},
		},
	}, nil
}

func ToApiPipelineVersions(versions []*model.PipelineVersion) ([]*api.PipelineVersion, error) {
	apiVersions := make([]*api.PipelineVersion, 0)
	for _, version := range versions {
		v, _ := ToApiPipelineVersion(version)
		apiVersions = append(apiVersions, v)
	}
	return apiVersions, nil
}

func ToApiPipelines(pipelines []*model.Pipeline) []*api.Pipeline {
	apiPipelines := make([]*api.Pipeline, 0)
	for _, pipeline := range pipelines {
		apiPipelines = append(apiPipelines, ToApiPipeline(pipeline))
	}
	return apiPipelines
}

func toApiParameters(paramsString string) ([]*api.Parameter, error) {
	if paramsString == "" {
		return nil, nil
	}
	params, err := util.UnmarshalParameters(util.ArgoWorkflow, paramsString)
	if err != nil {
		return nil, util.NewInternalServerError(err, "Parameter with wrong format is stored")
	}
	apiParams := make([]*api.Parameter, 0)
	for _, param := range params {
		var value string
		if param.Value != nil {
			value = *param.Value
		}
		apiParam := api.Parameter{
			Name:  param.Name,
			Value: value,
		}
		apiParams = append(apiParams, &apiParam)
	}
	return apiParams, nil
}

func toApiRuntimeConfig(modelRuntime model.RuntimeConfig) (*api.PipelineSpec_RuntimeConfig, error) {
	if modelRuntime.Parameters == "" && modelRuntime.PipelineRoot == "" {
		return nil, nil
	}
	var runtimeParams map[string]*structpb.Value
	if modelRuntime.Parameters != "" {
		err := json.Unmarshal([]byte(modelRuntime.Parameters), &runtimeParams)
		if err != nil {
			return nil, util.NewInternalServerError(err, fmt.Sprintf("Cannot unmarshal RuntimeConfig Parameter to map[string]*structpb.Value, string value: %+v", modelRuntime.Parameters))
		}
	}
	apiRuntimeConfig := &api.PipelineSpec_RuntimeConfig{
		Parameters:   runtimeParams,
		PipelineRoot: modelRuntime.PipelineRoot,
	}
	return apiRuntimeConfig, nil
}

func toApiRun(run *model.Run) *api.Run {
	// v1 parameters
	params, err := toApiParameters(run.Parameters)
	if err != nil {
		return &api.Run{
			Id:    run.UUID,
			Error: err.Error(),
		}
	}
	// v2 RuntimeConfig
	runtimeConfig, err := toApiRuntimeConfig(run.PipelineSpec.RuntimeConfig)
	if err != nil {
		return &api.Run{
			Id:    run.UUID,
			Error: err.Error(),
		}
	}
	var metrics []*api.RunMetric
	if run.Metrics != nil {
		for _, metric := range run.Metrics {
			metrics = append(metrics, ToApiRunMetric(metric))
		}
	}
	return &api.Run{
		CreatedAt:      &timestamp.Timestamp{Seconds: run.CreatedAtInSec},
		Id:             run.UUID,
		Metrics:        metrics,
		Name:           run.DisplayName,
		ServiceAccount: run.ServiceAccount,
		StorageState:   api.Run_StorageState(api.Run_StorageState_value[run.StorageState]),
		Description:    run.Description,
		ScheduledAt:    &timestamp.Timestamp{Seconds: run.ScheduledAtInSec},
		FinishedAt:     &timestamp.Timestamp{Seconds: run.FinishedAtInSec},
		Status:         run.Conditions,
		PipelineSpec: &api.PipelineSpec{
			PipelineId:       run.PipelineId,
			PipelineName:     run.PipelineName,
			WorkflowManifest: run.WorkflowSpecManifest,
			PipelineManifest: run.PipelineSpecManifest,
			Parameters:       params,
			RuntimeConfig:    runtimeConfig,
		},
		ResourceReferences: toApiResourceReferences(run.ResourceReferences),
	}
}

func ToApiRuns(runs []*model.Run) []*api.Run {
	apiRuns := make([]*api.Run, 0)
	for _, run := range runs {
		apiRuns = append(apiRuns, toApiRun(run))
	}
	return apiRuns
}

func ToApiRunDetail(run *model.RunDetail) *api.RunDetail {
	return &api.RunDetail{
		Run: toApiRun(&run.Run),
		PipelineRuntime: &api.PipelineRuntime{
			WorkflowManifest: run.WorkflowRuntimeManifest,
			PipelineManifest: run.PipelineRuntimeManifest,
		},
	}
}

func ToApiTask(task *model.Task) *api.Task {
	return &api.Task{
		Id:              task.UUID,
		Namespace:       task.Namespace,
		PipelineName:    task.PipelineName,
		RunId:           task.RunUUID,
		MlmdExecutionID: task.MLMDExecutionID,
		CreatedAt:       &timestamp.Timestamp{Seconds: task.CreatedTimestamp},
		FinishedAt:      &timestamp.Timestamp{Seconds: task.FinishedTimestamp},
		Fingerprint:     task.Fingerprint,
	}
}

func ToApiTasks(tasks []*model.Task) []*api.Task {
	apiTasks := make([]*api.Task, 0)
	for _, task := range tasks {
		apiTasks = append(apiTasks, ToApiTask(task))
	}
	return apiTasks
}
func ToApiJob(job *model.Job) *api.Job {
	// v1 parameters
	params, err := toApiParameters(job.Parameters)
	if err != nil {
		return &api.Job{
			Id:    job.UUID,
			Error: err.Error(),
		}
	}
	// v2 RuntimeConfig
	runtimeConfig, err := toApiRuntimeConfig(job.PipelineSpec.RuntimeConfig)
	if err != nil {
		return &api.Job{
			Id:    job.UUID,
			Error: err.Error(),
		}
	}
	return &api.Job{
		Id:             job.UUID,
		Name:           job.DisplayName,
		ServiceAccount: job.ServiceAccount,
		Description:    job.Description,
		Enabled:        job.Enabled,
		CreatedAt:      &timestamp.Timestamp{Seconds: job.CreatedAtInSec},
		UpdatedAt:      &timestamp.Timestamp{Seconds: job.UpdatedAtInSec},
		Status:         job.Conditions,
		MaxConcurrency: job.MaxConcurrency,
		NoCatchup:      job.NoCatchup,
		Trigger:        toApiTrigger(job.Trigger),
		PipelineSpec: &api.PipelineSpec{
			PipelineId:       job.PipelineId,
			PipelineName:     job.PipelineName,
			WorkflowManifest: job.WorkflowSpecManifest,
			PipelineManifest: job.PipelineSpecManifest,
			Parameters:       params,
			RuntimeConfig:    runtimeConfig,
		},
		ResourceReferences: toApiResourceReferences(job.ResourceReferences),
	}
}

func ToApiJobs(jobs []*model.Job) []*api.Job {
	apiJobs := make([]*api.Job, 0)
	for _, job := range jobs {
		apiJobs = append(apiJobs, ToApiJob(job))
	}
	return apiJobs
}

func ToApiRunMetric(metric *model.RunMetric) *api.RunMetric {
	return &api.RunMetric{
		Name:   metric.Name,
		NodeId: metric.NodeID,
		Value: &api.RunMetric_NumberValue{
			NumberValue: metric.NumberValue,
		},
		Format: api.RunMetric_Format(api.RunMetric_Format_value[metric.Format]),
	}
}

func toApiResourceReferences(references []*model.ResourceReference) []*api.ResourceReference {
	var apiReferences []*api.ResourceReference
	for _, ref := range references {
		apiReferences = append(apiReferences, &api.ResourceReference{
			Key: &api.ResourceKey{
				Type: toApiResourceType(ref.ReferenceType),
				Id:   ref.ReferenceUUID,
			},
			Name:         ref.ReferenceName,
			Relationship: toApiRelationship(ref.Relationship),
		})
	}
	return apiReferences
}

func toApiResourceType(modelType model.ResourceType) api.ResourceType {
	switch modelType {
	case common.Experiment:
		return api.ResourceType_EXPERIMENT
	case common.Job:
		return api.ResourceType_JOB
	case common.PipelineVersion:
		return api.ResourceType_PIPELINE_VERSION
	case common.Namespace:
		return api.ResourceType_NAMESPACE
	default:
		return api.ResourceType_UNKNOWN_RESOURCE_TYPE
	}
}

func toApiRelationship(r model.Relationship) api.Relationship {
	switch r {
	case common.Creator:
		return api.Relationship_CREATOR
	case common.Owner:
		return api.Relationship_OWNER
	default:
		return api.Relationship_UNKNOWN_RELATIONSHIP
	}
}

func toApiTrigger(trigger model.Trigger) *api.Trigger {
	if trigger.Cron != nil && *trigger.Cron != "" {
		var cronSchedule api.CronSchedule
		cronSchedule.Cron = *trigger.Cron
		if trigger.CronScheduleStartTimeInSec != nil {
			cronSchedule.StartTime = &timestamp.Timestamp{
				Seconds: *trigger.CronScheduleStartTimeInSec}
		}
		if trigger.CronScheduleEndTimeInSec != nil {
			cronSchedule.EndTime = &timestamp.Timestamp{
				Seconds: *trigger.CronScheduleEndTimeInSec}
		}
		return &api.Trigger{Trigger: &api.Trigger_CronSchedule{CronSchedule: &cronSchedule}}
	}

	if trigger.IntervalSecond != nil && *trigger.IntervalSecond != 0 {
		var periodicSchedule api.PeriodicSchedule
		periodicSchedule.IntervalSecond = *trigger.IntervalSecond
		if trigger.PeriodicScheduleStartTimeInSec != nil {
			periodicSchedule.StartTime = &timestamp.Timestamp{
				Seconds: *trigger.PeriodicScheduleStartTimeInSec}
		}
		if trigger.PeriodicScheduleEndTimeInSec != nil {
			periodicSchedule.EndTime = &timestamp.Timestamp{
				Seconds: *trigger.PeriodicScheduleEndTimeInSec}
		}
		return &api.Trigger{Trigger: &api.Trigger_PeriodicSchedule{PeriodicSchedule: &periodicSchedule}}
	}
	return &api.Trigger{}
}
<|endoftext|>


<commit_before>package driver

import (
	"fmt"
	"log"
	"path/filepath"
	"sync"

	"github.com/hashicorp/nomad/client/allocdir"
	"github.com/hashicorp/nomad/client/config"
	"github.com/hashicorp/nomad/client/driver/env"
	"github.com/hashicorp/nomad/client/fingerprint"
	"github.com/hashicorp/nomad/nomad/structs"

	dstructs "github.com/hashicorp/nomad/client/driver/structs"
	cstructs "github.com/hashicorp/nomad/client/structs"
)

// BuiltinDrivers contains the built in registered drivers
// which are available for allocation handling
var BuiltinDrivers = map[string]Factory{
	"docker":   NewDockerDriver,
	"exec":     NewExecDriver,
	"raw_exec": NewRawExecDriver,
	"java":     NewJavaDriver,
	"qemu":     NewQemuDriver,
	"rkt":      NewRktDriver,
}

// NewDriver is used to instantiate and return a new driver
// given the name and a logger
func NewDriver(name string, ctx *DriverContext) (Driver, error) {
	// Lookup the factory function
	factory, ok := BuiltinDrivers[name]
	if !ok {
		return nil, fmt.Errorf("unknown driver '%s'", name)
	}

	// Instantiate the driver
	f := factory(ctx)
	return f, nil
}

// Factory is used to instantiate a new Driver
type Factory func(*DriverContext) Driver

// Driver is used for execution of tasks. This allows Nomad
// to support many pluggable implementations of task drivers.
// Examples could include LXC, Docker, Qemu, etc.
type Driver interface {
	// Drivers must support the fingerprint interface for detection
	fingerprint.Fingerprint

	// Start is used to being task execution
	Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error)

	// Open is used to re-open a handle to a task
	Open(ctx *ExecContext, handleID string) (DriverHandle, error)

	// Drivers must validate their configuration
	Validate(map[string]interface{}) error
}

// DriverContext is a means to inject dependencies such as loggers, configs, and
// node attributes into a Driver without having to change the Driver interface
// each time we do it. Used in conjection with Factory, above.
type DriverContext struct {
	taskName string
	config   *config.Config
	logger   *log.Logger
	node     *structs.Node
	taskEnv  *env.TaskEnvironment
}

// NewEmptyDriverContext returns a DriverContext with all fields set to their
// zero value.
func NewEmptyDriverContext() *DriverContext {
	return &DriverContext{
		taskName: "",
		config:   nil,
		node:     nil,
		logger:   nil,
		taskEnv:  nil,
	}
}

// NewDriverContext initializes a new DriverContext with the specified fields.
// This enables other packages to create DriverContexts but keeps the fields
// private to the driver. If we want to change this later we can gorename all of
// the fields in DriverContext.
func NewDriverContext(taskName string, config *config.Config, node *structs.Node,
	logger *log.Logger, taskEnv *env.TaskEnvironment) *DriverContext {
	return &DriverContext{
		taskName: taskName,
		config:   config,
		node:     node,
		logger:   logger,
		taskEnv:  taskEnv,
	}
}

// DriverHandle is an opaque handle into a driver used for task
// manipulation
type DriverHandle interface {
	// Returns an opaque handle that can be used to re-open the handle
	ID() string

	// WaitCh is used to return a channel used wait for task completion
	WaitCh() chan *dstructs.WaitResult

	// Update is used to update the task if possible and update task related
	// configurations.
	Update(task *structs.Task) error

	// Kill is used to stop the task
	Kill() error

	// Stats returns aggregated stats of the driver
	Stats() (*cstructs.TaskResourceUsage, error)
}

// ExecContext is shared between drivers within an allocation
type ExecContext struct {
	sync.Mutex

	// AllocDir contains information about the alloc directory structure.
	AllocDir *allocdir.AllocDir

	// Alloc ID
	AllocID string
}

// NewExecContext is used to create a new execution context
func NewExecContext(alloc *allocdir.AllocDir, allocID string) *ExecContext {
	return &ExecContext{AllocDir: alloc, AllocID: allocID}
}

// GetTaskEnv converts the alloc dir, the node, task and alloc into a
// TaskEnvironment.
func GetTaskEnv(allocDir *allocdir.AllocDir, node *structs.Node,
	task *structs.Task, alloc *structs.Allocation) (*env.TaskEnvironment, error) {

	tg := alloc.Job.LookupTaskGroup(alloc.TaskGroup)
	env := env.NewTaskEnvironment(node).
		SetTaskMeta(task.Meta).
		SetTaskGroupMeta(tg.Meta).
		SetJobMeta(alloc.Job.Meta).
		SetEnvvars(task.Env).
		SetTaskName(task.Name)

	if allocDir != nil {
		env.SetAllocDir(allocDir.SharedDir)
		taskdir, ok := allocDir.TaskDirs[task.Name]
		if !ok {
			return nil, fmt.Errorf("failed to get task directory for task %q", task.Name)
		}

		env.SetTaskLocalDir(filepath.Join(taskdir, allocdir.TaskLocal))
	}

	if task.Resources != nil {
		env.SetMemLimit(task.Resources.MemoryMB).
			SetCpuLimit(task.Resources.CPU).
			SetNetworks(task.Resources.Networks)
	}

	if alloc != nil {
		env.SetAlloc(alloc)
	}

	return env.Build(), nil
}

func mapMergeStrInt(maps ...map[string]int) map[string]int {
	out := map[string]int{}
	for _, in := range maps {
		for key, val := range in {
			out[key] = val
		}
	}
	return out
}

func mapMergeStrStr(maps ...map[string]string) map[string]string {
	out := map[string]string{}
	for _, in := range maps {
		for key, val := range in {
			out[key] = val
		}
	}
	return out
}
<commit_msg>Remove unused embedded lock on ExecContext<commit_after>package driver

import (
	"fmt"
	"log"
	"path/filepath"

	"github.com/hashicorp/nomad/client/allocdir"
	"github.com/hashicorp/nomad/client/config"
	"github.com/hashicorp/nomad/client/driver/env"
	"github.com/hashicorp/nomad/client/fingerprint"
	"github.com/hashicorp/nomad/nomad/structs"

	dstructs "github.com/hashicorp/nomad/client/driver/structs"
	cstructs "github.com/hashicorp/nomad/client/structs"
)

// BuiltinDrivers contains the built in registered drivers
// which are available for allocation handling
var BuiltinDrivers = map[string]Factory{
	"docker":   NewDockerDriver,
	"exec":     NewExecDriver,
	"raw_exec": NewRawExecDriver,
	"java":     NewJavaDriver,
	"qemu":     NewQemuDriver,
	"rkt":      NewRktDriver,
}

// NewDriver is used to instantiate and return a new driver
// given the name and a logger
func NewDriver(name string, ctx *DriverContext) (Driver, error) {
	// Lookup the factory function
	factory, ok := BuiltinDrivers[name]
	if !ok {
		return nil, fmt.Errorf("unknown driver '%s'", name)
	}

	// Instantiate the driver
	f := factory(ctx)
	return f, nil
}

// Factory is used to instantiate a new Driver
type Factory func(*DriverContext) Driver

// Driver is used for execution of tasks. This allows Nomad
// to support many pluggable implementations of task drivers.
// Examples could include LXC, Docker, Qemu, etc.
type Driver interface {
	// Drivers must support the fingerprint interface for detection
	fingerprint.Fingerprint

	// Start is used to being task execution
	Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error)

	// Open is used to re-open a handle to a task
	Open(ctx *ExecContext, handleID string) (DriverHandle, error)

	// Drivers must validate their configuration
	Validate(map[string]interface{}) error
}

// DriverContext is a means to inject dependencies such as loggers, configs, and
// node attributes into a Driver without having to change the Driver interface
// each time we do it. Used in conjection with Factory, above.
type DriverContext struct {
	taskName string
	config   *config.Config
	logger   *log.Logger
	node     *structs.Node
	taskEnv  *env.TaskEnvironment
}

// NewEmptyDriverContext returns a DriverContext with all fields set to their
// zero value.
func NewEmptyDriverContext() *DriverContext {
	return &DriverContext{
		taskName: "",
		config:   nil,
		node:     nil,
		logger:   nil,
		taskEnv:  nil,
	}
}

// NewDriverContext initializes a new DriverContext with the specified fields.
// This enables other packages to create DriverContexts but keeps the fields
// private to the driver. If we want to change this later we can gorename all of
// the fields in DriverContext.
func NewDriverContext(taskName string, config *config.Config, node *structs.Node,
	logger *log.Logger, taskEnv *env.TaskEnvironment) *DriverContext {
	return &DriverContext{
		taskName: taskName,
		config:   config,
		node:     node,
		logger:   logger,
		taskEnv:  taskEnv,
	}
}

// DriverHandle is an opaque handle into a driver used for task
// manipulation
type DriverHandle interface {
	// Returns an opaque handle that can be used to re-open the handle
	ID() string

	// WaitCh is used to return a channel used wait for task completion
	WaitCh() chan *dstructs.WaitResult

	// Update is used to update the task if possible and update task related
	// configurations.
	Update(task *structs.Task) error

	// Kill is used to stop the task
	Kill() error

	// Stats returns aggregated stats of the driver
	Stats() (*cstructs.TaskResourceUsage, error)
}

// ExecContext is shared between drivers within an allocation
type ExecContext struct {
	// AllocDir contains information about the alloc directory structure.
	AllocDir *allocdir.AllocDir

	// Alloc ID
	AllocID string
}

// NewExecContext is used to create a new execution context
func NewExecContext(alloc *allocdir.AllocDir, allocID string) *ExecContext {
	return &ExecContext{AllocDir: alloc, AllocID: allocID}
}

// GetTaskEnv converts the alloc dir, the node, task and alloc into a
// TaskEnvironment.
func GetTaskEnv(allocDir *allocdir.AllocDir, node *structs.Node,
	task *structs.Task, alloc *structs.Allocation) (*env.TaskEnvironment, error) {

	tg := alloc.Job.LookupTaskGroup(alloc.TaskGroup)
	env := env.NewTaskEnvironment(node).
		SetTaskMeta(task.Meta).
		SetTaskGroupMeta(tg.Meta).
		SetJobMeta(alloc.Job.Meta).
		SetEnvvars(task.Env).
		SetTaskName(task.Name)

	if allocDir != nil {
		env.SetAllocDir(allocDir.SharedDir)
		taskdir, ok := allocDir.TaskDirs[task.Name]
		if !ok {
			return nil, fmt.Errorf("failed to get task directory for task %q", task.Name)
		}

		env.SetTaskLocalDir(filepath.Join(taskdir, allocdir.TaskLocal))
	}

	if task.Resources != nil {
		env.SetMemLimit(task.Resources.MemoryMB).
			SetCpuLimit(task.Resources.CPU).
			SetNetworks(task.Resources.Networks)
	}

	if alloc != nil {
		env.SetAlloc(alloc)
	}

	return env.Build(), nil
}

func mapMergeStrInt(maps ...map[string]int) map[string]int {
	out := map[string]int{}
	for _, in := range maps {
		for key, val := range in {
			out[key] = val
		}
	}
	return out
}

func mapMergeStrStr(maps ...map[string]string) map[string]string {
	out := map[string]string{}
	for _, in := range maps {
		for key, val := range in {
			out[key] = val
		}
	}
	return out
}
<|endoftext|>


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

package main

import (
	"bytes"
	"encoding/hex"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"io/ioutil"

	"github.com/pkg/errors"
	"github.com/sdboyer/gps"
)

var ensureCmd = &command{
	fn:   runEnsure,
	name: "ensure",
	flag: flag.NewFlagSet("", flag.ExitOnError),
	short: `[flags] <path>[:alt location][@<version specifier>]
	To ensure a dependency is in your project at a specific version (if specified).
	`,
	long: `
	Run it when
To ensure a new dependency is in your project.
To ensure a dependency is updated.
To the latest version that satisfies constraints.
To a specific version or different constraint.
(With no arguments) To ensure that you have all the dependencies specified by your Manifest + lockfile.

What it does
Download code, placing in the vendor/ directory of the project. Only the packages that are actually used by the current project and its dependencies are included.
Any authentication, proxy settings, or other parameters regarding communicating with external repositories is the responsibility of the underlying VCS tools.
Resolve version constraints
If the set of constraints are not solvable, print an error
Collapse any vendor folders in the downloaded code and its transient deps to the root.
Includes dependencies required by the current project’s tests. There are arguments both for and against including the deps of tests for any transitive deps. Defer on deciding this for now.
Copy the relevant versions of the code to the current project’s vendor directory.
The source of that code is implementation dependant. Probably some kind of local cache of the VCS data (not a GOPATH/workspace).
Write Manifest (if changed) and Lockfile
Print what changed

Flags:
	-update		update all packages
	-n			dry run
	-override <specs>	specify an override constraints for package(s)

Package specs:
	<path>[:alt location][@<version specifier>]

Examples:
Fetch/update github.com/heroku/rollrus to latest version, including transitive dependencies (ensuring it matches the constraints of rollrus, or—if not contrained—their latest versions):
	$ dep ensure github.com/heroku/rollrus
Same dep, but choose any minor patch release in the 0.9.X series, setting the constraint. If another constraint exists that constraint is changed to ~0.9.0:
	$ dep ensure github.com/heroku/rollrus@~0.9.0
Same dep, but choose any release >= 0.9.1 and < 1.0.0, setting/changing constraints:
	$ dep ensure github.com/heroku/rollrus@^0.9.1
Same dep, but updating to 1.0.X:
	$ dep ensure github.com/heroku/rollrus@~1.0.0
Same dep, but fetching from a different location:
	$ dep ensure github.com/heroku/rollrus:git.example.com/foo/bar
Same dep, but check out a specific version or range without updating the Manifest and update the Lockfile. This will fail if the specified version does not satisfy any existing constraints:
	$ dep ensure github.com/heroku/rollrus==1.2.3	# 1.2.3 specifically
	$ dep ensure github.com/heroku/rollrus=^1.2.0	# >= 1.2.0  < 2.0.0
Override any declared dependency range of 'github.com/foo/bar' to have the range of '^0.9.1'. This applies transitively:
	$ dep ensure -override github.com/foo/bar@^0.9.1

Transitive deps are ensured based on constraints in the local Manifest if they exist, then constraints in the dependency’s Manifest file. A lack of constraints defaults to the latest version, eg "^2".

For a description of the version specifier string, see this handy guide from crates.io. We are going to defer on making a final decision about this syntax until we have more experience with it in practice.
	`,
}

var ovr bool

func init() {
	ensureCmd.flag.BoolVar(&ovr, "override", false, "Interpret specified constraints as overrides rather than normal constraints")
}

func runEnsure(args []string) error {
	p, err := depContext.loadProject("")
	if err != nil {
		return err
	}

	sm, err := depContext.sourceManager()
	if err != nil {
		return err
	}
	defer sm.Release()

	var errs []error
	for _, arg := range args {
		// default persist to manifest
		constraint, err := getProjectConstraint(arg, sm)
		if err != nil {
			errs = append(errs, err)
		}
		pp := gps.ProjectProperties{
			NetworkName: constraint.Ident.NetworkName,
			Constraint:  constraint.Constraint,
		}

		if ovr {
			p.m.Ovr[constraint.Ident.ProjectRoot] = pp
		} else {
			p.m.Dependencies[constraint.Ident.ProjectRoot] = pp
		}

		for i, lp := range p.l.P {
			if lp.Ident() == constraint.Ident {
				p.l.P = append(p.l.P[:i], p.l.P[i+1:]...)
				break
			}
		}
	}

	if len(errs) > 0 {
		var buf bytes.Buffer
		for err := range errs {
			fmt.Fprintln(&buf, err)
		}

		return errors.New(buf.String())
	}

	params := gps.SolveParameters{
		RootDir:     p.absroot,
		Manifest:    p.m,
		Lock:        p.l,
		Trace:       true,
		TraceLogger: log.New(os.Stdout, "", 0),
	}

	params.RootPackageTree, err = gps.ListPackages(p.absroot, string(p.importroot))
	if err != nil {
		return errors.Wrap(err, "ensure ListPackage for project")
	}
	solver, err := gps.Prepare(params, sm)
	if err != nil {
		return errors.Wrap(err, "ensure Prepare")
	}
	solution, err := solver.Solve()
	if err != nil {
		handleAllTheFailuresOfTheWorld(err)
		return errors.Wrap(err, "ensure Solve()")
	}

	p.l.P = solution.Projects()
	p.l.Memo = solution.InputHash()

	tv, err := ioutil.TempDir("", "vendor")
	if err != nil {
		return errors.Wrap(err, "ensure making temporary vendor")
	}
	defer os.RemoveAll(tv)

	tm, err := ioutil.TempFile("", "manifest")
	if err != nil {
		return errors.Wrap(err, "ensure making temporary manifest")
	}
	tm.Close()
	defer os.Remove(tm.Name())

	tl, err := ioutil.TempFile("", "lock")
	if err != nil {
		return errors.Wrap(err, "ensure making temporary lock file")
	}
	tl.Close()
	defer os.Remove(tl.Name())

	if err := gps.WriteDepTree(tv, p.l, sm, true); err != nil {
		return errors.Wrap(err, "ensure gps.WriteDepTree")
	}

	if err := writeFile(tm.Name(), p.m); err != nil {
		return errors.Wrap(err, "ensure writeFile for manifest")
	}

	if err := writeFile(tl.Name(), p.l); err != nil {
		return errors.Wrap(err, "ensure writeFile for lock")
	}

	if err := os.Rename(tm.Name(), filepath.Join(p.absroot, manifestName)); err != nil {
		return errors.Wrap(err, "ensure moving temp manifest into place!")
	}

	if err := os.Rename(tl.Name(), filepath.Join(p.absroot, lockName)); err != nil {
		return errors.Wrap(err, "ensure moving temp manifest into place!")
	}

	os.RemoveAll(filepath.Join(p.absroot, "vendor"))
	if err := copyFolder(tv, filepath.Join(p.absroot, "vendor")); err != nil {
		return errors.Wrap(err, "ensure moving temp vendor")
	}

	return nil
}

func getProjectConstraint(arg string, sm *gps.SourceMgr) (gps.ProjectConstraint, error) {
	constraint := gps.ProjectConstraint{}

	// try to split on '@'
	atIndex := strings.Index(arg, "@")
	if atIndex > 0 {
		parts := strings.SplitN(arg, "@", 2)
		constraint.Constraint = deduceConstraint(parts[1])
		arg = parts[0]
	}
	// TODO: What if there is no @, assume default branch (which may not be master) ?
	// TODO: if we decide to keep equals.....

	// split on colon if there is a network location
	colonIndex := strings.Index(arg, ":")
	if colonIndex > 0 {
		parts := strings.SplitN(arg, ":", 2)
		arg = parts[0]
		constraint.Ident.NetworkName = parts[1]
	}

	pr, err := sm.DeduceProjectRoot(arg)
	if err != nil {
		return constraint, errors.Wrapf(err, "could not infer project root from dependency path: %s", arg) // this should go through to the user
	}

	if string(pr) != arg {
		return constraint, errors.Wrapf(err, "dependency path %s is not a project root", arg)
	}
	constraint.Ident.ProjectRoot = gps.ProjectRoot(arg)

	return constraint, nil
}

// deduceConstraint tries to puzzle out what kind of version is given in a string -
// semver, a revision, or as a fallback, a plain tag
func deduceConstraint(s string) gps.Constraint {
	// always semver if we can
	c, err := gps.NewSemverConstraint(s)
	if err == nil {
		return c
	}

	slen := len(s)
	if slen == 40 {
		if _, err = hex.DecodeString(s); err == nil {
			// Whether or not it's intended to be a SHA1 digest, this is a
			// valid byte sequence for that, so go with Revision. This
			// covers git and hg
			return gps.Revision(s)
		}
	}
	// Next, try for bzr, which has a three-component GUID separated by
	// dashes. There should be two, but the email part could contain
	// internal dashes
	if strings.Count(s, "-") >= 2 {
		// Work from the back to avoid potential confusion from the email
		i3 := strings.LastIndex(s, "-")
		// Skip if - is last char, otherwise this would panic on bounds err
		if slen == i3+1 {
			return gps.NewVersion(s)
		}

		if _, err = hex.DecodeString(s[i3+1:]); err == nil {
			i2 := strings.LastIndex(s[:i3], "-")
			if _, err = strconv.ParseUint(s[i2+1:i3], 10, 64); err == nil {
				// Getting this far means it'd pretty much be nuts if it's not a
				// bzr rev, so don't bother parsing the email.
				return gps.Revision(s)
			}
		}
	}

	// If not a plain SHA1 or bzr custom GUID, assume a plain version.
	// TODO: if there is amgibuity here, then prompt the user?
	return gps.NewVersion(s)
}

// stolen from k8s https://github.com/jessfraz/kubernetes/blob/2df475da2f7e5c0739afabe356012777b5634951/pkg/volume/volume.go#L249
func copyFolder(source string, dest string) (err error) {
	fi, err := os.Lstat(source)
	if err != nil {
		return err
	}

	err = os.MkdirAll(dest, fi.Mode())
	if err != nil {
		return err
	}

	directory, _ := os.Open(source)

	defer directory.Close()

	objects, err := directory.Readdir(-1)

	for _, obj := range objects {
		if obj.Mode()&os.ModeSymlink != 0 {
			continue
		}

		sourcefilepointer := filepath.Join(source, obj.Name())
		destinationfilepointer := filepath.Join(dest, obj.Name())

		if obj.IsDir() {
			err = copyFolder(sourcefilepointer, destinationfilepointer)
			if err != nil {
				return err
			}
		} else {
			err = copyFile(sourcefilepointer, destinationfilepointer)
			if err != nil {
				return err
			}
		}

	}
	return
}

func copyFile(source string, dest string) (err error) {
	sourcefile, err := os.Open(source)
	if err != nil {
		return err
	}

	defer sourcefile.Close()

	destfile, err := os.Create(dest)
	if err != nil {
		return err
	}

	defer destfile.Close()

	_, err = io.Copy(destfile, sourcefile)
	if err == nil {
		sourceinfo, err := os.Stat(source)
		if err != nil {
			err = os.Chmod(dest, sourceinfo.Mode())
		}

	}
	return
}
<commit_msg>ensure: change overrides flag to stringSlice<commit_after>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"encoding/hex"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"io/ioutil"

	"github.com/pkg/errors"
	"github.com/sdboyer/gps"
)

var ensureCmd = &command{
	fn:   runEnsure,
	name: "ensure",
	flag: flag.NewFlagSet("", flag.ExitOnError),
	short: `[flags] <path>[:alt location][@<version specifier>]
	To ensure a dependency is in your project at a specific version (if specified).
	`,
	long: `
	Run it when
To ensure a new dependency is in your project.
To ensure a dependency is updated.
To the latest version that satisfies constraints.
To a specific version or different constraint.
(With no arguments) To ensure that you have all the dependencies specified by your Manifest + lockfile.

What it does
Download code, placing in the vendor/ directory of the project. Only the packages that are actually used by the current project and its dependencies are included.
Any authentication, proxy settings, or other parameters regarding communicating with external repositories is the responsibility of the underlying VCS tools.
Resolve version constraints
If the set of constraints are not solvable, print an error
Collapse any vendor folders in the downloaded code and its transient deps to the root.
Includes dependencies required by the current project’s tests. There are arguments both for and against including the deps of tests for any transitive deps. Defer on deciding this for now.
Copy the relevant versions of the code to the current project’s vendor directory.
The source of that code is implementation dependant. Probably some kind of local cache of the VCS data (not a GOPATH/workspace).
Write Manifest (if changed) and Lockfile
Print what changed

Flags:
	-update		update all packages
	-n			dry run
	-override <specs>	specify an override constraints for package(s)

Package specs:
	<path>[:alt location][@<version specifier>]

Examples:
Fetch/update github.com/heroku/rollrus to latest version, including transitive dependencies (ensuring it matches the constraints of rollrus, or—if not contrained—their latest versions):
	$ dep ensure github.com/heroku/rollrus
Same dep, but choose any minor patch release in the 0.9.X series, setting the constraint. If another constraint exists that constraint is changed to ~0.9.0:
	$ dep ensure github.com/heroku/rollrus@~0.9.0
Same dep, but choose any release >= 0.9.1 and < 1.0.0, setting/changing constraints:
	$ dep ensure github.com/heroku/rollrus@^0.9.1
Same dep, but updating to 1.0.X:
	$ dep ensure github.com/heroku/rollrus@~1.0.0
Same dep, but fetching from a different location:
	$ dep ensure github.com/heroku/rollrus:git.example.com/foo/bar
Same dep, but check out a specific version or range without updating the Manifest and update the Lockfile. This will fail if the specified version does not satisfy any existing constraints:
	$ dep ensure github.com/heroku/rollrus==1.2.3	# 1.2.3 specifically
	$ dep ensure github.com/heroku/rollrus=^1.2.0	# >= 1.2.0  < 2.0.0
Override any declared dependency range of 'github.com/foo/bar' to have the range of '^0.9.1'. This applies transitively:
	$ dep ensure -override github.com/foo/bar@^0.9.1

Transitive deps are ensured based on constraints in the local Manifest if they exist, then constraints in the dependency’s Manifest file. A lack of constraints defaults to the latest version, eg "^2".

For a description of the version specifier string, see this handy guide from crates.io. We are going to defer on making a final decision about this syntax until we have more experience with it in practice.
	`,
}

// stringSlice is a slice of strings
type stringSlice []string

// implement the flag interface for stringSlice
func (s *stringSlice) String() string {
	return fmt.Sprintf("%s", *s)
}
func (s *stringSlice) Set(value string) error {
	*s = append(*s, value)
	return nil
}

var overrides stringSlice

func init() {
	ensureCmd.flag.Var(&overrides, "override", "Interpret specified constraint(s) as override(s) rather than normal constraints")
}

func runEnsure(args []string) error {
	p, err := depContext.loadProject("")
	if err != nil {
		return err
	}

	sm, err := depContext.sourceManager()
	if err != nil {
		return err
	}
	defer sm.Release()

	var errs []error
	for _, arg := range args {
		// default persist to manifest
		constraint, err := getProjectConstraint(arg, sm)
		if err != nil {
			errs = append(errs, err)
		}
		p.m.Dependencies[constraint.Ident.ProjectRoot] = gps.ProjectProperties{
			NetworkName: constraint.Ident.NetworkName,
			Constraint:  constraint.Constraint,
		}

		for i, lp := range p.l.P {
			if lp.Ident() == constraint.Ident {
				p.l.P = append(p.l.P[:i], p.l.P[i+1:]...)
				break
			}
		}
	}

	for _, ovr := range overrides {
		constraint, err := getProjectConstraint(ovr, sm)
		if err != nil {
			errs = append(errs, err)
		}
		p.m.Ovr[constraint.Ident.ProjectRoot] = gps.ProjectProperties{
			NetworkName: constraint.Ident.NetworkName,
			Constraint:  constraint.Constraint,
		}

		for i, lp := range p.l.P {
			if lp.Ident() == constraint.Ident {
				p.l.P = append(p.l.P[:i], p.l.P[i+1:]...)
				break
			}
		}
	}

	if len(errs) > 0 {
		var buf bytes.Buffer
		for err := range errs {
			fmt.Fprintln(&buf, err)
		}

		return errors.New(buf.String())
	}

	params := gps.SolveParameters{
		RootDir:     p.absroot,
		Manifest:    p.m,
		Lock:        p.l,
		Trace:       true,
		TraceLogger: log.New(os.Stdout, "", 0),
	}

	params.RootPackageTree, err = gps.ListPackages(p.absroot, string(p.importroot))
	if err != nil {
		return errors.Wrap(err, "ensure ListPackage for project")
	}
	solver, err := gps.Prepare(params, sm)
	if err != nil {
		return errors.Wrap(err, "ensure Prepare")
	}
	solution, err := solver.Solve()
	if err != nil {
		handleAllTheFailuresOfTheWorld(err)
		return errors.Wrap(err, "ensure Solve()")
	}

	p.l.P = solution.Projects()
	p.l.Memo = solution.InputHash()

	tv, err := ioutil.TempDir("", "vendor")
	if err != nil {
		return errors.Wrap(err, "ensure making temporary vendor")
	}
	defer os.RemoveAll(tv)

	tm, err := ioutil.TempFile("", "manifest")
	if err != nil {
		return errors.Wrap(err, "ensure making temporary manifest")
	}
	tm.Close()
	defer os.Remove(tm.Name())

	tl, err := ioutil.TempFile("", "lock")
	if err != nil {
		return errors.Wrap(err, "ensure making temporary lock file")
	}
	tl.Close()
	defer os.Remove(tl.Name())

	if err := gps.WriteDepTree(tv, p.l, sm, true); err != nil {
		return errors.Wrap(err, "ensure gps.WriteDepTree")
	}

	if err := writeFile(tm.Name(), p.m); err != nil {
		return errors.Wrap(err, "ensure writeFile for manifest")
	}

	if err := writeFile(tl.Name(), p.l); err != nil {
		return errors.Wrap(err, "ensure writeFile for lock")
	}

	if err := os.Rename(tm.Name(), filepath.Join(p.absroot, manifestName)); err != nil {
		return errors.Wrap(err, "ensure moving temp manifest into place!")
	}

	if err := os.Rename(tl.Name(), filepath.Join(p.absroot, lockName)); err != nil {
		return errors.Wrap(err, "ensure moving temp manifest into place!")
	}

	os.RemoveAll(filepath.Join(p.absroot, "vendor"))
	if err := copyFolder(tv, filepath.Join(p.absroot, "vendor")); err != nil {
		return errors.Wrap(err, "ensure moving temp vendor")
	}

	return nil
}

func getProjectConstraint(arg string, sm *gps.SourceMgr) (gps.ProjectConstraint, error) {
	constraint := gps.ProjectConstraint{}

	// try to split on '@'
	atIndex := strings.Index(arg, "@")
	if atIndex > 0 {
		parts := strings.SplitN(arg, "@", 2)
		constraint.Constraint = deduceConstraint(parts[1])
		arg = parts[0]
	}
	// TODO: What if there is no @, assume default branch (which may not be master) ?
	// TODO: if we decide to keep equals.....

	// split on colon if there is a network location
	colonIndex := strings.Index(arg, ":")
	if colonIndex > 0 {
		parts := strings.SplitN(arg, ":", 2)
		arg = parts[0]
		constraint.Ident.NetworkName = parts[1]
	}

	pr, err := sm.DeduceProjectRoot(arg)
	if err != nil {
		return constraint, errors.Wrapf(err, "could not infer project root from dependency path: %s", arg) // this should go through to the user
	}

	if string(pr) != arg {
		return constraint, errors.Wrapf(err, "dependency path %s is not a project root", arg)
	}
	constraint.Ident.ProjectRoot = gps.ProjectRoot(arg)

	return constraint, nil
}

// deduceConstraint tries to puzzle out what kind of version is given in a string -
// semver, a revision, or as a fallback, a plain tag
func deduceConstraint(s string) gps.Constraint {
	// always semver if we can
	c, err := gps.NewSemverConstraint(s)
	if err == nil {
		return c
	}

	slen := len(s)
	if slen == 40 {
		if _, err = hex.DecodeString(s); err == nil {
			// Whether or not it's intended to be a SHA1 digest, this is a
			// valid byte sequence for that, so go with Revision. This
			// covers git and hg
			return gps.Revision(s)
		}
	}
	// Next, try for bzr, which has a three-component GUID separated by
	// dashes. There should be two, but the email part could contain
	// internal dashes
	if strings.Count(s, "-") >= 2 {
		// Work from the back to avoid potential confusion from the email
		i3 := strings.LastIndex(s, "-")
		// Skip if - is last char, otherwise this would panic on bounds err
		if slen == i3+1 {
			return gps.NewVersion(s)
		}

		if _, err = hex.DecodeString(s[i3+1:]); err == nil {
			i2 := strings.LastIndex(s[:i3], "-")
			if _, err = strconv.ParseUint(s[i2+1:i3], 10, 64); err == nil {
				// Getting this far means it'd pretty much be nuts if it's not a
				// bzr rev, so don't bother parsing the email.
				return gps.Revision(s)
			}
		}
	}

	// If not a plain SHA1 or bzr custom GUID, assume a plain version.
	// TODO: if there is amgibuity here, then prompt the user?
	return gps.NewVersion(s)
}

// stolen from k8s https://github.com/jessfraz/kubernetes/blob/2df475da2f7e5c0739afabe356012777b5634951/pkg/volume/volume.go#L249
func copyFolder(source string, dest string) (err error) {
	fi, err := os.Lstat(source)
	if err != nil {
		return err
	}

	err = os.MkdirAll(dest, fi.Mode())
	if err != nil {
		return err
	}

	directory, _ := os.Open(source)

	defer directory.Close()

	objects, err := directory.Readdir(-1)

	for _, obj := range objects {
		if obj.Mode()&os.ModeSymlink != 0 {
			continue
		}

		sourcefilepointer := filepath.Join(source, obj.Name())
		destinationfilepointer := filepath.Join(dest, obj.Name())

		if obj.IsDir() {
			err = copyFolder(sourcefilepointer, destinationfilepointer)
			if err != nil {
				return err
			}
		} else {
			err = copyFile(sourcefilepointer, destinationfilepointer)
			if err != nil {
				return err
			}
		}

	}
	return
}

func copyFile(source string, dest string) (err error) {
	sourcefile, err := os.Open(source)
	if err != nil {
		return err
	}

	defer sourcefile.Close()

	destfile, err := os.Create(dest)
	if err != nil {
		return err
	}

	defer destfile.Close()

	_, err = io.Copy(destfile, sourcefile)
	if err == nil {
		sourceinfo, err := os.Stat(source)
		if err != nil {
			err = os.Chmod(dest, sourceinfo.Mode())
		}

	}
	return
}
<|endoftext|>


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

package main

import (
	"encoding/hex"
	"fmt"
	"os"
	"strconv"
	"strings"

	"github.com/pkg/errors"
	"github.com/sdboyer/gps"
)

var ensureCmd = &command{
	fn:   runEnsure,
	name: "ensure",
	short: `[flags] <path>[:alt location][@<version specifier>]
	To ensure a dependency is in your project at a specific version (if specified).
	`,
	long: `
	Run it when
To ensure a new dependency is in your project.
To ensure a dependency is updated.
To the latest version that satisfies constraints.
To a specific version or different constraint.
(With no arguments) To ensure that you have all the dependencies specified by your Manifest + lockfile.

What it does
Download code, placing in the vendor/ directory of the project. Only the packages that are actually used by the current project and its dependencies are included.
Any authentication, proxy settings, or other parameters regarding communicating with external repositories is the responsibility of the underlying VCS tools.
Resolve version constraints
If the set of constraints are not solvable, print an error
Collapse any vendor folders in the downloaded code and its transient deps to the root.
Includes dependencies required by the current project’s tests. There are arguments both for and against including the deps of tests for any transitive deps. Defer on deciding this for now.
Copy the relevant versions of the code to the current project’s vendor directory.
The source of that code is implementation dependant. Probably some kind of local cache of the VCS data (not a GOPATH/workspace).
Write Manifest (if changed) and Lockfile
Print what changed

Flags:
	-update		update all packages
	-n			dry run
	-override <specs>	specify an override constraints for package(s)

Package specs:
	<path>[:alt location][@<version specifier>]

Examples:
Fetch/update github.com/heroku/rollrus to latest version, including transitive dependencies (ensuring it matches the constraints of rollrus, or—if not contrained—their latest versions):
	$ dep ensure github.com/heroku/rollrus
Same dep, but choose any minor patch release in the 0.9.X series, setting the constraint. If another constraint exists that constraint is changed to ~0.9.0:
	$ dep ensure github.com/heroku/rollrus@~0.9.0
Same dep, but choose any release >= 0.9.1 and < 1.0.0, setting/changing constraints:
	$ dep ensure github.com/heroku/rollrus@^0.9.1
Same dep, but updating to 1.0.X:
	$ dep ensure github.com/heroku/rollrus@~1.0.0
Same dep, but fetching from a different location:
	$ dep ensure github.com/heroku/rollrus:git.example.com/foo/bar
Same dep, but check out a specific version or range without updating the Manifest and update the Lockfile. This will fail if the specified version does not satisfy any existing constraints:
	$ dep ensure github.com/heroku/rollrus==1.2.3	# 1.2.3 specifically
	$ dep ensure github.com/heroku/rollrus=^1.2.0	# >= 1.2.0  < 2.0.0
Override any declared dependency range of 'github.com/foo/bar' to have the range of '^0.9.1'. This applies transitively:
	$ dep ensure -override github.com/foo/bar@^0.9.1

Transitive deps are ensured based on constraints in the local Manifest if they exist, then constraints in the dependency’s Manifest file. A lack of constraints defaults to the latest version, eg "^2".

For a description of the version specifier string, see this handy guide from crates.io. We are going to defer on making a final decision about this syntax until we have more experience with it in practice.
	`,
}

func runEnsure(args []string) error {
	p, err := depContext.loadProject("")
	if err != nil {
		return err
	}

	sm, err := depContext.sourceManager()
	if err != nil {
		return err
	}
	defer sm.Release()

	var errs []error
	for _, arg := range args {
		// default persist to manifest
		constraint, err := getProjectConstraint(arg, sm)
		if err != nil {
			errs = append(errs, err)
		}
		p.m.Dependencies[constraint.Ident.ProjectRoot] = gps.ProjectProperties{
			NetworkName: constraint.Ident.NetworkName,
			Constraint:  constraint.Constraint,
		}
	}
	if len(errs) > 0 {
		for err := range errs {
			fmt.Fprintln(os.Stderr, err)
		}
		os.Exit(1)
	}

	// TODO: do all the sync things and write the manifest
	return nil
}

func getProjectConstraint(arg string, sm *gps.SourceMgr) (gps.ProjectConstraint, error) {
	constraint := gps.ProjectConstraint{}

	// try to split on '@'
	atIndex := strings.Index(arg, "@")
	if atIndex > 0 {
		parts := strings.SplitN(arg, "@", 2)
		constraint.Constraint = deduceConstraint(parts[1])
		arg = parts[0]
	}
	// TODO: if we decide to keep equals.....

	// split on colon if there is a network location
	colonIndex := strings.Index(arg, ":")
	if colonIndex > 0 {
		parts := strings.SplitN(arg, ":", 2)
		arg = parts[0]
		constraint.Ident.NetworkName = parts[1]
	}

	pr, err := sm.DeduceProjectRoot(arg)
	if err != nil {
		return constraint, errors.Wrapf(err, "could not infer project root from dependency path: %s", arg) // this should go through to the user
	}

	if string(pr) != arg {
		return constraint, errors.Wrapf(err, "dependency path %s is not a project root", arg)
	}
	constraint.Ident.ProjectRoot = gps.ProjectRoot(arg)

	return constraint, nil
}

// deduceConstraint tries to puzzle out what kind of version is given in a string -
// semver, a revision, or as a fallback, a plain tag
func deduceConstraint(s string) gps.Constraint {
	// always semver if we can
	c, err := gps.NewSemverConstraint(s)
	if err == nil {
		return c
	}

	slen := len(s)
	if slen == 40 {
		if _, err = hex.DecodeString(s); err == nil {
			// Whether or not it's intended to be a SHA1 digest, this is a
			// valid byte sequence for that, so go with Revision. This
			// covers git and hg
			return gps.Revision(s)
		}
	}
	// Next, try for bzr, which has a three-component GUID separated by
	// dashes. There should be two, but the email part could contain
	// internal dashes
	if strings.Count(s, "-") >= 2 {
		// Work from the back to avoid potential confusion from the email
		i3 := strings.LastIndex(s, "-")
		// Skip if - is last char, otherwise this would panic on bounds err
		if slen == i3+1 {
			return gps.NewVersion(s)
		}

		if _, err = hex.DecodeString(s[i3+1:]); err == nil {
			i2 := strings.LastIndex(s[:i3], "-")
			if _, err = strconv.ParseUint(s[i2+1:i3], 10, 64); err == nil {
				// Getting this far means it'd pretty much be nuts if it's not a
				// bzr rev, so don't bother parsing the email.
				return gps.Revision(s)
			}
		}
	}

	// If not a plain SHA1 or bzr custom GUID, assume a plain version.
	// TODO: if there is amgibuity here, then prompt the user?
	return gps.NewVersion(s)
}
<commit_msg>dep: write updated manfiest, lock and vendor after ensure<commit_after>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"encoding/hex"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"io/ioutil"

	"github.com/pkg/errors"
	"github.com/sdboyer/gps"
)

var ensureCmd = &command{
	fn:   runEnsure,
	name: "ensure",
	short: `[flags] <path>[:alt location][@<version specifier>]
	To ensure a dependency is in your project at a specific version (if specified).
	`,
	long: `
	Run it when
To ensure a new dependency is in your project.
To ensure a dependency is updated.
To the latest version that satisfies constraints.
To a specific version or different constraint.
(With no arguments) To ensure that you have all the dependencies specified by your Manifest + lockfile.

What it does
Download code, placing in the vendor/ directory of the project. Only the packages that are actually used by the current project and its dependencies are included.
Any authentication, proxy settings, or other parameters regarding communicating with external repositories is the responsibility of the underlying VCS tools.
Resolve version constraints
If the set of constraints are not solvable, print an error
Collapse any vendor folders in the downloaded code and its transient deps to the root.
Includes dependencies required by the current project’s tests. There are arguments both for and against including the deps of tests for any transitive deps. Defer on deciding this for now.
Copy the relevant versions of the code to the current project’s vendor directory.
The source of that code is implementation dependant. Probably some kind of local cache of the VCS data (not a GOPATH/workspace).
Write Manifest (if changed) and Lockfile
Print what changed

Flags:
	-update		update all packages
	-n			dry run
	-override <specs>	specify an override constraints for package(s)

Package specs:
	<path>[:alt location][@<version specifier>]

Examples:
Fetch/update github.com/heroku/rollrus to latest version, including transitive dependencies (ensuring it matches the constraints of rollrus, or—if not contrained—their latest versions):
	$ dep ensure github.com/heroku/rollrus
Same dep, but choose any minor patch release in the 0.9.X series, setting the constraint. If another constraint exists that constraint is changed to ~0.9.0:
	$ dep ensure github.com/heroku/rollrus@~0.9.0
Same dep, but choose any release >= 0.9.1 and < 1.0.0, setting/changing constraints:
	$ dep ensure github.com/heroku/rollrus@^0.9.1
Same dep, but updating to 1.0.X:
	$ dep ensure github.com/heroku/rollrus@~1.0.0
Same dep, but fetching from a different location:
	$ dep ensure github.com/heroku/rollrus:git.example.com/foo/bar
Same dep, but check out a specific version or range without updating the Manifest and update the Lockfile. This will fail if the specified version does not satisfy any existing constraints:
	$ dep ensure github.com/heroku/rollrus==1.2.3	# 1.2.3 specifically
	$ dep ensure github.com/heroku/rollrus=^1.2.0	# >= 1.2.0  < 2.0.0
Override any declared dependency range of 'github.com/foo/bar' to have the range of '^0.9.1'. This applies transitively:
	$ dep ensure -override github.com/foo/bar@^0.9.1

Transitive deps are ensured based on constraints in the local Manifest if they exist, then constraints in the dependency’s Manifest file. A lack of constraints defaults to the latest version, eg "^2".

For a description of the version specifier string, see this handy guide from crates.io. We are going to defer on making a final decision about this syntax until we have more experience with it in practice.
	`,
}

func runEnsure(args []string) error {
	p, err := depContext.loadProject("")
	if err != nil {
		return err
	}

	sm, err := depContext.sourceManager()
	if err != nil {
		return err
	}
	defer sm.Release()

	var errs []error
	for _, arg := range args {
		// default persist to manifest
		constraint, err := getProjectConstraint(arg, sm)
		if err != nil {
			errs = append(errs, err)
		}
		p.m.Dependencies[constraint.Ident.ProjectRoot] = gps.ProjectProperties{
			NetworkName: constraint.Ident.NetworkName,
			Constraint:  constraint.Constraint,
		}
	}
	if len(errs) > 0 {
		for err := range errs {
			fmt.Fprintln(os.Stderr, err)
		}
		os.Exit(1)
	}

	fmt.Println(p.absroot)

	params := gps.SolveParameters{
		RootDir:     p.absroot,
		Manifest:    p.m,
		Lock:        p.l,
		Trace:       true,
		TraceLogger: log.New(os.Stdout, "", 0),
	}

	params.RootPackageTree, err = gps.ListPackages(p.absroot, string(p.importroot))
	if err != nil {
		return errors.Wrap(err, "ensure ListPackage for project")
	}
	solver, err := gps.Prepare(params, sm)
	if err != nil {
		return errors.Wrap(err, "ensure Prepare")
	}
	solution, err := solver.Solve()
	if err != nil {
		return errors.Wrap(err, "ensure Solve()")
	}

	ours := p.l.Projects()
	for _, lp := range solution.Projects() {
		i := lp.Ident()
		var have bool
		for _, op := range ours {
			if op.Ident() == i {
				have = true
				break
			}
		}
		if !have {
			p.l.P = append(p.l.P, lp)
		}
	}

	tv, err := ioutil.TempDir("", "vendor")
	if err != nil {
		return errors.Wrap(err, "ensure making temporary vendor")
	}
	defer os.RemoveAll(tv)

	tm, err := ioutil.TempFile("", "manifest")
	if err != nil {
		return errors.Wrap(err, "ensure making temporary manifest")
	}
	tm.Close()
	defer os.Remove(tm.Name())

	tl, err := ioutil.TempFile("", "lock")
	if err != nil {
		return errors.Wrap(err, "ensure making temporary lock file")
	}
	tl.Close()
	defer os.Remove(tl.Name())

	if err := gps.WriteDepTree(tv, p.l, sm, true); err != nil {
		return errors.Wrap(err, "ensure gps.WriteDepTree")
	}

	if err := writeFile(tm.Name(), p.m); err != nil {
		return errors.Wrap(err, "ensure writeFile for manifest")
	}

	if err := writeFile(tl.Name(), p.l); err != nil {
		return errors.Wrap(err, "ensure writeFile for lock")
	}

	if err := os.Rename(tm.Name(), filepath.Join(p.absroot, manifestName)); err != nil {
		return errors.Wrap(err, "ensure moving temp manifest into place!")
	}

	if err := os.Rename(tl.Name(), filepath.Join(p.absroot, lockName)); err != nil {
		return errors.Wrap(err, "ensure moving temp manifest into place!")
	}

	os.RemoveAll(filepath.Join(p.absroot, "vendor"))
	if err := copyFolder(tv, filepath.Join(p.absroot, "vendor")); err != nil {
		return errors.Wrap(err, "ensure moving temp vendor")
	}

	return nil
}

func getProjectConstraint(arg string, sm *gps.SourceMgr) (gps.ProjectConstraint, error) {
	constraint := gps.ProjectConstraint{}

	// try to split on '@'
	atIndex := strings.Index(arg, "@")
	if atIndex > 0 {
		parts := strings.SplitN(arg, "@", 2)
		constraint.Constraint = deduceConstraint(parts[1])
		arg = parts[0]
	}
	// TODO: What if there is no @, assume default branch (which may not be master) ?
	// TODO: if we decide to keep equals.....

	// split on colon if there is a network location
	colonIndex := strings.Index(arg, ":")
	if colonIndex > 0 {
		parts := strings.SplitN(arg, ":", 2)
		arg = parts[0]
		constraint.Ident.NetworkName = parts[1]
	}

	pr, err := sm.DeduceProjectRoot(arg)
	if err != nil {
		return constraint, errors.Wrapf(err, "could not infer project root from dependency path: %s", arg) // this should go through to the user
	}

	if string(pr) != arg {
		return constraint, errors.Wrapf(err, "dependency path %s is not a project root", arg)
	}
	constraint.Ident.ProjectRoot = gps.ProjectRoot(arg)

	return constraint, nil
}

// deduceConstraint tries to puzzle out what kind of version is given in a string -
// semver, a revision, or as a fallback, a plain tag
func deduceConstraint(s string) gps.Constraint {
	// always semver if we can
	c, err := gps.NewSemverConstraint(s)
	if err == nil {
		return c
	}

	slen := len(s)
	if slen == 40 {
		if _, err = hex.DecodeString(s); err == nil {
			// Whether or not it's intended to be a SHA1 digest, this is a
			// valid byte sequence for that, so go with Revision. This
			// covers git and hg
			return gps.Revision(s)
		}
	}
	// Next, try for bzr, which has a three-component GUID separated by
	// dashes. There should be two, but the email part could contain
	// internal dashes
	if strings.Count(s, "-") >= 2 {
		// Work from the back to avoid potential confusion from the email
		i3 := strings.LastIndex(s, "-")
		// Skip if - is last char, otherwise this would panic on bounds err
		if slen == i3+1 {
			return gps.NewVersion(s)
		}

		if _, err = hex.DecodeString(s[i3+1:]); err == nil {
			i2 := strings.LastIndex(s[:i3], "-")
			if _, err = strconv.ParseUint(s[i2+1:i3], 10, 64); err == nil {
				// Getting this far means it'd pretty much be nuts if it's not a
				// bzr rev, so don't bother parsing the email.
				return gps.Revision(s)
			}
		}
	}

	// If not a plain SHA1 or bzr custom GUID, assume a plain version.
	// TODO: if there is amgibuity here, then prompt the user?
	return gps.NewVersion(s)
}

// stolen from k8s https://github.com/jessfraz/kubernetes/blob/2df475da2f7e5c0739afabe356012777b5634951/pkg/volume/volume.go#L249
func copyFolder(source string, dest string) (err error) {
	fi, err := os.Lstat(source)
	if err != nil {
		return err
	}

	err = os.MkdirAll(dest, fi.Mode())
	if err != nil {
		return err
	}

	directory, _ := os.Open(source)

	defer directory.Close()

	objects, err := directory.Readdir(-1)

	for _, obj := range objects {
		if obj.Mode()&os.ModeSymlink != 0 {
			continue
		}

		sourcefilepointer := filepath.Join(source, obj.Name())
		destinationfilepointer := filepath.Join(dest, obj.Name())

		if obj.IsDir() {
			err = copyFolder(sourcefilepointer, destinationfilepointer)
			if err != nil {
				return err
			}
		} else {
			err = copyFile(sourcefilepointer, destinationfilepointer)
			if err != nil {
				return err
			}
		}

	}
	return
}

func copyFile(source string, dest string) (err error) {
	sourcefile, err := os.Open(source)
	if err != nil {
		return err
	}

	defer sourcefile.Close()

	destfile, err := os.Create(dest)
	if err != nil {
		return err
	}

	defer destfile.Close()

	_, err = io.Copy(destfile, sourcefile)
	if err == nil {
		sourceinfo, err := os.Stat(source)
		if err != nil {
			err = os.Chmod(dest, sourceinfo.Mode())
		}

	}
	return
}
<|endoftext|>


<commit_before>package dom

import (
	"time"

	"github.com/gopherjs/gopherjs/js"
)

func WrapEvent(o *js.Object) Event {
	return wrapEvent(o)
}

func wrapEvent(o *js.Object) Event {
	if o == nil || o == js.Undefined {
		return nil
	}
	ev := &BasicEvent{o}
	c := o.Get("constructor")
	switch c {
	case js.Global.Get("AnimationEvent"):
		return &AnimationEvent{ev}
	case js.Global.Get("AudioProcessingEvent"):
		return &AudioProcessingEvent{ev}
	case js.Global.Get("BeforeInputEvent"):
		return &BeforeInputEvent{ev}
	case js.Global.Get("BeforeUnloadEvent"):
		return &BeforeUnloadEvent{ev}
	case js.Global.Get("BlobEvent"):
		return &BlobEvent{ev}
	case js.Global.Get("ClipboardEvent"):
		return &ClipboardEvent{ev}
	case js.Global.Get("CloseEvent"):
		return &CloseEvent{BasicEvent: ev}
	case js.Global.Get("CompositionEvent"):
		return &CompositionEvent{ev}
	case js.Global.Get("CSSFontFaceLoadEvent"):
		return &CSSFontFaceLoadEvent{ev}
	case js.Global.Get("CustomEvent"):
		return &CustomEvent{ev}
	case js.Global.Get("DeviceLightEvent"):
		return &DeviceLightEvent{ev}
	case js.Global.Get("DeviceMotionEvent"):
		return &DeviceMotionEvent{ev}
	case js.Global.Get("DeviceOrientationEvent"):
		return &DeviceOrientationEvent{ev}
	case js.Global.Get("DeviceProximityEvent"):
		return &DeviceProximityEvent{ev}
	case js.Global.Get("DOMTransactionEvent"):
		return &DOMTransactionEvent{ev}
	case js.Global.Get("DragEvent"):
		return &DragEvent{ev}
	case js.Global.Get("EditingBeforeInputEvent"):
		return &EditingBeforeInputEvent{ev}
	case js.Global.Get("ErrorEvent"):
		return &ErrorEvent{ev}
	case js.Global.Get("FocusEvent"):
		return &FocusEvent{ev}
	case js.Global.Get("GamepadEvent"):
		return &GamepadEvent{ev}
	case js.Global.Get("HashChangeEvent"):
		return &HashChangeEvent{ev}
	case js.Global.Get("IDBVersionChangeEvent"):
		return &IDBVersionChangeEvent{ev}
	case js.Global.Get("KeyboardEvent"):
		return &KeyboardEvent{BasicEvent: ev}
	case js.Global.Get("MediaStreamEvent"):
		return &MediaStreamEvent{ev}
	case js.Global.Get("MessageEvent"):
		return &MessageEvent{BasicEvent: ev}
	case js.Global.Get("MouseEvent"):
		return &MouseEvent{UIEvent: &UIEvent{ev}}
	case js.Global.Get("MutationEvent"):
		return &MutationEvent{ev}
	case js.Global.Get("OfflineAudioCompletionEvent"):
		return &OfflineAudioCompletionEvent{ev}
	case js.Global.Get("PageTransitionEvent"):
		return &PageTransitionEvent{ev}
	case js.Global.Get("PointerEvent"):
		return &PointerEvent{ev}
	case js.Global.Get("PopStateEvent"):
		return &PopStateEvent{ev}
	case js.Global.Get("ProgressEvent"):
		return &ProgressEvent{ev}
	case js.Global.Get("RelatedEvent"):
		return &RelatedEvent{ev}
	case js.Global.Get("RTCPeerConnectionIceEvent"):
		return &RTCPeerConnectionIceEvent{ev}
	case js.Global.Get("SensorEvent"):
		return &SensorEvent{ev}
	case js.Global.Get("StorageEvent"):
		return &StorageEvent{ev}
	case js.Global.Get("SVGEvent"):
		return &SVGEvent{ev}
	case js.Global.Get("SVGZoomEvent"):
		return &SVGZoomEvent{ev}
	case js.Global.Get("TimeEvent"):
		return &TimeEvent{ev}
	case js.Global.Get("TouchEvent"):
		return &TouchEvent{ev}
	case js.Global.Get("TrackEvent"):
		return &TrackEvent{ev}
	case js.Global.Get("TransitionEvent"):
		return &TransitionEvent{ev}
	case js.Global.Get("UIEvent"):
		return &UIEvent{ev}
	case js.Global.Get("UserProximityEvent"):
		return &UserProximityEvent{ev}
	case js.Global.Get("WheelEvent"):
		return &WheelEvent{BasicEvent: ev}
	default:
		return ev
	}
}

const (
	EvPhaseNone      = 0
	EvPhaseCapturing = 1
	EvPhaseAtTarget  = 2
	EvPhaseBubbling  = 3
)

type Event interface {
	Bubbles() bool
	Cancelable() bool
	CurrentTarget() Element
	DefaultPrevented() bool
	EventPhase() int
	Target() Element
	Timestamp() time.Time
	Type() string
	PreventDefault()
	StopImmediatePropagation()
	StopPropagation()
	Underlying() *js.Object
}

// Type BasicEvent implements the Event interface and is embedded by
// concrete event types.
type BasicEvent struct{ *js.Object }

type EventOptions struct {
	Bubbles    bool
	Cancelable bool
}

func CreateEvent(typ string, opts EventOptions) *BasicEvent {
	var event = js.Global.Get("Event").New(typ, js.M{
		"bubbles":    opts.Bubbles,
		"cancelable": opts.Cancelable,
	})
	return &BasicEvent{event}
}

func (ev *BasicEvent) Bubbles() bool {
	return ev.Get("bubbles").Bool()
}

func (ev *BasicEvent) Cancelable() bool {
	return ev.Get("cancelable").Bool()
}

func (ev *BasicEvent) CurrentTarget() Element {
	return wrapElement(ev.Get("currentTarget"))
}

func (ev *BasicEvent) DefaultPrevented() bool {
	return ev.Get("defaultPrevented").Bool()
}

func (ev *BasicEvent) EventPhase() int {
	return ev.Get("eventPhase").Int()
}

func (ev *BasicEvent) Target() Element {
	return wrapElement(ev.Get("target"))
}

func (ev *BasicEvent) Timestamp() time.Time {
	ms := ev.Get("timeStamp").Int()
	s := ms / 1000
	ns := (ms % 1000 * 1e6)
	return time.Unix(int64(s), int64(ns))
}

func (ev *BasicEvent) Type() string {
	return ev.Get("type").String()
}

func (ev *BasicEvent) PreventDefault() {
	ev.Call("preventDefault")
}

func (ev *BasicEvent) StopImmediatePropagation() {
	ev.Call("stopImmediatePropagation")
}

func (ev *BasicEvent) StopPropagation() {
	ev.Call("stopPropagation")
}

func (ev *BasicEvent) Underlying() *js.Object {
	return ev.Object
}

type AnimationEvent struct{ *BasicEvent }
type AudioProcessingEvent struct{ *BasicEvent }
type BeforeInputEvent struct{ *BasicEvent }
type BeforeUnloadEvent struct{ *BasicEvent }
type BlobEvent struct{ *BasicEvent }
type ClipboardEvent struct{ *BasicEvent }

type CloseEvent struct {
	*BasicEvent
	Code     int    `js:"code"`
	Reason   string `js:"reason"`
	WasClean bool   `js:"wasClean"`
}

type CompositionEvent struct{ *BasicEvent }
type CSSFontFaceLoadEvent struct{ *BasicEvent }
type CustomEvent struct{ *BasicEvent }
type DeviceLightEvent struct{ *BasicEvent }
type DeviceMotionEvent struct{ *BasicEvent }
type DeviceOrientationEvent struct{ *BasicEvent }
type DeviceProximityEvent struct{ *BasicEvent }
type DOMTransactionEvent struct{ *BasicEvent }
type DragEvent struct{ *BasicEvent }
type EditingBeforeInputEvent struct{ *BasicEvent }
type ErrorEvent struct{ *BasicEvent }
type FocusEvent struct{ *BasicEvent }
type GamepadEvent struct{ *BasicEvent }
type HashChangeEvent struct{ *BasicEvent }
type IDBVersionChangeEvent struct{ *BasicEvent }

const (
	KeyLocationStandard = 0
	KeyLocationLeft     = 1
	KeyLocationRight    = 2
	KeyLocationNumpad   = 3
)

type KeyboardEvent struct {
	*BasicEvent
	AltKey        bool   `js:"altKey"`
	CharCode      int    `js:"charCode"`
	CtrlKey       bool   `js:"ctrlKey"`
	Key           string `js:"key"`
	KeyIdentifier string `js:"keyIdentifier"`
	KeyCode       int    `js:"keyCode"`
	Locale        string `js:"locale"`
	Location      int    `js:"location"`
	KeyLocation   int    `js:"keyLocation"`
	MetaKey       bool   `js:"metaKey"`
	Repeat        bool   `js:"repeat"`
	ShiftKey      bool   `js:"shiftKey"`
}

func (ev *KeyboardEvent) ModifierState(mod string) bool {
	return ev.Call("getModifierState", mod).Bool()
}

type MediaStreamEvent struct{ *BasicEvent }

type MessageEvent struct {
	*BasicEvent
	Data *js.Object `js:"data"`
}

type MouseEvent struct {
	*UIEvent
	AltKey    bool `js:"altKey"`
	Button    int  `js:"button"`
	ClientX   int  `js:"clientX"`
	ClientY   int  `js:"clientY"`
	CtrlKey   bool `js:"ctrlKey"`
	MetaKey   bool `js:"metaKey"`
	MovementX int  `js:"movementX"`
	MovementY int  `js:"movementY"`
	ScreenX   int  `js:"screenX"`
	ScreenY   int  `js:"screenY"`
	ShiftKey  bool `js:"shiftKey"`
}

func (ev *MouseEvent) RelatedTarget() Element {
	return wrapElement(ev.Get("relatedTarget"))
}

func (ev *MouseEvent) ModifierState(mod string) bool {
	return ev.Call("getModifierState", mod).Bool()
}

type MutationEvent struct{ *BasicEvent }
type OfflineAudioCompletionEvent struct{ *BasicEvent }
type PageTransitionEvent struct{ *BasicEvent }
type PointerEvent struct{ *BasicEvent }
type PopStateEvent struct{ *BasicEvent }
type ProgressEvent struct{ *BasicEvent }
type RelatedEvent struct{ *BasicEvent }
type RTCPeerConnectionIceEvent struct{ *BasicEvent }
type SensorEvent struct{ *BasicEvent }
type StorageEvent struct{ *BasicEvent }
type SVGEvent struct{ *BasicEvent }
type SVGZoomEvent struct{ *BasicEvent }
type TimeEvent struct{ *BasicEvent }
type TouchEvent struct{ *BasicEvent }
type TrackEvent struct{ *BasicEvent }
type TransitionEvent struct{ *BasicEvent }
type UIEvent struct{ *BasicEvent }
type UserProximityEvent struct{ *BasicEvent }

const (
	DeltaPixel = 0
	DeltaLine  = 1
	DeltaPage  = 2
)

type WheelEvent struct {
	*BasicEvent
	DeltaX    float64 `js:"deltaX"`
	DeltaY    float64 `js:"deltaY"`
	DeltaZ    float64 `js:"deltaZ"`
	DeltaMode int     `js:"deltaMode"`
}

type EventTarget interface {
	// AddEventListener adds a new event listener and returns the
	// wrapper function it generated. If using RemoveEventListener,
	// that wrapper has to be used.
	AddEventListener(typ string, useCapture bool, listener func(Event)) func(*js.Object)
	RemoveEventListener(typ string, useCapture bool, listener func(*js.Object))
	DispatchEvent(event Event) bool
}
<commit_msg>Add RelatedTarget to FocusEvent<commit_after>package dom

import (
	"time"

	"github.com/gopherjs/gopherjs/js"
)

func WrapEvent(o *js.Object) Event {
	return wrapEvent(o)
}

func wrapEvent(o *js.Object) Event {
	if o == nil || o == js.Undefined {
		return nil
	}
	ev := &BasicEvent{o}
	c := o.Get("constructor")
	switch c {
	case js.Global.Get("AnimationEvent"):
		return &AnimationEvent{ev}
	case js.Global.Get("AudioProcessingEvent"):
		return &AudioProcessingEvent{ev}
	case js.Global.Get("BeforeInputEvent"):
		return &BeforeInputEvent{ev}
	case js.Global.Get("BeforeUnloadEvent"):
		return &BeforeUnloadEvent{ev}
	case js.Global.Get("BlobEvent"):
		return &BlobEvent{ev}
	case js.Global.Get("ClipboardEvent"):
		return &ClipboardEvent{ev}
	case js.Global.Get("CloseEvent"):
		return &CloseEvent{BasicEvent: ev}
	case js.Global.Get("CompositionEvent"):
		return &CompositionEvent{ev}
	case js.Global.Get("CSSFontFaceLoadEvent"):
		return &CSSFontFaceLoadEvent{ev}
	case js.Global.Get("CustomEvent"):
		return &CustomEvent{ev}
	case js.Global.Get("DeviceLightEvent"):
		return &DeviceLightEvent{ev}
	case js.Global.Get("DeviceMotionEvent"):
		return &DeviceMotionEvent{ev}
	case js.Global.Get("DeviceOrientationEvent"):
		return &DeviceOrientationEvent{ev}
	case js.Global.Get("DeviceProximityEvent"):
		return &DeviceProximityEvent{ev}
	case js.Global.Get("DOMTransactionEvent"):
		return &DOMTransactionEvent{ev}
	case js.Global.Get("DragEvent"):
		return &DragEvent{ev}
	case js.Global.Get("EditingBeforeInputEvent"):
		return &EditingBeforeInputEvent{ev}
	case js.Global.Get("ErrorEvent"):
		return &ErrorEvent{ev}
	case js.Global.Get("FocusEvent"):
		return &FocusEvent{ev}
	case js.Global.Get("GamepadEvent"):
		return &GamepadEvent{ev}
	case js.Global.Get("HashChangeEvent"):
		return &HashChangeEvent{ev}
	case js.Global.Get("IDBVersionChangeEvent"):
		return &IDBVersionChangeEvent{ev}
	case js.Global.Get("KeyboardEvent"):
		return &KeyboardEvent{BasicEvent: ev}
	case js.Global.Get("MediaStreamEvent"):
		return &MediaStreamEvent{ev}
	case js.Global.Get("MessageEvent"):
		return &MessageEvent{BasicEvent: ev}
	case js.Global.Get("MouseEvent"):
		return &MouseEvent{UIEvent: &UIEvent{ev}}
	case js.Global.Get("MutationEvent"):
		return &MutationEvent{ev}
	case js.Global.Get("OfflineAudioCompletionEvent"):
		return &OfflineAudioCompletionEvent{ev}
	case js.Global.Get("PageTransitionEvent"):
		return &PageTransitionEvent{ev}
	case js.Global.Get("PointerEvent"):
		return &PointerEvent{ev}
	case js.Global.Get("PopStateEvent"):
		return &PopStateEvent{ev}
	case js.Global.Get("ProgressEvent"):
		return &ProgressEvent{ev}
	case js.Global.Get("RelatedEvent"):
		return &RelatedEvent{ev}
	case js.Global.Get("RTCPeerConnectionIceEvent"):
		return &RTCPeerConnectionIceEvent{ev}
	case js.Global.Get("SensorEvent"):
		return &SensorEvent{ev}
	case js.Global.Get("StorageEvent"):
		return &StorageEvent{ev}
	case js.Global.Get("SVGEvent"):
		return &SVGEvent{ev}
	case js.Global.Get("SVGZoomEvent"):
		return &SVGZoomEvent{ev}
	case js.Global.Get("TimeEvent"):
		return &TimeEvent{ev}
	case js.Global.Get("TouchEvent"):
		return &TouchEvent{ev}
	case js.Global.Get("TrackEvent"):
		return &TrackEvent{ev}
	case js.Global.Get("TransitionEvent"):
		return &TransitionEvent{ev}
	case js.Global.Get("UIEvent"):
		return &UIEvent{ev}
	case js.Global.Get("UserProximityEvent"):
		return &UserProximityEvent{ev}
	case js.Global.Get("WheelEvent"):
		return &WheelEvent{BasicEvent: ev}
	default:
		return ev
	}
}

const (
	EvPhaseNone      = 0
	EvPhaseCapturing = 1
	EvPhaseAtTarget  = 2
	EvPhaseBubbling  = 3
)

type Event interface {
	Bubbles() bool
	Cancelable() bool
	CurrentTarget() Element
	DefaultPrevented() bool
	EventPhase() int
	Target() Element
	Timestamp() time.Time
	Type() string
	PreventDefault()
	StopImmediatePropagation()
	StopPropagation()
	Underlying() *js.Object
}

// Type BasicEvent implements the Event interface and is embedded by
// concrete event types.
type BasicEvent struct{ *js.Object }

type EventOptions struct {
	Bubbles    bool
	Cancelable bool
}

func CreateEvent(typ string, opts EventOptions) *BasicEvent {
	var event = js.Global.Get("Event").New(typ, js.M{
		"bubbles":    opts.Bubbles,
		"cancelable": opts.Cancelable,
	})
	return &BasicEvent{event}
}

func (ev *BasicEvent) Bubbles() bool {
	return ev.Get("bubbles").Bool()
}

func (ev *BasicEvent) Cancelable() bool {
	return ev.Get("cancelable").Bool()
}

func (ev *BasicEvent) CurrentTarget() Element {
	return wrapElement(ev.Get("currentTarget"))
}

func (ev *BasicEvent) DefaultPrevented() bool {
	return ev.Get("defaultPrevented").Bool()
}

func (ev *BasicEvent) EventPhase() int {
	return ev.Get("eventPhase").Int()
}

func (ev *BasicEvent) Target() Element {
	return wrapElement(ev.Get("target"))
}

func (ev *BasicEvent) Timestamp() time.Time {
	ms := ev.Get("timeStamp").Int()
	s := ms / 1000
	ns := (ms % 1000 * 1e6)
	return time.Unix(int64(s), int64(ns))
}

func (ev *BasicEvent) Type() string {
	return ev.Get("type").String()
}

func (ev *BasicEvent) PreventDefault() {
	ev.Call("preventDefault")
}

func (ev *BasicEvent) StopImmediatePropagation() {
	ev.Call("stopImmediatePropagation")
}

func (ev *BasicEvent) StopPropagation() {
	ev.Call("stopPropagation")
}

func (ev *BasicEvent) Underlying() *js.Object {
	return ev.Object
}

type AnimationEvent struct{ *BasicEvent }
type AudioProcessingEvent struct{ *BasicEvent }
type BeforeInputEvent struct{ *BasicEvent }
type BeforeUnloadEvent struct{ *BasicEvent }
type BlobEvent struct{ *BasicEvent }
type ClipboardEvent struct{ *BasicEvent }

type CloseEvent struct {
	*BasicEvent
	Code     int    `js:"code"`
	Reason   string `js:"reason"`
	WasClean bool   `js:"wasClean"`
}

type CompositionEvent struct{ *BasicEvent }
type CSSFontFaceLoadEvent struct{ *BasicEvent }
type CustomEvent struct{ *BasicEvent }
type DeviceLightEvent struct{ *BasicEvent }
type DeviceMotionEvent struct{ *BasicEvent }
type DeviceOrientationEvent struct{ *BasicEvent }
type DeviceProximityEvent struct{ *BasicEvent }
type DOMTransactionEvent struct{ *BasicEvent }
type DragEvent struct{ *BasicEvent }
type EditingBeforeInputEvent struct{ *BasicEvent }
type ErrorEvent struct{ *BasicEvent }

type FocusEvent struct{ *BasicEvent }

func (ev *FocusEvent) RelatedTarget() Element {
	return wrapElement(ev.Get("relatedTarget"))
}

type GamepadEvent struct{ *BasicEvent }
type HashChangeEvent struct{ *BasicEvent }
type IDBVersionChangeEvent struct{ *BasicEvent }

const (
	KeyLocationStandard = 0
	KeyLocationLeft     = 1
	KeyLocationRight    = 2
	KeyLocationNumpad   = 3
)

type KeyboardEvent struct {
	*BasicEvent
	AltKey        bool   `js:"altKey"`
	CharCode      int    `js:"charCode"`
	CtrlKey       bool   `js:"ctrlKey"`
	Key           string `js:"key"`
	KeyIdentifier string `js:"keyIdentifier"`
	KeyCode       int    `js:"keyCode"`
	Locale        string `js:"locale"`
	Location      int    `js:"location"`
	KeyLocation   int    `js:"keyLocation"`
	MetaKey       bool   `js:"metaKey"`
	Repeat        bool   `js:"repeat"`
	ShiftKey      bool   `js:"shiftKey"`
}

func (ev *KeyboardEvent) ModifierState(mod string) bool {
	return ev.Call("getModifierState", mod).Bool()
}

type MediaStreamEvent struct{ *BasicEvent }

type MessageEvent struct {
	*BasicEvent
	Data *js.Object `js:"data"`
}

type MouseEvent struct {
	*UIEvent
	AltKey    bool `js:"altKey"`
	Button    int  `js:"button"`
	ClientX   int  `js:"clientX"`
	ClientY   int  `js:"clientY"`
	CtrlKey   bool `js:"ctrlKey"`
	MetaKey   bool `js:"metaKey"`
	MovementX int  `js:"movementX"`
	MovementY int  `js:"movementY"`
	ScreenX   int  `js:"screenX"`
	ScreenY   int  `js:"screenY"`
	ShiftKey  bool `js:"shiftKey"`
}

func (ev *MouseEvent) RelatedTarget() Element {
	return wrapElement(ev.Get("relatedTarget"))
}

func (ev *MouseEvent) ModifierState(mod string) bool {
	return ev.Call("getModifierState", mod).Bool()
}

type MutationEvent struct{ *BasicEvent }
type OfflineAudioCompletionEvent struct{ *BasicEvent }
type PageTransitionEvent struct{ *BasicEvent }
type PointerEvent struct{ *BasicEvent }
type PopStateEvent struct{ *BasicEvent }
type ProgressEvent struct{ *BasicEvent }
type RelatedEvent struct{ *BasicEvent }
type RTCPeerConnectionIceEvent struct{ *BasicEvent }
type SensorEvent struct{ *BasicEvent }
type StorageEvent struct{ *BasicEvent }
type SVGEvent struct{ *BasicEvent }
type SVGZoomEvent struct{ *BasicEvent }
type TimeEvent struct{ *BasicEvent }
type TouchEvent struct{ *BasicEvent }
type TrackEvent struct{ *BasicEvent }
type TransitionEvent struct{ *BasicEvent }
type UIEvent struct{ *BasicEvent }
type UserProximityEvent struct{ *BasicEvent }

const (
	DeltaPixel = 0
	DeltaLine  = 1
	DeltaPage  = 2
)

type WheelEvent struct {
	*BasicEvent
	DeltaX    float64 `js:"deltaX"`
	DeltaY    float64 `js:"deltaY"`
	DeltaZ    float64 `js:"deltaZ"`
	DeltaMode int     `js:"deltaMode"`
}

type EventTarget interface {
	// AddEventListener adds a new event listener and returns the
	// wrapper function it generated. If using RemoveEventListener,
	// that wrapper has to be used.
	AddEventListener(typ string, useCapture bool, listener func(Event)) func(*js.Object)
	RemoveEventListener(typ string, useCapture bool, listener func(*js.Object))
	DispatchEvent(event Event) bool
}
<|endoftext|>


<commit_before>package client

import (
	"encoding/json"
	"net/url"
	"time"

	"golang.org/x/net/context"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/events"
	"github.com/docker/docker/api/types/filters"
	timetypes "github.com/docker/docker/api/types/time"
)

// Events returns a stream of events in the daemon. It's up to the caller to close the stream
// by cancelling the context. Once the stream has been completely read an io.EOF error will
// be sent over the error channel. If an error is sent all processing will be stopped. It's up
// to the caller to reopen the stream in the event of an error by reinvoking this method.
func (cli *Client) Events(ctx context.Context, options types.EventsOptions) (<-chan events.Message, <-chan error) {

	messages := make(chan events.Message)
	errs := make(chan error, 1)

	go func() {
		defer close(errs)

		query, err := buildEventsQueryParams(cli.version, options)
		if err != nil {
			errs <- err
			return
		}

		resp, err := cli.get(ctx, "/events", query, nil)
		if err != nil {
			errs <- err
			return
		}
		defer resp.body.Close()

		decoder := json.NewDecoder(resp.body)

		for {
			select {
			case <-ctx.Done():
				errs <- ctx.Err()
				return
			default:
				var event events.Message
				if err := decoder.Decode(&event); err != nil {
					errs <- err
					return
				}

				select {
				case messages <- event:
				case <-ctx.Done():
					errs <- ctx.Err()
					return
				}
			}
		}
	}()

	return messages, errs
}

func buildEventsQueryParams(cliVersion string, options types.EventsOptions) (url.Values, error) {
	query := url.Values{}
	ref := time.Now()

	if options.Since != "" {
		ts, err := timetypes.GetTimestamp(options.Since, ref)
		if err != nil {
			return nil, err
		}
		query.Set("since", ts)
	}

	if options.Until != "" {
		ts, err := timetypes.GetTimestamp(options.Until, ref)
		if err != nil {
			return nil, err
		}
		query.Set("until", ts)
	}

	if options.Filters.Len() > 0 {
		filterJSON, err := filters.ToParamWithVersion(cliVersion, options.Filters)
		if err != nil {
			return nil, err
		}
		query.Set("filters", filterJSON)
	}

	return query, nil
}
<commit_msg>Fixes a race condition in client events monitoring<commit_after>package client

import (
	"encoding/json"
	"net/url"
	"time"

	"golang.org/x/net/context"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/events"
	"github.com/docker/docker/api/types/filters"
	timetypes "github.com/docker/docker/api/types/time"
)

// Events returns a stream of events in the daemon. It's up to the caller to close the stream
// by cancelling the context. Once the stream has been completely read an io.EOF error will
// be sent over the error channel. If an error is sent all processing will be stopped. It's up
// to the caller to reopen the stream in the event of an error by reinvoking this method.
func (cli *Client) Events(ctx context.Context, options types.EventsOptions) (<-chan events.Message, <-chan error) {

	messages := make(chan events.Message)
	errs := make(chan error, 1)

	started := make(chan struct{})
	go func() {
		defer close(errs)

		query, err := buildEventsQueryParams(cli.version, options)
		if err != nil {
			close(started)
			errs <- err
			return
		}

		resp, err := cli.get(ctx, "/events", query, nil)
		if err != nil {
			close(started)
			errs <- err
			return
		}
		defer resp.body.Close()

		decoder := json.NewDecoder(resp.body)

		close(started)
		for {
			select {
			case <-ctx.Done():
				errs <- ctx.Err()
				return
			default:
				var event events.Message
				if err := decoder.Decode(&event); err != nil {
					errs <- err
					return
				}

				select {
				case messages <- event:
				case <-ctx.Done():
					errs <- ctx.Err()
					return
				}
			}
		}
	}()
	<-started

	return messages, errs
}

func buildEventsQueryParams(cliVersion string, options types.EventsOptions) (url.Values, error) {
	query := url.Values{}
	ref := time.Now()

	if options.Since != "" {
		ts, err := timetypes.GetTimestamp(options.Since, ref)
		if err != nil {
			return nil, err
		}
		query.Set("since", ts)
	}

	if options.Until != "" {
		ts, err := timetypes.GetTimestamp(options.Until, ref)
		if err != nil {
			return nil, err
		}
		query.Set("until", ts)
	}

	if options.Filters.Len() > 0 {
		filterJSON, err := filters.ToParamWithVersion(cliVersion, options.Filters)
		if err != nil {
			return nil, err
		}
		query.Set("filters", filterJSON)
	}

	return query, nil
}
<|endoftext|>