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

package dao

import (
	"fmt"
	"time"

	"strings"

	"github.com/astaxie/beego/orm"
	"github.com/vmware/harbor/src/common/models"
	"github.com/vmware/harbor/src/common/utils/log"
)

// AddRepTarget ...
func AddRepTarget(target models.RepTarget) (int64, error) {
	o := GetOrmer()
	return o.Insert(&target)
}

// GetRepTarget ...
func GetRepTarget(id int64) (*models.RepTarget, error) {
	o := GetOrmer()
	t := models.RepTarget{ID: id}
	err := o.Read(&t)
	if err == orm.ErrNoRows {
		return nil, nil
	}
	return &t, err
}

// GetRepTargetByName ...
func GetRepTargetByName(name string) (*models.RepTarget, error) {
	o := GetOrmer()
	t := models.RepTarget{Name: name}
	err := o.Read(&t, "Name")
	if err == orm.ErrNoRows {
		return nil, nil
	}
	return &t, err
}

// GetRepTargetByEndpoint ...
func GetRepTargetByEndpoint(endpoint string) (*models.RepTarget, error) {
	o := GetOrmer()
	t := models.RepTarget{
		URL: endpoint,
	}
	err := o.Read(&t, "URL")
	if err == orm.ErrNoRows {
		return nil, nil
	}
	return &t, err
}

// DeleteRepTarget ...
func DeleteRepTarget(id int64) error {
	o := GetOrmer()
	_, err := o.Delete(&models.RepTarget{ID: id})
	return err
}

// UpdateRepTarget ...
func UpdateRepTarget(target models.RepTarget) error {
	o := GetOrmer()
	target.UpdateTime = time.Now()
	_, err := o.Update(&target, "URL", "Name", "Username", "Password", "Insecure", "UpdateTime")
	return err
}

// FilterRepTargets filters targets by name
func FilterRepTargets(name string) ([]*models.RepTarget, error) {
	o := GetOrmer()

	var args []interface{}

	sql := `select * from replication_target `
	if len(name) != 0 {
		sql += `where name like ? `
		args = append(args, "%"+escape(name)+"%")
	}
	sql += `order by creation_time`

	var targets []*models.RepTarget

	if _, err := o.Raw(sql, args).QueryRows(&targets); err != nil {
		return nil, err
	}

	return targets, nil
}

// AddRepPolicy ...
func AddRepPolicy(policy models.RepPolicy) (int64, error) {
	o := GetOrmer()
	sql := `insert into replication_policy (name, project_id, target_id, enabled, description, cron_str, creation_time, update_time, filters, replicate_deletion)
				values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
	params := []interface{}{}
	now := time.Now()
	params = append(params, policy.Name, policy.ProjectID, policy.TargetID, 1,
		policy.Description, policy.Trigger, now, now, policy.Filters,
		policy.ReplicateDeletion)

	result, err := o.Raw(sql, params...).Exec()
	if err != nil {
		return 0, err
	}

	return result.LastInsertId()
}

// GetRepPolicy ...
func GetRepPolicy(id int64) (*models.RepPolicy, error) {
	o := GetOrmer()
	sql := `select * from replication_policy where id = ? and deleted = 0`

	var policy models.RepPolicy

	if err := o.Raw(sql, id).QueryRow(&policy); err != nil {
		if err == orm.ErrNoRows {
			return nil, nil
		}
		return nil, err
	}

	return &policy, nil
}

// FilterRepPolicies filters policies by name and project ID
func FilterRepPolicies(name string, projectID int64) ([]*models.RepPolicy, error) {
	o := GetOrmer()

	var args []interface{}

	sql := `select rp.id, rp.project_id, rp.target_id,
				rt.name as target_name, rp.name, rp.description,
				rp.cron_str, rp.filters, rp.replicate_deletion,
				rp.creation_time, rp.update_time,
				count(rj.status) as error_job_count
			from replication_policy rp
			left join replication_target rt on rp.target_id=rt.id
			left join replication_job rj on rp.id=rj.policy_id and (rj.status="error"
				or rj.status="retrying")
			where rp.deleted = 0 `

	if len(name) != 0 && projectID != 0 {
		sql += `and rp.name like ? and rp.project_id = ? `
		args = append(args, "%"+escape(name)+"%")
		args = append(args, projectID)
	} else if len(name) != 0 {
		sql += `and rp.name like ? `
		args = append(args, "%"+escape(name)+"%")
	} else if projectID != 0 {
		sql += `and rp.project_id = ? `
		args = append(args, projectID)
	}

	sql += `group by rp.id order by rp.creation_time`

	var policies []*models.RepPolicy
	if _, err := o.Raw(sql, args).QueryRows(&policies); err != nil {
		return nil, err
	}

	return policies, nil
}

// GetRepPolicyByName ...
func GetRepPolicyByName(name string) (*models.RepPolicy, error) {
	o := GetOrmer()
	sql := `select * from replication_policy where deleted = 0 and name = ?`

	var policy models.RepPolicy

	if err := o.Raw(sql, name).QueryRow(&policy); err != nil {
		if err == orm.ErrNoRows {
			return nil, nil
		}
		return nil, err
	}

	return &policy, nil
}

// GetRepPolicyByProject ...
func GetRepPolicyByProject(projectID int64) ([]*models.RepPolicy, error) {
	o := GetOrmer()
	sql := `select * from replication_policy where deleted = 0 and project_id = ?`

	var policies []*models.RepPolicy

	if _, err := o.Raw(sql, projectID).QueryRows(&policies); err != nil {
		return nil, err
	}

	return policies, nil
}

// GetRepPolicyByTarget ...
func GetRepPolicyByTarget(targetID int64) ([]*models.RepPolicy, error) {
	o := GetOrmer()
	sql := `select * from replication_policy where deleted = 0 and target_id = ?`

	var policies []*models.RepPolicy

	if _, err := o.Raw(sql, targetID).QueryRows(&policies); err != nil {
		return nil, err
	}

	return policies, nil
}

// GetRepPolicyByProjectAndTarget ...
func GetRepPolicyByProjectAndTarget(projectID, targetID int64) ([]*models.RepPolicy, error) {
	o := GetOrmer()
	sql := `select * from replication_policy where deleted = 0 and project_id = ? and target_id = ?`

	var policies []*models.RepPolicy

	if _, err := o.Raw(sql, projectID, targetID).QueryRows(&policies); err != nil {
		return nil, err
	}

	return policies, nil
}

// UpdateRepPolicy ...
func UpdateRepPolicy(policy *models.RepPolicy) error {
	o := GetOrmer()
	policy.UpdateTime = time.Now()
	_, err := o.Update(policy, "TargetID", "Name", "Description",
		"Trigger", "Filters", "ReplicateDeletion", "UpdateTime")
	return err
}

// DeleteRepPolicy ...
func DeleteRepPolicy(id int64) error {
	o := GetOrmer()
	policy := &models.RepPolicy{
		ID:         id,
		Deleted:    1,
		UpdateTime: time.Now(),
	}
	_, err := o.Update(policy, "Deleted")
	return err
}

// AddRepJob ...
func AddRepJob(job models.RepJob) (int64, error) {
	o := GetOrmer()
	if len(job.Status) == 0 {
		job.Status = models.JobPending
	}
	if len(job.TagList) > 0 {
		job.Tags = strings.Join(job.TagList, ",")
	}
	return o.Insert(&job)
}

// GetRepJob ...
func GetRepJob(id int64) (*models.RepJob, error) {
	o := GetOrmer()
	j := models.RepJob{ID: id}
	err := o.Read(&j)
	if err == orm.ErrNoRows {
		return nil, nil
	}
	genTagListForJob(&j)
	return &j, nil
}

// GetRepJobByPolicy ...
func GetRepJobByPolicy(policyID int64) ([]*models.RepJob, error) {
	var res []*models.RepJob
	_, err := repJobPolicyIDQs(policyID).All(&res)
	genTagListForJob(res...)
	return res, err
}

// FilterRepJobs ...
func FilterRepJobs(policyID int64, repository, status string, startTime,
	endTime *time.Time, limit, offset int64) ([]*models.RepJob, int64, error) {

	jobs := []*models.RepJob{}

	qs := GetOrmer().QueryTable(new(models.RepJob))

	if policyID != 0 {
		qs = qs.Filter("PolicyID", policyID)
	}
	if len(repository) != 0 {
		qs = qs.Filter("Repository__icontains", repository)
	}
	if len(status) != 0 {
		qs = qs.Filter("Status__icontains", status)
	}
	if startTime != nil {
		qs = qs.Filter("CreationTime__gte", startTime)
	}
	if endTime != nil {
		qs = qs.Filter("CreationTime__lte", endTime)
	}

	total, err := qs.Count()
	if err != nil {
		return jobs, 0, err
	}

	qs = qs.OrderBy("-UpdateTime")

	_, err = qs.Limit(limit).Offset(offset).All(&jobs)
	if err != nil {
		return jobs, 0, err
	}

	genTagListForJob(jobs...)

	return jobs, total, nil
}

// GetRepJobToStop get jobs that are possibly being handled by workers of a certain policy.
func GetRepJobToStop(policyID int64) ([]*models.RepJob, error) {
	var res []*models.RepJob
	_, err := repJobPolicyIDQs(policyID).Filter("status__in", models.JobPending, models.JobRunning).All(&res)
	genTagListForJob(res...)
	return res, err
}

func repJobQs() orm.QuerySeter {
	o := GetOrmer()
	return o.QueryTable("replication_job")
}

func repJobPolicyIDQs(policyID int64) orm.QuerySeter {
	return repJobQs().Filter("policy_id", policyID)
}

// DeleteRepJob ...
func DeleteRepJob(id int64) error {
	o := GetOrmer()
	_, err := o.Delete(&models.RepJob{ID: id})
	return err
}

// UpdateRepJobStatus ...
func UpdateRepJobStatus(id int64, status string) error {
	o := GetOrmer()
	j := models.RepJob{
		ID:         id,
		Status:     status,
		UpdateTime: time.Now(),
	}
	n, err := o.Update(&j, "Status", "UpdateTime")
	if n == 0 {
		log.Warningf("no records are updated when updating replication job %d", id)
	}
	return err
}

// ResetRunningJobs update all running jobs status to pending, including replication jobs and scan jobs.
func ResetRunningJobs() error {
	o := GetOrmer()
	sql := fmt.Sprintf("update replication_job set status = '%s', update_time = ? where status = '%s'", models.JobPending, models.JobRunning)
	_, err := o.Raw(sql, time.Now()).Exec()
	if err != nil {
		return err
	}
	sql = fmt.Sprintf("update %s set status = '%s', update_time = ? where status = '%s'", models.ScanJobTable, models.JobPending, models.JobRunning)
	_, err = o.Raw(sql, time.Now()).Exec()
	return err
}

// GetRepJobByStatus get jobs of certain statuses
func GetRepJobByStatus(status ...string) ([]*models.RepJob, error) {
	var res []*models.RepJob
	var t []interface{}
	for _, s := range status {
		t = append(t, interface{}(s))
	}
	_, err := repJobQs().Filter("status__in", t...).All(&res)
	genTagListForJob(res...)
	return res, err
}

func genTagListForJob(jobs ...*models.RepJob) {
	for _, j := range jobs {
		if len(j.Tags) > 0 {
			j.TagList = strings.Split(j.Tags, ",")
		}
	}
}
<commit_msg>Update project ID property if needed when updating replication policy<commit_after>// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package dao

import (
	"fmt"
	"time"

	"strings"

	"github.com/astaxie/beego/orm"
	"github.com/vmware/harbor/src/common/models"
	"github.com/vmware/harbor/src/common/utils/log"
)

// AddRepTarget ...
func AddRepTarget(target models.RepTarget) (int64, error) {
	o := GetOrmer()
	return o.Insert(&target)
}

// GetRepTarget ...
func GetRepTarget(id int64) (*models.RepTarget, error) {
	o := GetOrmer()
	t := models.RepTarget{ID: id}
	err := o.Read(&t)
	if err == orm.ErrNoRows {
		return nil, nil
	}
	return &t, err
}

// GetRepTargetByName ...
func GetRepTargetByName(name string) (*models.RepTarget, error) {
	o := GetOrmer()
	t := models.RepTarget{Name: name}
	err := o.Read(&t, "Name")
	if err == orm.ErrNoRows {
		return nil, nil
	}
	return &t, err
}

// GetRepTargetByEndpoint ...
func GetRepTargetByEndpoint(endpoint string) (*models.RepTarget, error) {
	o := GetOrmer()
	t := models.RepTarget{
		URL: endpoint,
	}
	err := o.Read(&t, "URL")
	if err == orm.ErrNoRows {
		return nil, nil
	}
	return &t, err
}

// DeleteRepTarget ...
func DeleteRepTarget(id int64) error {
	o := GetOrmer()
	_, err := o.Delete(&models.RepTarget{ID: id})
	return err
}

// UpdateRepTarget ...
func UpdateRepTarget(target models.RepTarget) error {
	o := GetOrmer()
	target.UpdateTime = time.Now()
	_, err := o.Update(&target, "URL", "Name", "Username", "Password", "Insecure", "UpdateTime")
	return err
}

// FilterRepTargets filters targets by name
func FilterRepTargets(name string) ([]*models.RepTarget, error) {
	o := GetOrmer()

	var args []interface{}

	sql := `select * from replication_target `
	if len(name) != 0 {
		sql += `where name like ? `
		args = append(args, "%"+escape(name)+"%")
	}
	sql += `order by creation_time`

	var targets []*models.RepTarget

	if _, err := o.Raw(sql, args).QueryRows(&targets); err != nil {
		return nil, err
	}

	return targets, nil
}

// AddRepPolicy ...
func AddRepPolicy(policy models.RepPolicy) (int64, error) {
	o := GetOrmer()
	sql := `insert into replication_policy (name, project_id, target_id, enabled, description, cron_str, creation_time, update_time, filters, replicate_deletion)
				values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
	params := []interface{}{}
	now := time.Now()
	params = append(params, policy.Name, policy.ProjectID, policy.TargetID, 1,
		policy.Description, policy.Trigger, now, now, policy.Filters,
		policy.ReplicateDeletion)

	result, err := o.Raw(sql, params...).Exec()
	if err != nil {
		return 0, err
	}

	return result.LastInsertId()
}

// GetRepPolicy ...
func GetRepPolicy(id int64) (*models.RepPolicy, error) {
	o := GetOrmer()
	sql := `select * from replication_policy where id = ? and deleted = 0`

	var policy models.RepPolicy

	if err := o.Raw(sql, id).QueryRow(&policy); err != nil {
		if err == orm.ErrNoRows {
			return nil, nil
		}
		return nil, err
	}

	return &policy, nil
}

// FilterRepPolicies filters policies by name and project ID
func FilterRepPolicies(name string, projectID int64) ([]*models.RepPolicy, error) {
	o := GetOrmer()

	var args []interface{}

	sql := `select rp.id, rp.project_id, rp.target_id,
				rt.name as target_name, rp.name, rp.description,
				rp.cron_str, rp.filters, rp.replicate_deletion,
				rp.creation_time, rp.update_time,
				count(rj.status) as error_job_count
			from replication_policy rp
			left join replication_target rt on rp.target_id=rt.id
			left join replication_job rj on rp.id=rj.policy_id and (rj.status="error"
				or rj.status="retrying")
			where rp.deleted = 0 `

	if len(name) != 0 && projectID != 0 {
		sql += `and rp.name like ? and rp.project_id = ? `
		args = append(args, "%"+escape(name)+"%")
		args = append(args, projectID)
	} else if len(name) != 0 {
		sql += `and rp.name like ? `
		args = append(args, "%"+escape(name)+"%")
	} else if projectID != 0 {
		sql += `and rp.project_id = ? `
		args = append(args, projectID)
	}

	sql += `group by rp.id order by rp.creation_time`

	var policies []*models.RepPolicy
	if _, err := o.Raw(sql, args).QueryRows(&policies); err != nil {
		return nil, err
	}

	return policies, nil
}

// GetRepPolicyByName ...
func GetRepPolicyByName(name string) (*models.RepPolicy, error) {
	o := GetOrmer()
	sql := `select * from replication_policy where deleted = 0 and name = ?`

	var policy models.RepPolicy

	if err := o.Raw(sql, name).QueryRow(&policy); err != nil {
		if err == orm.ErrNoRows {
			return nil, nil
		}
		return nil, err
	}

	return &policy, nil
}

// GetRepPolicyByProject ...
func GetRepPolicyByProject(projectID int64) ([]*models.RepPolicy, error) {
	o := GetOrmer()
	sql := `select * from replication_policy where deleted = 0 and project_id = ?`

	var policies []*models.RepPolicy

	if _, err := o.Raw(sql, projectID).QueryRows(&policies); err != nil {
		return nil, err
	}

	return policies, nil
}

// GetRepPolicyByTarget ...
func GetRepPolicyByTarget(targetID int64) ([]*models.RepPolicy, error) {
	o := GetOrmer()
	sql := `select * from replication_policy where deleted = 0 and target_id = ?`

	var policies []*models.RepPolicy

	if _, err := o.Raw(sql, targetID).QueryRows(&policies); err != nil {
		return nil, err
	}

	return policies, nil
}

// GetRepPolicyByProjectAndTarget ...
func GetRepPolicyByProjectAndTarget(projectID, targetID int64) ([]*models.RepPolicy, error) {
	o := GetOrmer()
	sql := `select * from replication_policy where deleted = 0 and project_id = ? and target_id = ?`

	var policies []*models.RepPolicy

	if _, err := o.Raw(sql, projectID, targetID).QueryRows(&policies); err != nil {
		return nil, err
	}

	return policies, nil
}

// UpdateRepPolicy ...
func UpdateRepPolicy(policy *models.RepPolicy) error {
	o := GetOrmer()
	policy.UpdateTime = time.Now()
	_, err := o.Update(policy, "ProjectID", "TargetID", "Name", "Description",
		"Trigger", "Filters", "ReplicateDeletion", "UpdateTime")
	return err
}

// DeleteRepPolicy ...
func DeleteRepPolicy(id int64) error {
	o := GetOrmer()
	policy := &models.RepPolicy{
		ID:         id,
		Deleted:    1,
		UpdateTime: time.Now(),
	}
	_, err := o.Update(policy, "Deleted")
	return err
}

// AddRepJob ...
func AddRepJob(job models.RepJob) (int64, error) {
	o := GetOrmer()
	if len(job.Status) == 0 {
		job.Status = models.JobPending
	}
	if len(job.TagList) > 0 {
		job.Tags = strings.Join(job.TagList, ",")
	}
	return o.Insert(&job)
}

// GetRepJob ...
func GetRepJob(id int64) (*models.RepJob, error) {
	o := GetOrmer()
	j := models.RepJob{ID: id}
	err := o.Read(&j)
	if err == orm.ErrNoRows {
		return nil, nil
	}
	genTagListForJob(&j)
	return &j, nil
}

// GetRepJobByPolicy ...
func GetRepJobByPolicy(policyID int64) ([]*models.RepJob, error) {
	var res []*models.RepJob
	_, err := repJobPolicyIDQs(policyID).All(&res)
	genTagListForJob(res...)
	return res, err
}

// FilterRepJobs ...
func FilterRepJobs(policyID int64, repository, status string, startTime,
	endTime *time.Time, limit, offset int64) ([]*models.RepJob, int64, error) {

	jobs := []*models.RepJob{}

	qs := GetOrmer().QueryTable(new(models.RepJob))

	if policyID != 0 {
		qs = qs.Filter("PolicyID", policyID)
	}
	if len(repository) != 0 {
		qs = qs.Filter("Repository__icontains", repository)
	}
	if len(status) != 0 {
		qs = qs.Filter("Status__icontains", status)
	}
	if startTime != nil {
		qs = qs.Filter("CreationTime__gte", startTime)
	}
	if endTime != nil {
		qs = qs.Filter("CreationTime__lte", endTime)
	}

	total, err := qs.Count()
	if err != nil {
		return jobs, 0, err
	}

	qs = qs.OrderBy("-UpdateTime")

	_, err = qs.Limit(limit).Offset(offset).All(&jobs)
	if err != nil {
		return jobs, 0, err
	}

	genTagListForJob(jobs...)

	return jobs, total, nil
}

// GetRepJobToStop get jobs that are possibly being handled by workers of a certain policy.
func GetRepJobToStop(policyID int64) ([]*models.RepJob, error) {
	var res []*models.RepJob
	_, err := repJobPolicyIDQs(policyID).Filter("status__in", models.JobPending, models.JobRunning).All(&res)
	genTagListForJob(res...)
	return res, err
}

func repJobQs() orm.QuerySeter {
	o := GetOrmer()
	return o.QueryTable("replication_job")
}

func repJobPolicyIDQs(policyID int64) orm.QuerySeter {
	return repJobQs().Filter("policy_id", policyID)
}

// DeleteRepJob ...
func DeleteRepJob(id int64) error {
	o := GetOrmer()
	_, err := o.Delete(&models.RepJob{ID: id})
	return err
}

// UpdateRepJobStatus ...
func UpdateRepJobStatus(id int64, status string) error {
	o := GetOrmer()
	j := models.RepJob{
		ID:         id,
		Status:     status,
		UpdateTime: time.Now(),
	}
	n, err := o.Update(&j, "Status", "UpdateTime")
	if n == 0 {
		log.Warningf("no records are updated when updating replication job %d", id)
	}
	return err
}

// ResetRunningJobs update all running jobs status to pending, including replication jobs and scan jobs.
func ResetRunningJobs() error {
	o := GetOrmer()
	sql := fmt.Sprintf("update replication_job set status = '%s', update_time = ? where status = '%s'", models.JobPending, models.JobRunning)
	_, err := o.Raw(sql, time.Now()).Exec()
	if err != nil {
		return err
	}
	sql = fmt.Sprintf("update %s set status = '%s', update_time = ? where status = '%s'", models.ScanJobTable, models.JobPending, models.JobRunning)
	_, err = o.Raw(sql, time.Now()).Exec()
	return err
}

// GetRepJobByStatus get jobs of certain statuses
func GetRepJobByStatus(status ...string) ([]*models.RepJob, error) {
	var res []*models.RepJob
	var t []interface{}
	for _, s := range status {
		t = append(t, interface{}(s))
	}
	_, err := repJobQs().Filter("status__in", t...).All(&res)
	genTagListForJob(res...)
	return res, err
}

func genTagListForJob(jobs ...*models.RepJob) {
	for _, j := range jobs {
		if len(j.Tags) > 0 {
			j.TagList = strings.Split(j.Tags, ",")
		}
	}
}
<|endoftext|>


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

// The iterable package provides several traversal and searching methods.
// It can be used on anything that satisfies the Iterable interface,
// including vector, though certain functions, such as Map, can also be used on
// something that would produce an infinite amount of data.
package iterable

import (
	"container/list"
	"container/vector"
)

type Iterable interface {
	// Iter should return a fresh channel each time it is called.
	Iter() <-chan interface{}
}

func not(f func(interface{}) bool) func(interface{}) bool {
	return func(e interface{}) bool { return !f(e) }
}

// All tests whether f is true for every element of iter.
func All(iter Iterable, f func(interface{}) bool) bool {
	for e := range iter.Iter() {
		if !f(e) {
			return false
		}
	}
	return true
}

// Any tests whether f is true for at least one element of iter.
func Any(iter Iterable, f func(interface{}) bool) bool {
	return !All(iter, not(f))
}

// Data returns a slice containing the elements of iter.
func Data(iter Iterable) []interface{} {
	vec := new(vector.Vector)
	for e := range iter.Iter() {
		vec.Push(e)
	}
	return vec.Data()
}

// filteredIterable is a struct that implements Iterable with each element
// passed through a filter.
type filteredIterable struct {
	it Iterable
	f  func(interface{}) bool
}

func (f *filteredIterable) iterate(out chan<- interface{}) {
	for e := range f.it.Iter() {
		if f.f(e) {
			out <- e
		}
	}
	close(out)
}

func (f *filteredIterable) Iter() <-chan interface{} {
	ch := make(chan interface{})
	go f.iterate(ch)
	return ch
}

// Filter returns an Iterable that returns the elements of iter that satisfy f.
func Filter(iter Iterable, f func(interface{}) bool) Iterable {
	return &filteredIterable{iter, f}
}

// Find returns the first element of iter that satisfies f.
// Returns nil if no such element is found.
func Find(iter Iterable, f func(interface{}) bool) interface{} {
	for e := range Filter(iter, f).Iter() {
		return e
	}
	return nil
}

// Injector is a type representing a function that takes two arguments,
// an accumulated value and an element, and returns the next accumulated value.
// See the Inject function.
type Injector func(interface{}, interface{}) interface{}

// Inject combines the elements of iter by repeatedly calling f with an
// accumulated value and each element in order. The starting accumulated value
// is initial, and after each call the accumulated value is set to the return
// value of f. For instance, to compute a sum:
//   var arr IntArray = []int{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
//   sum := iterable.Inject(arr, 0,
//                          func(ax interface {}, x interface {}) interface {} {
//                            return ax.(int) + x.(int) }).(int)
func Inject(iter Iterable, initial interface{}, f Injector) interface{} {
	acc := initial
	for e := range iter.Iter() {
		acc = f(acc, e)
	}
	return acc
}

// mappedIterable is a helper struct that implements Iterable, returned by Map.
type mappedIterable struct {
	it Iterable
	f  func(interface{}) interface{}
}

func (m *mappedIterable) iterate(out chan<- interface{}) {
	for e := range m.it.Iter() {
		out <- m.f(e)
	}
	close(out)
}

func (m *mappedIterable) Iter() <-chan interface{} {
	ch := make(chan interface{})
	go m.iterate(ch)
	return ch
}

// Map returns an Iterable that returns the result of applying f to each
// element of iter.
func Map(iter Iterable, f func(interface{}) interface{}) Iterable {
	return &mappedIterable{iter, f}
}

// Partition(iter, f) returns Filter(iter, f) and Filter(iter, !f).
func Partition(iter Iterable, f func(interface{}) bool) (Iterable, Iterable) {
	return Filter(iter, f), Filter(iter, not(f))
}

// helper type for the Take/TakeWhile/Drop/DropWhile functions.
// primarily used so that the .Iter() method can be attached
type iterFunc func(chan<- interface{})

// provide the Iterable interface
func (v iterFunc) Iter() <-chan interface{} {
	ch := make(chan interface{})
	go v(ch)
	return ch
}

// Take returns an Iterable that contains the first n elements of iter.
func Take(iter Iterable, n int) Iterable { return Slice(iter, 0, n) }

// TakeWhile returns an Iterable that contains elements from iter while f is true.
func TakeWhile(iter Iterable, f func(interface{}) bool) Iterable {
	return iterFunc(func(ch chan<- interface{}) {
		for v := range iter.Iter() {
			if !f(v) {
				break
			}
			ch <- v
		}
		close(ch)
	})
}

// Drop returns an Iterable that returns each element of iter after the first n elements.
func Drop(iter Iterable, n int) Iterable {
	return iterFunc(func(ch chan<- interface{}) {
		m := n
		for v := range iter.Iter() {
			if m > 0 {
				m--
				continue
			}
			ch <- v
		}
		close(ch)
	})
}

// DropWhile returns an Iterable that returns each element of iter after the initial sequence for which f returns true.
func DropWhile(iter Iterable, f func(interface{}) bool) Iterable {
	return iterFunc(func(ch chan<- interface{}) {
		drop := true
		for v := range iter.Iter() {
			if drop {
				if f(v) {
					continue
				}
				drop = false
			}
			ch <- v
		}
		close(ch)
	})
}

// Cycle repeats the values of iter in order infinitely.
func Cycle(iter Iterable) Iterable {
	return iterFunc(func(ch chan<- interface{}) {
		for {
			for v := range iter.Iter() {
				ch <- v
			}
		}
	})
}

// Chain returns an Iterable that concatentates all values from the specified Iterables.
func Chain(args []Iterable) Iterable {
	return iterFunc(func(ch chan<- interface{}) {
		for _, e := range args {
			for v := range e.Iter() {
				ch <- v
			}
		}
		close(ch)
	})
}

// Zip returns an Iterable of []interface{} consisting of the next element from
// each input Iterable.  The length of the returned Iterable is the minimum of
// the lengths of the input Iterables.
func Zip(args []Iterable) Iterable {
	return iterFunc(func(ch chan<- interface{}) {
		defer close(ch)
		if len(args) == 0 {
			return
		}
		iters := make([]<-chan interface{}, len(args))
		for i := 0; i < len(iters); i++ {
			iters[i] = args[i].Iter()
		}
		for {
			out := make([]interface{}, len(args))
			for i, v := range iters {
				out[i] = <-v
				if closed(v) {
					return
				}
			}
			ch <- out
		}
	})
}

// ZipWith returns an Iterable containing the result of executing f using arguments read from a and b.
func ZipWith2(f func(c, d interface{}) interface{}, a, b Iterable) Iterable {
	return Map(Zip([]Iterable{a, b}), func(a1 interface{}) interface{} {
		arr := a1.([]interface{})
		return f(arr[0], arr[1])
	})
}

// ZipWith returns an Iterable containing the result of executing f using arguments read from a, b and c.
func ZipWith3(f func(d, e, f interface{}) interface{}, a, b, c Iterable) Iterable {
	return Map(Zip([]Iterable{a, b, c}), func(a1 interface{}) interface{} {
		arr := a1.([]interface{})
		return f(arr[0], arr[1], arr[2])
	})
}

// Slice returns an Iterable that contains the elements from iter
// with indexes in [start, stop).
func Slice(iter Iterable, start, stop int) Iterable {
	return iterFunc(func(ch chan<- interface{}) {
		defer close(ch)
		i := 0
		for v := range iter.Iter() {
			switch {
			case i >= stop:
				return
			case i >= start:
				ch <- v
			}
			i++
		}
	})
}

// Repeat generates an infinite stream of v.
func Repeat(v interface{}) Iterable {
	return iterFunc(func(ch chan<- interface{}) {
		for {
			ch <- v
		}
	})
}

// RepeatTimes generates a stream of n copies of v.
func RepeatTimes(v interface{}, n int) Iterable {
	return iterFunc(func(ch chan<- interface{}) {
		for i := 0; i < n; i++ {
			ch <- v
		}
		close(ch)
	})
}

// Group is the type for elements returned by the GroupBy function.
type Group struct {
	Key  interface{} // key value for matching items
	Vals Iterable    // Iterable for receiving values in the group
}

// Key defines the interface required by the GroupBy function.
type Grouper interface {
	// Return the key for the given value
	Key(interface{}) interface{}

	// Compute equality for the given keys
	Equal(a, b interface{}) bool
}

// GroupBy combines sequences of logically identical values from iter using k
// to generate a key to compare values.  Each value emitted by the returned
// Iterable is of type Group, which contains the key used for matching the
// values for the group, and an Iterable for retrieving all the values in the
// group.
func GroupBy(iter Iterable, k Grouper) Iterable {
	return iterFunc(func(ch chan<- interface{}) {
		var curkey interface{}
		var lst *list.List
		// Basic strategy is to read one group at a time into a list prior to emitting the Group value
		for v := range iter.Iter() {
			kv := k.Key(v)
			if lst == nil || !k.Equal(curkey, kv) {
				if lst != nil {
					ch <- Group{curkey, lst}
				}
				lst = list.New()
				curkey = kv
			}
			lst.PushBack(v)
		}
		if lst != nil {
			ch <- Group{curkey, lst}
		}
		close(ch)
	})
}

// Unique removes duplicate values which occur consecutively using id to compute keys.
func Unique(iter Iterable, id Grouper) Iterable {
	return Map(GroupBy(iter, id), func(v interface{}) interface{} { return v.(Group).Key })
}
<commit_msg>iterable: expose iterFunc as iterable.Func<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The iterable package provides several traversal and searching methods.
// It can be used on anything that satisfies the Iterable interface,
// including vector, though certain functions, such as Map, can also be used on
// something that would produce an infinite amount of data.
package iterable

import (
	"container/list"
	"container/vector"
)

type Iterable interface {
	// Iter should return a fresh channel each time it is called.
	Iter() <-chan interface{}
}

func not(f func(interface{}) bool) func(interface{}) bool {
	return func(e interface{}) bool { return !f(e) }
}

// All tests whether f is true for every element of iter.
func All(iter Iterable, f func(interface{}) bool) bool {
	for e := range iter.Iter() {
		if !f(e) {
			return false
		}
	}
	return true
}

// Any tests whether f is true for at least one element of iter.
func Any(iter Iterable, f func(interface{}) bool) bool {
	return !All(iter, not(f))
}

// Data returns a slice containing the elements of iter.
func Data(iter Iterable) []interface{} {
	vec := new(vector.Vector)
	for e := range iter.Iter() {
		vec.Push(e)
	}
	return vec.Data()
}

// filteredIterable is a struct that implements Iterable with each element
// passed through a filter.
type filteredIterable struct {
	it Iterable
	f  func(interface{}) bool
}

func (f *filteredIterable) iterate(out chan<- interface{}) {
	for e := range f.it.Iter() {
		if f.f(e) {
			out <- e
		}
	}
	close(out)
}

func (f *filteredIterable) Iter() <-chan interface{} {
	ch := make(chan interface{})
	go f.iterate(ch)
	return ch
}

// Filter returns an Iterable that returns the elements of iter that satisfy f.
func Filter(iter Iterable, f func(interface{}) bool) Iterable {
	return &filteredIterable{iter, f}
}

// Find returns the first element of iter that satisfies f.
// Returns nil if no such element is found.
func Find(iter Iterable, f func(interface{}) bool) interface{} {
	for e := range Filter(iter, f).Iter() {
		return e
	}
	return nil
}

// Injector is a type representing a function that takes two arguments,
// an accumulated value and an element, and returns the next accumulated value.
// See the Inject function.
type Injector func(interface{}, interface{}) interface{}

// Inject combines the elements of iter by repeatedly calling f with an
// accumulated value and each element in order. The starting accumulated value
// is initial, and after each call the accumulated value is set to the return
// value of f. For instance, to compute a sum:
//   var arr IntArray = []int{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
//   sum := iterable.Inject(arr, 0,
//                          func(ax interface {}, x interface {}) interface {} {
//                            return ax.(int) + x.(int) }).(int)
func Inject(iter Iterable, initial interface{}, f Injector) interface{} {
	acc := initial
	for e := range iter.Iter() {
		acc = f(acc, e)
	}
	return acc
}

// mappedIterable is a helper struct that implements Iterable, returned by Map.
type mappedIterable struct {
	it Iterable
	f  func(interface{}) interface{}
}

func (m *mappedIterable) iterate(out chan<- interface{}) {
	for e := range m.it.Iter() {
		out <- m.f(e)
	}
	close(out)
}

func (m *mappedIterable) Iter() <-chan interface{} {
	ch := make(chan interface{})
	go m.iterate(ch)
	return ch
}

// Map returns an Iterable that returns the result of applying f to each
// element of iter.
func Map(iter Iterable, f func(interface{}) interface{}) Iterable {
	return &mappedIterable{iter, f}
}

// Partition(iter, f) returns Filter(iter, f) and Filter(iter, !f).
func Partition(iter Iterable, f func(interface{}) bool) (Iterable, Iterable) {
	return Filter(iter, f), Filter(iter, not(f))
}

// A Func is a function that, when called, sends the
// iterable values on a channel.
type Func func(chan<- interface{})

// Iter creates and returns a new channel; it starts a
// goroutine running f to send values to the channel.
func (f Func) Iter() <-chan interface{} {
	ch := make(chan interface{})
	go f(ch)
	return ch
}

// Take returns an Iterable that contains the first n elements of iter.
func Take(iter Iterable, n int) Iterable { return Slice(iter, 0, n) }

// TakeWhile returns an Iterable that contains elements from iter while f is true.
func TakeWhile(iter Iterable, f func(interface{}) bool) Iterable {
	return Func(func(ch chan<- interface{}) {
		for v := range iter.Iter() {
			if !f(v) {
				break
			}
			ch <- v
		}
		close(ch)
	})
}

// Drop returns an Iterable that returns each element of iter after the first n elements.
func Drop(iter Iterable, n int) Iterable {
	return Func(func(ch chan<- interface{}) {
		m := n
		for v := range iter.Iter() {
			if m > 0 {
				m--
				continue
			}
			ch <- v
		}
		close(ch)
	})
}

// DropWhile returns an Iterable that returns each element of iter after the initial sequence for which f returns true.
func DropWhile(iter Iterable, f func(interface{}) bool) Iterable {
	return Func(func(ch chan<- interface{}) {
		drop := true
		for v := range iter.Iter() {
			if drop {
				if f(v) {
					continue
				}
				drop = false
			}
			ch <- v
		}
		close(ch)
	})
}

// Cycle repeats the values of iter in order infinitely.
func Cycle(iter Iterable) Iterable {
	return Func(func(ch chan<- interface{}) {
		for {
			for v := range iter.Iter() {
				ch <- v
			}
		}
	})
}

// Chain returns an Iterable that concatentates all values from the specified Iterables.
func Chain(args []Iterable) Iterable {
	return Func(func(ch chan<- interface{}) {
		for _, e := range args {
			for v := range e.Iter() {
				ch <- v
			}
		}
		close(ch)
	})
}

// Zip returns an Iterable of []interface{} consisting of the next element from
// each input Iterable.  The length of the returned Iterable is the minimum of
// the lengths of the input Iterables.
func Zip(args []Iterable) Iterable {
	return Func(func(ch chan<- interface{}) {
		defer close(ch)
		if len(args) == 0 {
			return
		}
		iters := make([]<-chan interface{}, len(args))
		for i := 0; i < len(iters); i++ {
			iters[i] = args[i].Iter()
		}
		for {
			out := make([]interface{}, len(args))
			for i, v := range iters {
				out[i] = <-v
				if closed(v) {
					return
				}
			}
			ch <- out
		}
	})
}

// ZipWith returns an Iterable containing the result of executing f using arguments read from a and b.
func ZipWith2(f func(c, d interface{}) interface{}, a, b Iterable) Iterable {
	return Map(Zip([]Iterable{a, b}), func(a1 interface{}) interface{} {
		arr := a1.([]interface{})
		return f(arr[0], arr[1])
	})
}

// ZipWith returns an Iterable containing the result of executing f using arguments read from a, b and c.
func ZipWith3(f func(d, e, f interface{}) interface{}, a, b, c Iterable) Iterable {
	return Map(Zip([]Iterable{a, b, c}), func(a1 interface{}) interface{} {
		arr := a1.([]interface{})
		return f(arr[0], arr[1], arr[2])
	})
}

// Slice returns an Iterable that contains the elements from iter
// with indexes in [start, stop).
func Slice(iter Iterable, start, stop int) Iterable {
	return Func(func(ch chan<- interface{}) {
		defer close(ch)
		i := 0
		for v := range iter.Iter() {
			switch {
			case i >= stop:
				return
			case i >= start:
				ch <- v
			}
			i++
		}
	})
}

// Repeat generates an infinite stream of v.
func Repeat(v interface{}) Iterable {
	return Func(func(ch chan<- interface{}) {
		for {
			ch <- v
		}
	})
}

// RepeatTimes generates a stream of n copies of v.
func RepeatTimes(v interface{}, n int) Iterable {
	return Func(func(ch chan<- interface{}) {
		for i := 0; i < n; i++ {
			ch <- v
		}
		close(ch)
	})
}

// Group is the type for elements returned by the GroupBy function.
type Group struct {
	Key  interface{} // key value for matching items
	Vals Iterable    // Iterable for receiving values in the group
}

// Key defines the interface required by the GroupBy function.
type Grouper interface {
	// Return the key for the given value
	Key(interface{}) interface{}

	// Compute equality for the given keys
	Equal(a, b interface{}) bool
}

// GroupBy combines sequences of logically identical values from iter using k
// to generate a key to compare values.  Each value emitted by the returned
// Iterable is of type Group, which contains the key used for matching the
// values for the group, and an Iterable for retrieving all the values in the
// group.
func GroupBy(iter Iterable, k Grouper) Iterable {
	return Func(func(ch chan<- interface{}) {
		var curkey interface{}
		var lst *list.List
		// Basic strategy is to read one group at a time into a list prior to emitting the Group value
		for v := range iter.Iter() {
			kv := k.Key(v)
			if lst == nil || !k.Equal(curkey, kv) {
				if lst != nil {
					ch <- Group{curkey, lst}
				}
				lst = list.New()
				curkey = kv
			}
			lst.PushBack(v)
		}
		if lst != nil {
			ch <- Group{curkey, lst}
		}
		close(ch)
	})
}

// Unique removes duplicate values which occur consecutively using id to compute keys.
func Unique(iter Iterable, id Grouper) Iterable {
	return Map(GroupBy(iter, id), func(v interface{}) interface{} { return v.(Group).Key })
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

// Version is the current version of the buffalo binary
const Version = "0.9.0"

func init() {
	RootCmd.AddCommand(versionCmd)
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print the version number of buffalo",
	Long:  `All software has versions.  This is buffalo's.`,
	Run: func(c *cobra.Command, args []string) {
		fmt.Printf("Buffalo version is: %s\n", Version)
	},
	// needed to override the root level pre-run func
	PersistentPreRun: func(c *cobra.Command, args []string) {
	},
}
<commit_msg>actual version bump<commit_after>package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

// Version is the current version of the buffalo binary
const Version = "v0.9.0"

func init() {
	RootCmd.AddCommand(versionCmd)
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print the version number of buffalo",
	Long:  `All software has versions.  This is buffalo's.`,
	Run: func(c *cobra.Command, args []string) {
		fmt.Printf("Buffalo version is: %s\n", Version)
	},
	// needed to override the root level pre-run func
	PersistentPreRun: func(c *cobra.Command, args []string) {
	},
}
<|endoftext|>


<commit_before>// +build cgo

package copy

/*
#include <linux/fs.h>

#ifndef FICLONE
#define FICLONE		_IOW(0x94, 9, int)
#endif
*/
import "C"
import (
	"container/list"
	"errors"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"
	"syscall"
	"time"

	"github.com/containers/storage/pkg/idtools"
	"github.com/containers/storage/pkg/pools"
	"github.com/containers/storage/pkg/system"
	rsystem "github.com/opencontainers/runc/libcontainer/system"
	"golang.org/x/sys/unix"
)

// Mode indicates whether to use hardlink or copy content
type Mode int

const (
	// Content creates a new file, and copies the content of the file
	Content Mode = iota
	// Hardlink creates a new hardlink to the existing file
	Hardlink
)

// CopyRegularToFile copies the content of a file to another
func CopyRegularToFile(srcPath string, dstFile *os.File, fileinfo os.FileInfo, copyWithFileRange, copyWithFileClone *bool) error { // nolint: golint
	srcFile, err := os.Open(srcPath)
	if err != nil {
		return err
	}
	defer srcFile.Close()

	if *copyWithFileClone {
		_, _, err = unix.Syscall(unix.SYS_IOCTL, dstFile.Fd(), C.FICLONE, srcFile.Fd())
		if err == nil {
			return nil
		}

		*copyWithFileClone = false
		if err == unix.EXDEV {
			*copyWithFileRange = false
		}
	}
	if *copyWithFileRange {
		err = doCopyWithFileRange(srcFile, dstFile, fileinfo)
		// Trying the file_clone may not have caught the exdev case
		// as the ioctl may not have been available (therefore EINVAL)
		if err == unix.EXDEV || err == unix.ENOSYS {
			*copyWithFileRange = false
		} else {
			return err
		}
	}
	return legacyCopy(srcFile, dstFile)
}

// CopyRegular copies the content of a file to another
func CopyRegular(srcPath, dstPath string, fileinfo os.FileInfo, copyWithFileRange, copyWithFileClone *bool) error { // nolint: golint
	// If the destination file already exists, we shouldn't blow it away
	dstFile, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, fileinfo.Mode())
	if err != nil {
		return err
	}
	defer dstFile.Close()

	return CopyRegularToFile(srcPath, dstFile, fileinfo, copyWithFileRange, copyWithFileClone)
}

func doCopyWithFileRange(srcFile, dstFile *os.File, fileinfo os.FileInfo) error {
	amountLeftToCopy := fileinfo.Size()

	for amountLeftToCopy > 0 {
		n, err := unix.CopyFileRange(int(srcFile.Fd()), nil, int(dstFile.Fd()), nil, int(amountLeftToCopy), 0)
		if err != nil {
			return err
		}

		amountLeftToCopy = amountLeftToCopy - int64(n)
	}

	return nil
}

func legacyCopy(srcFile io.Reader, dstFile io.Writer) error {
	_, err := pools.Copy(dstFile, srcFile)

	return err
}

func copyXattr(srcPath, dstPath, attr string) error {
	data, err := system.Lgetxattr(srcPath, attr)
	if err != nil && !errors.Is(err, unix.EOPNOTSUPP) {
		return err
	}
	if data != nil {
		if err := system.Lsetxattr(dstPath, attr, data, 0); err != nil {
			return err
		}
	}
	return nil
}

type fileID struct {
	dev uint64
	ino uint64
}

type dirMtimeInfo struct {
	dstPath *string
	stat    *syscall.Stat_t
}

// DirCopy copies or hardlinks the contents of one directory to another,
// properly handling xattrs, and soft links
//
// Copying xattrs can be opted out of by passing false for copyXattrs.
func DirCopy(srcDir, dstDir string, copyMode Mode, copyXattrs bool) error {
	copyWithFileRange := true
	copyWithFileClone := true

	// This is a map of source file inodes to dst file paths
	copiedFiles := make(map[fileID]string)

	dirsToSetMtimes := list.New()
	err := filepath.Walk(srcDir, func(srcPath string, f os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		// Rebase path
		relPath, err := filepath.Rel(srcDir, srcPath)
		if err != nil {
			return err
		}

		dstPath := filepath.Join(dstDir, relPath)
		stat, ok := f.Sys().(*syscall.Stat_t)
		if !ok {
			return fmt.Errorf("Unable to get raw syscall.Stat_t data for %s", srcPath)
		}

		isHardlink := false

		switch mode := f.Mode(); {
		case mode.IsRegular():
			id := fileID{dev: uint64(stat.Dev), ino: stat.Ino}
			if copyMode == Hardlink {
				isHardlink = true
				if err2 := os.Link(srcPath, dstPath); err2 != nil {
					return err2
				}
			} else if hardLinkDstPath, ok := copiedFiles[id]; ok {
				if err2 := os.Link(hardLinkDstPath, dstPath); err2 != nil {
					return err2
				}
			} else {
				if err2 := CopyRegular(srcPath, dstPath, f, &copyWithFileRange, &copyWithFileClone); err2 != nil {
					return err2
				}
				copiedFiles[id] = dstPath
			}

		case mode.IsDir():
			if err := os.Mkdir(dstPath, f.Mode()); err != nil && !os.IsExist(err) {
				return err
			}

		case mode&os.ModeSymlink != 0:
			link, err := os.Readlink(srcPath)
			if err != nil {
				return err
			}

			if err := os.Symlink(link, dstPath); err != nil {
				return err
			}

		case mode&os.ModeNamedPipe != 0:
			fallthrough

		case mode&os.ModeSocket != 0:
			if err := unix.Mkfifo(dstPath, stat.Mode); err != nil {
				return err
			}

		case mode&os.ModeDevice != 0:
			if rsystem.RunningInUserNS() {
				// cannot create a device if running in user namespace
				return nil
			}
			if err := unix.Mknod(dstPath, stat.Mode, int(stat.Rdev)); err != nil {
				return err
			}

		default:
			return fmt.Errorf("unknown file type with mode %v for %s", mode, srcPath)
		}

		// Everything below is copying metadata from src to dst. All this metadata
		// already shares an inode for hardlinks.
		if isHardlink {
			return nil
		}

		if err := idtools.SafeLchown(dstPath, int(stat.Uid), int(stat.Gid)); err != nil {
			return err
		}

		if copyXattrs {
			if err := doCopyXattrs(srcPath, dstPath); err != nil {
				return err
			}
		}

		isSymlink := f.Mode()&os.ModeSymlink != 0

		// There is no LChmod, so ignore mode for symlink. Also, this
		// must happen after chown, as that can modify the file mode
		if !isSymlink {
			if err := os.Chmod(dstPath, f.Mode()); err != nil {
				return err
			}
		}

		// system.Chtimes doesn't support a NOFOLLOW flag atm
		// nolint: unconvert
		if f.IsDir() {
			dirsToSetMtimes.PushFront(&dirMtimeInfo{dstPath: &dstPath, stat: stat})
		} else if !isSymlink {
			aTime := time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec))
			mTime := time.Unix(int64(stat.Mtim.Sec), int64(stat.Mtim.Nsec))
			if err := system.Chtimes(dstPath, aTime, mTime); err != nil {
				return err
			}
		} else {
			ts := []syscall.Timespec{stat.Atim, stat.Mtim}
			if err := system.LUtimesNano(dstPath, ts); err != nil {
				return err
			}
		}
		return nil
	})
	if err != nil {
		return err
	}
	for e := dirsToSetMtimes.Front(); e != nil; e = e.Next() {
		mtimeInfo := e.Value.(*dirMtimeInfo)
		ts := []syscall.Timespec{mtimeInfo.stat.Atim, mtimeInfo.stat.Mtim}
		if err := system.LUtimesNano(*mtimeInfo.dstPath, ts); err != nil {
			return err
		}
	}

	return nil
}

func doCopyXattrs(srcPath, dstPath string) error {
	if err := copyXattr(srcPath, dstPath, "security.capability"); err != nil {
		return err
	}

	xattrs, err := system.Llistxattr(srcPath)
	if err != nil && !errors.Is(err, unix.EOPNOTSUPP) {
		return err
	}

	for _, key := range xattrs {
		if strings.HasPrefix(key, "user.") {
			if err := copyXattr(srcPath, dstPath, key); err != nil {
				return err
			}
		}
	}

	// We need to copy this attribute if it appears in an overlay upper layer, as
	// this function is used to copy those. It is set by overlay if a directory
	// is removed and then re-created and should not inherit anything from the
	// same dir in the lower dir.
	return copyXattr(srcPath, dstPath, "trusted.overlay.opaque")
}
<commit_msg>copy: create a unix socket with os.ModeSocket<commit_after>// +build cgo

package copy

/*
#include <linux/fs.h>

#ifndef FICLONE
#define FICLONE		_IOW(0x94, 9, int)
#endif
*/
import "C"
import (
	"container/list"
	"errors"
	"fmt"
	"io"
	"net"
	"os"
	"path/filepath"
	"strings"
	"syscall"
	"time"

	"github.com/containers/storage/pkg/idtools"
	"github.com/containers/storage/pkg/pools"
	"github.com/containers/storage/pkg/system"
	rsystem "github.com/opencontainers/runc/libcontainer/system"
	"golang.org/x/sys/unix"
)

// Mode indicates whether to use hardlink or copy content
type Mode int

const (
	// Content creates a new file, and copies the content of the file
	Content Mode = iota
	// Hardlink creates a new hardlink to the existing file
	Hardlink
)

// CopyRegularToFile copies the content of a file to another
func CopyRegularToFile(srcPath string, dstFile *os.File, fileinfo os.FileInfo, copyWithFileRange, copyWithFileClone *bool) error { // nolint: golint
	srcFile, err := os.Open(srcPath)
	if err != nil {
		return err
	}
	defer srcFile.Close()

	if *copyWithFileClone {
		_, _, err = unix.Syscall(unix.SYS_IOCTL, dstFile.Fd(), C.FICLONE, srcFile.Fd())
		if err == nil {
			return nil
		}

		*copyWithFileClone = false
		if err == unix.EXDEV {
			*copyWithFileRange = false
		}
	}
	if *copyWithFileRange {
		err = doCopyWithFileRange(srcFile, dstFile, fileinfo)
		// Trying the file_clone may not have caught the exdev case
		// as the ioctl may not have been available (therefore EINVAL)
		if err == unix.EXDEV || err == unix.ENOSYS {
			*copyWithFileRange = false
		} else {
			return err
		}
	}
	return legacyCopy(srcFile, dstFile)
}

// CopyRegular copies the content of a file to another
func CopyRegular(srcPath, dstPath string, fileinfo os.FileInfo, copyWithFileRange, copyWithFileClone *bool) error { // nolint: golint
	// If the destination file already exists, we shouldn't blow it away
	dstFile, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, fileinfo.Mode())
	if err != nil {
		return err
	}
	defer dstFile.Close()

	return CopyRegularToFile(srcPath, dstFile, fileinfo, copyWithFileRange, copyWithFileClone)
}

func doCopyWithFileRange(srcFile, dstFile *os.File, fileinfo os.FileInfo) error {
	amountLeftToCopy := fileinfo.Size()

	for amountLeftToCopy > 0 {
		n, err := unix.CopyFileRange(int(srcFile.Fd()), nil, int(dstFile.Fd()), nil, int(amountLeftToCopy), 0)
		if err != nil {
			return err
		}

		amountLeftToCopy = amountLeftToCopy - int64(n)
	}

	return nil
}

func legacyCopy(srcFile io.Reader, dstFile io.Writer) error {
	_, err := pools.Copy(dstFile, srcFile)

	return err
}

func copyXattr(srcPath, dstPath, attr string) error {
	data, err := system.Lgetxattr(srcPath, attr)
	if err != nil && !errors.Is(err, unix.EOPNOTSUPP) {
		return err
	}
	if data != nil {
		if err := system.Lsetxattr(dstPath, attr, data, 0); err != nil {
			return err
		}
	}
	return nil
}

type fileID struct {
	dev uint64
	ino uint64
}

type dirMtimeInfo struct {
	dstPath *string
	stat    *syscall.Stat_t
}

// DirCopy copies or hardlinks the contents of one directory to another,
// properly handling xattrs, and soft links
//
// Copying xattrs can be opted out of by passing false for copyXattrs.
func DirCopy(srcDir, dstDir string, copyMode Mode, copyXattrs bool) error {
	copyWithFileRange := true
	copyWithFileClone := true

	// This is a map of source file inodes to dst file paths
	copiedFiles := make(map[fileID]string)

	dirsToSetMtimes := list.New()
	err := filepath.Walk(srcDir, func(srcPath string, f os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		// Rebase path
		relPath, err := filepath.Rel(srcDir, srcPath)
		if err != nil {
			return err
		}

		dstPath := filepath.Join(dstDir, relPath)
		stat, ok := f.Sys().(*syscall.Stat_t)
		if !ok {
			return fmt.Errorf("Unable to get raw syscall.Stat_t data for %s", srcPath)
		}

		isHardlink := false

		switch mode := f.Mode(); {
		case mode.IsRegular():
			id := fileID{dev: uint64(stat.Dev), ino: stat.Ino}
			if copyMode == Hardlink {
				isHardlink = true
				if err2 := os.Link(srcPath, dstPath); err2 != nil {
					return err2
				}
			} else if hardLinkDstPath, ok := copiedFiles[id]; ok {
				if err2 := os.Link(hardLinkDstPath, dstPath); err2 != nil {
					return err2
				}
			} else {
				if err2 := CopyRegular(srcPath, dstPath, f, &copyWithFileRange, &copyWithFileClone); err2 != nil {
					return err2
				}
				copiedFiles[id] = dstPath
			}

		case mode.IsDir():
			if err := os.Mkdir(dstPath, f.Mode()); err != nil && !os.IsExist(err) {
				return err
			}

		case mode&os.ModeSymlink != 0:
			link, err := os.Readlink(srcPath)
			if err != nil {
				return err
			}

			if err := os.Symlink(link, dstPath); err != nil {
				return err
			}

		case mode&os.ModeNamedPipe != 0:
			if err := unix.Mkfifo(dstPath, stat.Mode); err != nil {
				return err
			}

		case mode&os.ModeSocket != 0:
			s, err := net.Listen("unix", dstPath)
			if err != nil {
				return err
			}
			s.Close()

		case mode&os.ModeDevice != 0:
			if rsystem.RunningInUserNS() {
				// cannot create a device if running in user namespace
				return nil
			}
			if err := unix.Mknod(dstPath, stat.Mode, int(stat.Rdev)); err != nil {
				return err
			}

		default:
			return fmt.Errorf("unknown file type with mode %v for %s", mode, srcPath)
		}

		// Everything below is copying metadata from src to dst. All this metadata
		// already shares an inode for hardlinks.
		if isHardlink {
			return nil
		}

		if err := idtools.SafeLchown(dstPath, int(stat.Uid), int(stat.Gid)); err != nil {
			return err
		}

		if copyXattrs {
			if err := doCopyXattrs(srcPath, dstPath); err != nil {
				return err
			}
		}

		isSymlink := f.Mode()&os.ModeSymlink != 0

		// There is no LChmod, so ignore mode for symlink. Also, this
		// must happen after chown, as that can modify the file mode
		if !isSymlink {
			if err := os.Chmod(dstPath, f.Mode()); err != nil {
				return err
			}
		}

		// system.Chtimes doesn't support a NOFOLLOW flag atm
		// nolint: unconvert
		if f.IsDir() {
			dirsToSetMtimes.PushFront(&dirMtimeInfo{dstPath: &dstPath, stat: stat})
		} else if !isSymlink {
			aTime := time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec))
			mTime := time.Unix(int64(stat.Mtim.Sec), int64(stat.Mtim.Nsec))
			if err := system.Chtimes(dstPath, aTime, mTime); err != nil {
				return err
			}
		} else {
			ts := []syscall.Timespec{stat.Atim, stat.Mtim}
			if err := system.LUtimesNano(dstPath, ts); err != nil {
				return err
			}
		}
		return nil
	})
	if err != nil {
		return err
	}
	for e := dirsToSetMtimes.Front(); e != nil; e = e.Next() {
		mtimeInfo := e.Value.(*dirMtimeInfo)
		ts := []syscall.Timespec{mtimeInfo.stat.Atim, mtimeInfo.stat.Mtim}
		if err := system.LUtimesNano(*mtimeInfo.dstPath, ts); err != nil {
			return err
		}
	}

	return nil
}

func doCopyXattrs(srcPath, dstPath string) error {
	if err := copyXattr(srcPath, dstPath, "security.capability"); err != nil {
		return err
	}

	xattrs, err := system.Llistxattr(srcPath)
	if err != nil && !errors.Is(err, unix.EOPNOTSUPP) {
		return err
	}

	for _, key := range xattrs {
		if strings.HasPrefix(key, "user.") {
			if err := copyXattr(srcPath, dstPath, key); err != nil {
				return err
			}
		}
	}

	// We need to copy this attribute if it appears in an overlay upper layer, as
	// this function is used to copy those. It is set by overlay if a directory
	// is removed and then re-created and should not inherit anything from the
	// same dir in the lower dir.
	return copyXattr(srcPath, dstPath, "trusted.overlay.opaque")
}
<|endoftext|>


<commit_before>package droplet_runner_test

import (
	"errors"
	"io/ioutil"
	"os"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"github.com/cloudfoundry-incubator/lattice/ltc/config/blob_store"
	"github.com/cloudfoundry-incubator/lattice/ltc/config/blob_store/fake_blob_bucket"
	"github.com/cloudfoundry-incubator/lattice/ltc/config/blob_store/fake_blob_store"
	"github.com/cloudfoundry-incubator/lattice/ltc/droplet_runner"
)

var _ = Describe("DropletRunner", func() {

	var (
		fakeBlobStore  *fake_blob_store.FakeBlobStore
		fakeBlobBucket *fake_blob_bucket.FakeBlobBucket
		dropletRunner  droplet_runner.DropletRunner
	)

	BeforeEach(func() {
		fakeBlobStore = new(fake_blob_store.FakeBlobStore)
		fakeBlobBucket = new(fake_blob_bucket.FakeBlobBucket)
		dropletRunner = droplet_runner.New(fakeBlobStore, fakeBlobBucket)
	})

	Describe("UploadBits", func() {
		Context("when the archive path is a file and exists", func() {
			var (
				tmpFile *os.File
				err     error
			)

			BeforeEach(func() {
				tmpDir := os.TempDir()
				tmpFile, err = ioutil.TempFile(tmpDir, "tmp_file")
				Expect(err).NotTo(HaveOccurred())

				err = ioutil.WriteFile(tmpFile.Name(), []byte(`{"Value":"test value"}`), 0700)
				Expect(err).NotTo(HaveOccurred())
			})

			AfterEach(func() {
				Expect(os.Remove(tmpFile.Name())).To(Succeed())
			})

			It("uploads the file to the bucket", func() {
				err = dropletRunner.UploadBits("droplet-name", tmpFile.Name())

				Expect(err).NotTo(HaveOccurred())

				Expect(fakeBlobBucket.PutReaderCallCount()).To(Equal(1))
				path, reader, length, contType, perm, options := fakeBlobBucket.PutReaderArgsForCall(0)
				Expect(path).To(Equal("droplet-name"))
				Expect(reader).ToNot(BeNil())
				Expect(length).ToNot(BeZero())
				Expect(contType).To(Equal(blob_store.DropletContentType))
				Expect(perm).To(Equal(blob_store.DefaultPrivilege))
				Expect(options).To(BeZero())
			})

			It("errors when Bucket.PutReader fails", func() {
				fakeBlobBucket.PutReaderReturns(errors.New("winter is coming yo"))

				err = dropletRunner.UploadBits("droplet-name", tmpFile.Name())

				Expect(err).To(MatchError("winter is coming yo"))
				Expect(fakeBlobBucket.PutReaderCallCount()).To(Equal(1))
			})
		})

		It("errors when file cannot be Stat'ed", func() {
			// name doesn't match file descriptor
			osFile := os.NewFile(os.Stdout.Fd(), "new-file-yo")

			err := dropletRunner.UploadBits("droplet-name", osFile.Name())

			Expect(err).To(HaveOccurred())
			Expect(fakeBlobBucket.PutReaderCallCount()).To(BeZero())
		})

		It("errors when file can be Stat'ed but not Opened", func() {
			tmpFile, err := ioutil.TempFile(os.TempDir(), "stat")
			Expect(err).ToNot(HaveOccurred())

			Expect(os.Chmod(tmpFile.Name(), 0)).To(Succeed())

			err = dropletRunner.UploadBits("droplet-name", tmpFile.Name())

			Expect(err).To(HaveOccurred())
			Expect(fakeBlobBucket.PutReaderCallCount()).To(BeZero())
		})
	})

})
<commit_msg>Commented test that doesn't work when run as root on CI.<commit_after>package droplet_runner_test

import (
	"errors"
	"io/ioutil"
	"os"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"github.com/cloudfoundry-incubator/lattice/ltc/config/blob_store"
	"github.com/cloudfoundry-incubator/lattice/ltc/config/blob_store/fake_blob_bucket"
	"github.com/cloudfoundry-incubator/lattice/ltc/config/blob_store/fake_blob_store"
	"github.com/cloudfoundry-incubator/lattice/ltc/droplet_runner"
)

var _ = Describe("DropletRunner", func() {

	var (
		fakeBlobStore  *fake_blob_store.FakeBlobStore
		fakeBlobBucket *fake_blob_bucket.FakeBlobBucket
		dropletRunner  droplet_runner.DropletRunner
	)

	BeforeEach(func() {
		fakeBlobStore = new(fake_blob_store.FakeBlobStore)
		fakeBlobBucket = new(fake_blob_bucket.FakeBlobBucket)
		dropletRunner = droplet_runner.New(fakeBlobStore, fakeBlobBucket)
	})

	Describe("UploadBits", func() {
		Context("when the archive path is a file and exists", func() {
			var (
				tmpFile *os.File
				err     error
			)

			BeforeEach(func() {
				tmpDir := os.TempDir()
				tmpFile, err = ioutil.TempFile(tmpDir, "tmp_file")
				Expect(err).NotTo(HaveOccurred())

				err = ioutil.WriteFile(tmpFile.Name(), []byte(`{"Value":"test value"}`), 0700)
				Expect(err).NotTo(HaveOccurred())
			})

			AfterEach(func() {
				Expect(os.Remove(tmpFile.Name())).To(Succeed())
			})

			It("uploads the file to the bucket", func() {
				err = dropletRunner.UploadBits("droplet-name", tmpFile.Name())

				Expect(err).NotTo(HaveOccurred())

				Expect(fakeBlobBucket.PutReaderCallCount()).To(Equal(1))
				path, reader, length, contType, perm, options := fakeBlobBucket.PutReaderArgsForCall(0)
				Expect(path).To(Equal("droplet-name"))
				Expect(reader).ToNot(BeNil())
				Expect(length).ToNot(BeZero())
				Expect(contType).To(Equal(blob_store.DropletContentType))
				Expect(perm).To(Equal(blob_store.DefaultPrivilege))
				Expect(options).To(BeZero())
			})

			It("errors when Bucket.PutReader fails", func() {
				fakeBlobBucket.PutReaderReturns(errors.New("winter is coming yo"))

				err = dropletRunner.UploadBits("droplet-name", tmpFile.Name())

				Expect(err).To(MatchError("winter is coming yo"))
				Expect(fakeBlobBucket.PutReaderCallCount()).To(Equal(1))
			})
		})

		It("errors when file cannot be Stat'ed", func() {
			// name doesn't match file descriptor
			osFile := os.NewFile(os.Stdout.Fd(), "new-file-yo")

			err := dropletRunner.UploadBits("droplet-name", osFile.Name())

			Expect(err).To(HaveOccurred())
			Expect(fakeBlobBucket.PutReaderCallCount()).To(BeZero())
		})

		// FIXME: This strategy doesn't work when run as root on CI.
		//
		// It("errors when file can be Stat'ed but not Opened", func() {
		// 	tmpFile, err := ioutil.TempFile(os.TempDir(), "stat")
		// 	Expect(err).ToNot(HaveOccurred())

		// 	Expect(os.Chmod(tmpFile.Name(), 0)).To(Succeed())

		// 	err = dropletRunner.UploadBits("droplet-name", tmpFile.Name())

		// 	Expect(err).To(HaveOccurred())
		// 	Expect(fakeBlobBucket.PutReaderCallCount()).To(BeZero())
		// })
	})

})
<|endoftext|>


<commit_before>package tests

import (
	"os"
	"testing"

	"github.com/ktrysmt/go-bitbucket"
)

var (
	user  = os.Getenv("BITBUCKET_TEST_USERNAME")
	pass  = os.Getenv("BITBUCKET_TEST_PASSWORD")
	owner = os.Getenv("BITBUCKET_TEST_OWNER")
	repo  = os.Getenv("BITBUCKET_TEST_REPOSLUG")
)

func setup(t *testing.T) *bitbucket.Client {

	if user == "" {
		t.Error("BITBUCKET_TEST_USERNAME is empty.")
	}
	if pass == "" {
		t.Error("BITBUCKET_TEST_PASSWORD is empty.")
	}
	if owner == "" {
		t.Error("BITBUCKET_TEST_OWNER is empty.")
	}
	if repo == "" {
		t.Error("BITBUCKET_TEST_REPOSLUG is empty.")
	}

	c := bitbucket.NewBasicAuth(user, pass)
	return c
}

func TestCreateBranchRestrictionsKindPush(t *testing.T) {

	c := setup(t)

	opt := &bitbucket.BranchRestrictionsOptions{
		Owner:    owner,
		Pattern:  "develop",
		RepoSlug: repo,
		Kind:     "push",
		Users:    []string{user},
	}
	res, err := c.Repositories.BranchRestrictions.Create(opt)
	if err != nil {
		t.Error(err)
	}
	if res.Kind != "push" {
		t.Error("did not match branchrestriction kind")
	}
}

func TestCreateBranchRestrictionsKindRequirePassingBuilds(t *testing.T) {

	c := setup(t)

	opt := &bitbucket.BranchRestrictionsOptions{
		Owner:    owner,
		Pattern:  "master",
		RepoSlug: repo,
		Kind:     "require_passing_builds_to_merge",
		Value:    2,
	}
	res, err := c.Repositories.BranchRestrictions.Create(opt)
	if err != nil {
		t.Error(err)
	}
	if res.Kind != "require_passing_builds_to_merge" {
		t.Error("did not match branchrestriction kind")
	}
}
<commit_msg>Add tests for deletion of branch restriction (#148)<commit_after>package tests

import (
	"os"
	"strconv"
	"testing"

	"github.com/ktrysmt/go-bitbucket"
)

var (
	user  = os.Getenv("BITBUCKET_TEST_USERNAME")
	pass  = os.Getenv("BITBUCKET_TEST_PASSWORD")
	owner = os.Getenv("BITBUCKET_TEST_OWNER")
	repo  = os.Getenv("BITBUCKET_TEST_REPOSLUG")
)

func setup(t *testing.T) *bitbucket.Client {

	if user == "" {
		t.Error("BITBUCKET_TEST_USERNAME is empty.")
	}
	if pass == "" {
		t.Error("BITBUCKET_TEST_PASSWORD is empty.")
	}
	if owner == "" {
		t.Error("BITBUCKET_TEST_OWNER is empty.")
	}
	if repo == "" {
		t.Error("BITBUCKET_TEST_REPOSLUG is empty.")
	}

	c := bitbucket.NewBasicAuth(user, pass)
	return c
}

func TestBranchRestrictionsKindPush(t *testing.T) {

	c := setup(t)
	var pushRestrictionID int

	t.Run("create", func(t *testing.T) {
		opt := &bitbucket.BranchRestrictionsOptions{
			Owner:    owner,
			Pattern:  "develop",
			RepoSlug: repo,
			Kind:     "push",
			Users:    []string{user},
		}
		res, err := c.Repositories.BranchRestrictions.Create(opt)
		if err != nil {
			t.Error(err)
		}
		if res.Kind != "push" {
			t.Error("did not match branchrestriction kind")
		}
		pushRestrictionID = res.ID
	})

	t.Run("delete", func(t *testing.T) {
		opt := &bitbucket.BranchRestrictionsOptions{
			Owner:    owner,
			RepoSlug: repo,
			ID:       strconv.Itoa(pushRestrictionID),
		}
		_, err := c.Repositories.BranchRestrictions.Delete(opt)
		if err != nil {
			t.Error(err)
		}
	})
}

func TestBranchRestrictionsKindRequirePassingBuilds(t *testing.T) {

	c := setup(t)
	var pushRestrictionID int

	t.Run("create", func(t *testing.T) {
		opt := &bitbucket.BranchRestrictionsOptions{
			Owner:    owner,
			Pattern:  "master",
			RepoSlug: repo,
			Kind:     "require_passing_builds_to_merge",
			Value:    2,
		}
		res, err := c.Repositories.BranchRestrictions.Create(opt)
		if err != nil {
			t.Error(err)
		}
		if res.Kind != "require_passing_builds_to_merge" {
			t.Error("did not match branchrestriction kind")
		}
		pushRestrictionID = res.ID
	})

	t.Run("delete", func(t *testing.T) {
		opt := &bitbucket.BranchRestrictionsOptions{
			Owner:    owner,
			RepoSlug: repo,
			ID:       strconv.Itoa(pushRestrictionID),
		}
		_, err := c.Repositories.BranchRestrictions.Delete(opt)
		if err != nil {
			t.Error(err)
		}
	})
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package thrift

import (
	"bytes"
	"io/ioutil"

	"github.com/yarpc/yarpc-go/internal/encoding"
	"github.com/yarpc/yarpc-go/transport"

	"github.com/thriftrw/thriftrw-go/protocol"
	"github.com/thriftrw/thriftrw-go/wire"
	"golang.org/x/net/context"
)

// thriftHandler wraps a Thrift Handler into a transport.Handler
type thriftHandler struct {
	Handler  Handler
	Protocol protocol.Protocol
}

func (t thriftHandler) Handle(ctx context.Context, treq *transport.Request, rw transport.ResponseWriter) error {
	treq.Encoding = Encoding
	// TODO(abg): Should we fail requests if Rpc-Encoding does not match?

	body, err := ioutil.ReadAll(treq.Body)
	if err != nil {
		return err
	}

	reqBody, err := t.Protocol.Decode(bytes.NewReader(body), wire.TStruct)
	if err != nil {
		return encoding.RequestBodyDecodeError(treq, err)
	}

	resBody, response, err := t.Handler.Handle(&Request{
		Context: ctx,
		Headers: treq.Headers,
		TTL:     treq.TTL,
	}, reqBody)

	if response != nil {
		rw.AddHeaders(response.Headers)
	}

	if err := t.Protocol.Encode(resBody, rw); err != nil {
		return encoding.ResponseBodyEncodeError(treq, err)
	}

	return nil
}
<commit_msg>thrift: Handle unexpected errors in handlers (#146)<commit_after>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package thrift

import (
	"bytes"
	"io/ioutil"

	"github.com/yarpc/yarpc-go/internal/encoding"
	"github.com/yarpc/yarpc-go/transport"

	"github.com/thriftrw/thriftrw-go/protocol"
	"github.com/thriftrw/thriftrw-go/wire"
	"golang.org/x/net/context"
)

// thriftHandler wraps a Thrift Handler into a transport.Handler
type thriftHandler struct {
	Handler  Handler
	Protocol protocol.Protocol
}

func (t thriftHandler) Handle(ctx context.Context, treq *transport.Request, rw transport.ResponseWriter) error {
	treq.Encoding = Encoding
	// TODO(abg): Should we fail requests if Rpc-Encoding does not match?

	body, err := ioutil.ReadAll(treq.Body)
	if err != nil {
		return err
	}

	reqBody, err := t.Protocol.Decode(bytes.NewReader(body), wire.TStruct)
	if err != nil {
		return encoding.RequestBodyDecodeError(treq, err)
	}

	resBody, response, err := t.Handler.Handle(&Request{
		Context: ctx,
		Headers: treq.Headers,
		TTL:     treq.TTL,
	}, reqBody)
	if err != nil {
		return err
	}

	if response != nil {
		rw.AddHeaders(response.Headers)
	}

	if err := t.Protocol.Encode(resBody, rw); err != nil {
		return encoding.ResponseBodyEncodeError(treq, err)
	}

	return nil
}
<|endoftext|>


<commit_before>package jujutest

import (
	"bytes"
	"io"
	"io/ioutil"
	. "launchpad.net/gocheck"
	"launchpad.net/juju-core/constraints"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/juju/testing"
	"launchpad.net/juju-core/state"
	coretesting "launchpad.net/juju-core/testing"
	"launchpad.net/juju-core/trivial"
	"net/http"
	"sort"
)

// TestConfig contains the configuration for the environment
// This is a is an indirection to make it harder for tests to accidentally
// share the underlying map.
type TestConfig struct {
	Config map[string]interface{}
}

// UpdateConfig modifies the configuration safely by creating a new map
func (testConfig *TestConfig) UpdateConfig(update map[string]interface{}) {
	newConfig := map[string]interface{}{}
	for key, val := range testConfig.Config {
		newConfig[key] = val
	}
	for key, val := range update {
		newConfig[key] = val
	}
	testConfig.Config = newConfig
}

// Tests is a gocheck suite containing tests verifying juju functionality
// against the environment with the given configuration. The
// tests are not designed to be run against a live server - the Environ
// is opened once for each test, and some potentially expensive operations
// may be executed.
type Tests struct {
	coretesting.LoggingSuite
	TestConfig TestConfig
	Env        environs.Environ
}

// Open opens an instance of the testing environment.
func (t *Tests) Open(c *C) environs.Environ {
	e, err := environs.NewFromAttrs(t.TestConfig.Config)
	c.Assert(err, IsNil, Commentf("opening environ %#v", t.TestConfig.Config))
	c.Assert(e, NotNil)
	return e
}

func (t *Tests) SetUpTest(c *C) {
	t.LoggingSuite.SetUpTest(c)
	t.Env = t.Open(c)
}

func (t *Tests) TearDownTest(c *C) {
	if t.Env != nil {
		err := t.Env.Destroy(nil)
		c.Check(err, IsNil)
		t.Env = nil
	}
	t.LoggingSuite.TearDownTest(c)
}

func (t *Tests) TestBootstrapWithoutAdminSecret(c *C) {
	m := t.Env.Config().AllAttrs()
	delete(m, "admin-secret")
	env, err := environs.NewFromAttrs(m)
	c.Assert(err, IsNil)
	err = environs.Bootstrap(env, constraints.Value{})
	c.Assert(err, ErrorMatches, ".*admin-secret is required for bootstrap")
}

func (t *Tests) TestProviderAssignmentPolicy(c *C) {
	e := t.Open(c)
	policy := e.AssignmentPolicy()
	c.Assert(policy, FitsTypeOf, state.AssignNew)
}

func (t *Tests) TestStartStop(c *C) {
	e := t.Open(c)

	insts, err := e.Instances(nil)
	c.Assert(err, IsNil)
	c.Assert(insts, HasLen, 0)

	inst0 := testing.StartInstance(c, e, "0")
	c.Assert(inst0, NotNil)
	id0 := inst0.Id()

	inst1 := testing.StartInstance(c, e, "1")
	c.Assert(inst1, NotNil)
	id1 := inst1.Id()

	insts, err = e.Instances([]state.InstanceId{id0, id1})
	c.Assert(err, IsNil)
	c.Assert(insts, HasLen, 2)
	c.Assert(insts[0].Id(), Equals, id0)
	c.Assert(insts[1].Id(), Equals, id1)

	// order of results is not specified
	insts, err = e.AllInstances()
	c.Assert(err, IsNil)
	c.Assert(insts, HasLen, 2)
	c.Assert(insts[0].Id(), Not(Equals), insts[1].Id())

	err = e.StopInstances([]environs.Instance{inst0})
	c.Assert(err, IsNil)

	insts, err = e.Instances([]state.InstanceId{id0, id1})
	c.Assert(err, Equals, environs.ErrPartialInstances)
	c.Assert(insts[0], IsNil)
	c.Assert(insts[1].Id(), Equals, id1)

	insts, err = e.AllInstances()
	c.Assert(err, IsNil)
	c.Assert(insts[0].Id(), Equals, id1)
}

func (t *Tests) TestBootstrap(c *C) {
	// TODO tests for Bootstrap(true)
	e := t.Open(c)
	err := environs.Bootstrap(e, constraints.Value{})
	c.Assert(err, IsNil)

	info, apiInfo, err := e.StateInfo()
	c.Check(info.Addrs, Not(HasLen), 0)
	c.Check(apiInfo.Addrs, Not(HasLen), 0)

	err = environs.Bootstrap(e, constraints.Value{})
	c.Assert(err, ErrorMatches, "environment is already bootstrapped")

	e2 := t.Open(c)
	err = environs.Bootstrap(e2, constraints.Value{})
	c.Assert(err, ErrorMatches, "environment is already bootstrapped")

	info2, apiInfo2, err := e2.StateInfo()
	c.Check(info2, DeepEquals, info)
	c.Check(apiInfo2, DeepEquals, apiInfo)

	err = e2.Destroy(nil)
	c.Assert(err, IsNil)

	// Open again because Destroy invalidates old environments.
	e3 := t.Open(c)

	err = environs.Bootstrap(e3, constraints.Value{})
	c.Assert(err, IsNil)

	err = environs.Bootstrap(e3, constraints.Value{})
	c.Assert(err, NotNil)
}

var noRetry = trivial.AttemptStrategy{}

func (t *Tests) TestPersistence(c *C) {
	storage := t.Open(c).Storage()

	names := []string{
		"aa",
		"zzz/aa",
		"zzz/bb",
	}
	for _, name := range names {
		checkFileDoesNotExist(c, storage, name, noRetry)
		checkPutFile(c, storage, name, []byte(name))
	}
	checkList(c, storage, "", names)
	checkList(c, storage, "a", []string{"aa"})
	checkList(c, storage, "zzz/", []string{"zzz/aa", "zzz/bb"})

	storage2 := t.Open(c).Storage()
	for _, name := range names {
		checkFileHasContents(c, storage2, name, []byte(name), noRetry)
	}

	// remove the first file and check that the others remain.
	err := storage2.Remove(names[0])
	c.Check(err, IsNil)

	// check that it's ok to remove a file twice.
	err = storage2.Remove(names[0])
	c.Check(err, IsNil)

	// ... and check it's been removed in the other environment
	checkFileDoesNotExist(c, storage, names[0], noRetry)

	// ... and that the rest of the files are still around
	checkList(c, storage2, "", names[1:])

	for _, name := range names[1:] {
		err := storage2.Remove(name)
		c.Assert(err, IsNil)
	}

	// check they've all gone
	checkList(c, storage2, "", nil)
}

func checkList(c *C, storage environs.StorageReader, prefix string, names []string) {
	lnames, err := storage.List(prefix)
	c.Assert(err, IsNil)
	// TODO(dfc) gocheck should grow an SliceEquals checker.
	expected := copyslice(lnames)
	sort.Strings(expected)
	actual := copyslice(names)
	sort.Strings(actual)
	c.Assert(expected, DeepEquals, actual)
}

// copyslice returns a copy of the slice
func copyslice(s []string) []string {
	r := make([]string, len(s))
	copy(r, s)
	return r
}

func checkPutFile(c *C, storage environs.StorageWriter, name string, contents []byte) {
	err := storage.Put(name, bytes.NewBuffer(contents), int64(len(contents)))
	c.Assert(err, IsNil)
}

func checkFileDoesNotExist(c *C, storage environs.StorageReader, name string, attempt trivial.AttemptStrategy) {
	var r io.ReadCloser
	var err error
	for a := attempt.Start(); a.Next(); {
		r, err = storage.Get(name)
		if err != nil {
			break
		}
	}
	c.Assert(r, IsNil)
	var notFoundError *environs.NotFoundError
	c.Assert(err, FitsTypeOf, notFoundError)
}

func checkFileHasContents(c *C, storage environs.StorageReader, name string, contents []byte, attempt trivial.AttemptStrategy) {
	r, err := storage.Get(name)
	c.Assert(err, IsNil)
	c.Check(r, NotNil)
	defer r.Close()

	data, err := ioutil.ReadAll(r)
	c.Check(err, IsNil)
	c.Check(data, DeepEquals, contents)

	url, err := storage.URL(name)
	c.Assert(err, IsNil)

	var resp *http.Response
	for a := attempt.Start(); a.Next(); {
		resp, err = http.Get(url)
		c.Assert(err, IsNil)
		if resp.StatusCode != 404 {
			break
		}
		c.Logf("get retrying after earlier get succeeded. *sigh*.")
	}
	c.Assert(err, IsNil)
	data, err = ioutil.ReadAll(resp.Body)
	c.Assert(err, IsNil)
	defer resp.Body.Close()
	c.Assert(resp.StatusCode, Equals, 200, Commentf("error response: %s", data))
	c.Check(data, DeepEquals, contents)
}
<commit_msg>Remove bogus test.<commit_after>package jujutest

import (
	"bytes"
	"io"
	"io/ioutil"
	. "launchpad.net/gocheck"
	"launchpad.net/juju-core/constraints"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/juju/testing"
	"launchpad.net/juju-core/state"
	coretesting "launchpad.net/juju-core/testing"
	"launchpad.net/juju-core/trivial"
	"net/http"
	"sort"
)

// TestConfig contains the configuration for the environment
// This is a is an indirection to make it harder for tests to accidentally
// share the underlying map.
type TestConfig struct {
	Config map[string]interface{}
}

// UpdateConfig modifies the configuration safely by creating a new map
func (testConfig *TestConfig) UpdateConfig(update map[string]interface{}) {
	newConfig := map[string]interface{}{}
	for key, val := range testConfig.Config {
		newConfig[key] = val
	}
	for key, val := range update {
		newConfig[key] = val
	}
	testConfig.Config = newConfig
}

// Tests is a gocheck suite containing tests verifying juju functionality
// against the environment with the given configuration. The
// tests are not designed to be run against a live server - the Environ
// is opened once for each test, and some potentially expensive operations
// may be executed.
type Tests struct {
	coretesting.LoggingSuite
	TestConfig TestConfig
	Env        environs.Environ
}

// Open opens an instance of the testing environment.
func (t *Tests) Open(c *C) environs.Environ {
	e, err := environs.NewFromAttrs(t.TestConfig.Config)
	c.Assert(err, IsNil, Commentf("opening environ %#v", t.TestConfig.Config))
	c.Assert(e, NotNil)
	return e
}

func (t *Tests) SetUpTest(c *C) {
	t.LoggingSuite.SetUpTest(c)
	t.Env = t.Open(c)
}

func (t *Tests) TearDownTest(c *C) {
	if t.Env != nil {
		err := t.Env.Destroy(nil)
		c.Check(err, IsNil)
		t.Env = nil
	}
	t.LoggingSuite.TearDownTest(c)
}

func (t *Tests) TestBootstrapWithoutAdminSecret(c *C) {
	m := t.Env.Config().AllAttrs()
	delete(m, "admin-secret")
	env, err := environs.NewFromAttrs(m)
	c.Assert(err, IsNil)
	err = environs.Bootstrap(env, constraints.Value{})
	c.Assert(err, ErrorMatches, ".*admin-secret is required for bootstrap")
}

func (t *Tests) TestStartStop(c *C) {
	e := t.Open(c)

	insts, err := e.Instances(nil)
	c.Assert(err, IsNil)
	c.Assert(insts, HasLen, 0)

	inst0 := testing.StartInstance(c, e, "0")
	c.Assert(inst0, NotNil)
	id0 := inst0.Id()

	inst1 := testing.StartInstance(c, e, "1")
	c.Assert(inst1, NotNil)
	id1 := inst1.Id()

	insts, err = e.Instances([]state.InstanceId{id0, id1})
	c.Assert(err, IsNil)
	c.Assert(insts, HasLen, 2)
	c.Assert(insts[0].Id(), Equals, id0)
	c.Assert(insts[1].Id(), Equals, id1)

	// order of results is not specified
	insts, err = e.AllInstances()
	c.Assert(err, IsNil)
	c.Assert(insts, HasLen, 2)
	c.Assert(insts[0].Id(), Not(Equals), insts[1].Id())

	err = e.StopInstances([]environs.Instance{inst0})
	c.Assert(err, IsNil)

	insts, err = e.Instances([]state.InstanceId{id0, id1})
	c.Assert(err, Equals, environs.ErrPartialInstances)
	c.Assert(insts[0], IsNil)
	c.Assert(insts[1].Id(), Equals, id1)

	insts, err = e.AllInstances()
	c.Assert(err, IsNil)
	c.Assert(insts[0].Id(), Equals, id1)
}

func (t *Tests) TestBootstrap(c *C) {
	// TODO tests for Bootstrap(true)
	e := t.Open(c)
	err := environs.Bootstrap(e, constraints.Value{})
	c.Assert(err, IsNil)

	info, apiInfo, err := e.StateInfo()
	c.Check(info.Addrs, Not(HasLen), 0)
	c.Check(apiInfo.Addrs, Not(HasLen), 0)

	err = environs.Bootstrap(e, constraints.Value{})
	c.Assert(err, ErrorMatches, "environment is already bootstrapped")

	e2 := t.Open(c)
	err = environs.Bootstrap(e2, constraints.Value{})
	c.Assert(err, ErrorMatches, "environment is already bootstrapped")

	info2, apiInfo2, err := e2.StateInfo()
	c.Check(info2, DeepEquals, info)
	c.Check(apiInfo2, DeepEquals, apiInfo)

	err = e2.Destroy(nil)
	c.Assert(err, IsNil)

	// Open again because Destroy invalidates old environments.
	e3 := t.Open(c)

	err = environs.Bootstrap(e3, constraints.Value{})
	c.Assert(err, IsNil)

	err = environs.Bootstrap(e3, constraints.Value{})
	c.Assert(err, NotNil)
}

var noRetry = trivial.AttemptStrategy{}

func (t *Tests) TestPersistence(c *C) {
	storage := t.Open(c).Storage()

	names := []string{
		"aa",
		"zzz/aa",
		"zzz/bb",
	}
	for _, name := range names {
		checkFileDoesNotExist(c, storage, name, noRetry)
		checkPutFile(c, storage, name, []byte(name))
	}
	checkList(c, storage, "", names)
	checkList(c, storage, "a", []string{"aa"})
	checkList(c, storage, "zzz/", []string{"zzz/aa", "zzz/bb"})

	storage2 := t.Open(c).Storage()
	for _, name := range names {
		checkFileHasContents(c, storage2, name, []byte(name), noRetry)
	}

	// remove the first file and check that the others remain.
	err := storage2.Remove(names[0])
	c.Check(err, IsNil)

	// check that it's ok to remove a file twice.
	err = storage2.Remove(names[0])
	c.Check(err, IsNil)

	// ... and check it's been removed in the other environment
	checkFileDoesNotExist(c, storage, names[0], noRetry)

	// ... and that the rest of the files are still around
	checkList(c, storage2, "", names[1:])

	for _, name := range names[1:] {
		err := storage2.Remove(name)
		c.Assert(err, IsNil)
	}

	// check they've all gone
	checkList(c, storage2, "", nil)
}

func checkList(c *C, storage environs.StorageReader, prefix string, names []string) {
	lnames, err := storage.List(prefix)
	c.Assert(err, IsNil)
	// TODO(dfc) gocheck should grow an SliceEquals checker.
	expected := copyslice(lnames)
	sort.Strings(expected)
	actual := copyslice(names)
	sort.Strings(actual)
	c.Assert(expected, DeepEquals, actual)
}

// copyslice returns a copy of the slice
func copyslice(s []string) []string {
	r := make([]string, len(s))
	copy(r, s)
	return r
}

func checkPutFile(c *C, storage environs.StorageWriter, name string, contents []byte) {
	err := storage.Put(name, bytes.NewBuffer(contents), int64(len(contents)))
	c.Assert(err, IsNil)
}

func checkFileDoesNotExist(c *C, storage environs.StorageReader, name string, attempt trivial.AttemptStrategy) {
	var r io.ReadCloser
	var err error
	for a := attempt.Start(); a.Next(); {
		r, err = storage.Get(name)
		if err != nil {
			break
		}
	}
	c.Assert(r, IsNil)
	var notFoundError *environs.NotFoundError
	c.Assert(err, FitsTypeOf, notFoundError)
}

func checkFileHasContents(c *C, storage environs.StorageReader, name string, contents []byte, attempt trivial.AttemptStrategy) {
	r, err := storage.Get(name)
	c.Assert(err, IsNil)
	c.Check(r, NotNil)
	defer r.Close()

	data, err := ioutil.ReadAll(r)
	c.Check(err, IsNil)
	c.Check(data, DeepEquals, contents)

	url, err := storage.URL(name)
	c.Assert(err, IsNil)

	var resp *http.Response
	for a := attempt.Start(); a.Next(); {
		resp, err = http.Get(url)
		c.Assert(err, IsNil)
		if resp.StatusCode != 404 {
			break
		}
		c.Logf("get retrying after earlier get succeeded. *sigh*.")
	}
	c.Assert(err, IsNil)
	data, err = ioutil.ReadAll(resp.Body)
	c.Assert(err, IsNil)
	defer resp.Body.Close()
	c.Assert(resp.StatusCode, Equals, 200, Commentf("error response: %s", data))
	c.Check(data, DeepEquals, contents)
}
<|endoftext|>