<commit_before>/*
Copyright 2021 The Vitess Authors.

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

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

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

package engine

import (
	"vitess.io/vitess/go/sqltypes"
	querypb "vitess.io/vitess/go/vt/proto/query"
	"vitess.io/vitess/go/vt/proto/vtrpc"
	"vitess.io/vitess/go/vt/vterrors"
)

var _ Primitive = (*RenameFields)(nil)

// RenameFields is a primitive that renames the fields
type RenameFields struct {
	Cols    []string
	Indices []int
	Input   Primitive
	noTxNeeded
}

// NewRenameField creates a new rename field
func NewRenameField(cols []string, indices []int, input Primitive) (*RenameFields, error) {
	if len(cols) != len(indices) {
		return nil, vterrors.New(vtrpc.Code_INTERNAL, "Unequal length of columns and indices in RenameField primitive")
	}
	return &RenameFields{
		Cols:    cols,
		Indices: indices,
		Input:   input,
	}, nil
}

// RouteType implements the primitive interface
func (r *RenameFields) RouteType() string {
	return r.Input.RouteType()
}

// GetKeyspaceName implements the primitive interface
func (r *RenameFields) GetKeyspaceName() string {
	return r.Input.GetKeyspaceName()
}

// GetTableName implements the primitive interface
func (r *RenameFields) GetTableName() string {
	return r.Input.GetTableName()
}

// Execute implements the primitive interface
func (r *RenameFields) Execute(vcursor VCursor, bindVars map[string]*querypb.BindVariable, wantfields bool) (*sqltypes.Result, error) {
	qr, err := r.Input.Execute(vcursor, bindVars, wantfields)
	if err != nil {
		return nil, err
	}
	if wantfields {
		r.renameFields(qr)
	}
	return qr, nil
}

func (r *RenameFields) renameFields(qr *sqltypes.Result) {
	for i := 0; i < len(r.Indices) && i < len(qr.Fields); i++ {
		colName := r.Cols[r.Indices[i]]
		qr.Fields[i].Name = colName
	}
}

// StreamExecute implements the primitive interface
func (r *RenameFields) StreamExecute(vcursor VCursor, bindVars map[string]*querypb.BindVariable, wantfields bool, callback func(*sqltypes.Result) error) error {
	if wantfields {
		innerCallback := callback
		callback = func(result *sqltypes.Result) error {
			r.renameFields(result)
			return innerCallback(result)
		}
	}
	return r.Input.StreamExecute(vcursor, bindVars, wantfields, callback)
}

// GetFields implements the primitive interface
func (r *RenameFields) GetFields(vcursor VCursor, bindVars map[string]*querypb.BindVariable) (*sqltypes.Result, error) {
	qr, err := r.Input.GetFields(vcursor, bindVars)
	if err != nil {
		return nil, err
	}
	r.renameFields(qr)
	return qr, nil
}

// Inputs implements the primitive interface
func (r *RenameFields) Inputs() []Primitive {
	return []Primitive{r.Input}
}

// description implements the primitive interface
func (r *RenameFields) description() PrimitiveDescription {
	return PrimitiveDescription{
		OperatorType: "RenameFields",
		Other: map[string]interface{}{
			"Indices": r.Indices,
			"Columns": r.Cols,
		},
	}
}
<commit_msg>Fixing renameFields for loop logic<commit_after>/*
Copyright 2021 The Vitess Authors.

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

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

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

package engine

import (
	"vitess.io/vitess/go/sqltypes"
	querypb "vitess.io/vitess/go/vt/proto/query"
	"vitess.io/vitess/go/vt/proto/vtrpc"
	"vitess.io/vitess/go/vt/vterrors"
)

var _ Primitive = (*RenameFields)(nil)

// RenameFields is a primitive that renames the fields
type RenameFields struct {
	Cols    []string
	Indices []int
	Input   Primitive
	noTxNeeded
}

// NewRenameField creates a new rename field
func NewRenameField(cols []string, indices []int, input Primitive) (*RenameFields, error) {
	if len(cols) != len(indices) {
		return nil, vterrors.New(vtrpc.Code_INTERNAL, "Unequal length of columns and indices in RenameField primitive")
	}
	return &RenameFields{
		Cols:    cols,
		Indices: indices,
		Input:   input,
	}, nil
}

// RouteType implements the primitive interface
func (r *RenameFields) RouteType() string {
	return r.Input.RouteType()
}

// GetKeyspaceName implements the primitive interface
func (r *RenameFields) GetKeyspaceName() string {
	return r.Input.GetKeyspaceName()
}

// GetTableName implements the primitive interface
func (r *RenameFields) GetTableName() string {
	return r.Input.GetTableName()
}

// Execute implements the primitive interface
func (r *RenameFields) Execute(vcursor VCursor, bindVars map[string]*querypb.BindVariable, wantfields bool) (*sqltypes.Result, error) {
	qr, err := r.Input.Execute(vcursor, bindVars, wantfields)
	if err != nil {
		return nil, err
	}
	if wantfields {
		r.renameFields(qr)
	}
	return qr, nil
}

func (r *RenameFields) renameFields(qr *sqltypes.Result) {
	for ind, index := range r.Indices {
		if ind == len(qr.Fields) {
			break
		}
		colName := r.Cols[ind]
		qr.Fields[index].Name = colName
	}
}

// StreamExecute implements the primitive interface
func (r *RenameFields) StreamExecute(vcursor VCursor, bindVars map[string]*querypb.BindVariable, wantfields bool, callback func(*sqltypes.Result) error) error {
	if wantfields {
		innerCallback := callback
		callback = func(result *sqltypes.Result) error {
			r.renameFields(result)
			return innerCallback(result)
		}
	}
	return r.Input.StreamExecute(vcursor, bindVars, wantfields, callback)
}

// GetFields implements the primitive interface
func (r *RenameFields) GetFields(vcursor VCursor, bindVars map[string]*querypb.BindVariable) (*sqltypes.Result, error) {
	qr, err := r.Input.GetFields(vcursor, bindVars)
	if err != nil {
		return nil, err
	}
	r.renameFields(qr)
	return qr, nil
}

// Inputs implements the primitive interface
func (r *RenameFields) Inputs() []Primitive {
	return []Primitive{r.Input}
}

// description implements the primitive interface
func (r *RenameFields) description() PrimitiveDescription {
	return PrimitiveDescription{
		OperatorType: "RenameFields",
		Other: map[string]interface{}{
			"Indices": r.Indices,
			"Columns": r.Cols,
		},
	}
}
<|endoftext|>


<commit_before>package inlet_http

import (
	"encoding/json"
	"io/ioutil"
	"net/http"

	"github.com/go-martini/martini"
	"github.com/gogap/errors"
	"github.com/gogap/logs"
	"github.com/gogap/spirit"
)

const (
	CTX_HTTP_COOKIES = "CTX_HTTP_COOKIES"
	CTX_HTTP_HEADERS = "CTX_HTTP_HEADERS"

	CMD_HTTP_HEADERS_SET = "CMD_HTTP_HEADERS_SET"
	CMD_HTTP_COOKIES_SET = "CMD_HTTP_COOKIES_SET"
)

type NameValue struct {
	Name  string `json:"name"`
	Value string `json:"value"`
}

type InletHTTPResponseHandler func(spirit.Payload, http.ResponseWriter, *http.Request)
type InletHTTPErrorResponseHandler func(error, http.ResponseWriter, *http.Request)

type option func(*InletHTTP)

type InletHTTP struct {
	config         Config
	requester      Requester
	graphProvider  GraphProvider
	respHandler    InletHTTPResponseHandler
	errRespHandler InletHTTPErrorResponseHandler
}

func (p *InletHTTP) Option(opts ...option) {
	for _, opt := range opts {
		opt(p)
	}
}

func SetRequester(requester Requester) option {
	return func(f *InletHTTP) {
		f.requester = requester
	}
}

func SetHTTPConfig(httpConfig Config) option {
	return func(f *InletHTTP) {
		f.config = httpConfig
	}
}

func SetGraphProvider(graphProvider GraphProvider) option {
	return func(f *InletHTTP) {
		f.graphProvider = graphProvider
	}
}

func SetResponseHandler(handler InletHTTPResponseHandler) option {
	return func(f *InletHTTP) {
		f.respHandler = handler
	}
}

func SetErrorResponseHandler(handler InletHTTPErrorResponseHandler) option {
	return func(f *InletHTTP) {
		f.errRespHandler = handler
	}
}

func NewInletHTTP(opts ...option) *InletHTTP {
	inletHTTP := new(InletHTTP)
	inletHTTP.Option(opts...)

	if inletHTTP.requester == nil {
		inletHTTP.requester = NewClassicRequester()
	}

	return inletHTTP
}

func (p *InletHTTP) Requester() Requester {
	return p.requester
}

func (p *InletHTTP) Run(handlers ...martini.Handler) {
	if p.graphProvider == nil {
		panic("graph provider is nil")
	}

	if p.requester == nil {
		panic("requester is nil")
	}

	if p.respHandler == nil {
		panic("response handler is nil")
	}

	if p.errRespHandler == nil {
		panic("error response handler is nil")
	}

	m := martini.Classic()

	if handlers != nil {
		for _, handler := range handlers {
			m.Use(handler)
		}
	}

	m.Use(p.handler)

	if p.config.Address != "" {
		m.RunOnAddr(p.config.Address)
	} else {
		m.Run()
	}
}

func (p *InletHTTP) handler(w http.ResponseWriter, r *http.Request) {
	var err error
	var binBody []byte
	if binBody, err = ioutil.ReadAll(r.Body); err != nil {
		err = ERR_READ_HTTP_BODY_FAILED.New(errors.Params{"err": err})
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	var mapContent map[string]interface{} = make(map[string]interface{})

	if err = json.Unmarshal(binBody, &mapContent); err != nil {
		err = ERR_UNMARSHAL_HTTP_BODY_FAILED.New(errors.Params{"err": err})
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	payload := spirit.Payload{}

	payload.SetContent(mapContent)

	responseChan := make(chan spirit.Payload)
	defer close(responseChan)

	var addrs []spirit.MessageAddress
	if addrs, err = p.graphProvider.GetGraph(r); err != nil {
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	msgId := ""
	msgId, err = p.requester.Request(addrs, payload, responseChan)
	if err != nil {
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	defer p.requester.OnMessageProcessed(msgId)

	var respPayload spirit.Payload

	respPayload = <-responseChan
	//TODO add recv timeout

	p.writeCookiesAndHeaders(respPayload, w, r)
	p.respHandler(respPayload, w, r)
}

func (p *InletHTTP) writeCookiesAndHeaders(payload spirit.Payload, w http.ResponseWriter, r *http.Request) {
	var err error
	// Cookies
	cmdCookiesSize := payload.GetCommandValueSize(CMD_HTTP_COOKIES_SET)
	cmdCookies := make([]interface{}, cmdCookiesSize)
	for i := 0; i < cmdCookiesSize; i++ {
		cookie := new(http.Cookie)
		cmdCookies[i] = cookie
	}

	if err = payload.GetCommandObjectArray(CMD_HTTP_COOKIES_SET, cmdCookies); err != nil {
		err = ERR_PARSE_COMMAND_TO_OBJECT_FAILED.New(errors.Params{"cmd": CMD_HTTP_COOKIES_SET, "err": err})
		p.errRespHandler(err, w, r)
		return
	}

	for _, cookie := range cmdCookies {
		if c, ok := cookie.(*http.Cookie); ok {
			c.Domain = p.config.Domain
			c.Path = "/"
			http.SetCookie(w, c)
		} else {
			err = ERR_PARSE_COMMAND_TO_OBJECT_FAILED.New(errors.Params{"cmd": CMD_HTTP_COOKIES_SET, "err": "object could not parser to cookies"})
			logs.Error(err)
			p.errRespHandler(err, w, r)
			return
		}
	}

	cmdHeadersSize := payload.GetCommandValueSize(CMD_HTTP_HEADERS_SET)
	cmdHeaders := make([]interface{}, cmdHeadersSize)
	for i := 0; i < cmdHeadersSize; i++ {
		header := new(NameValue)
		cmdHeaders[i] = header
	}

	if err = payload.GetCommandObjectArray(CMD_HTTP_HEADERS_SET, cmdHeaders); err != nil {
		err = ERR_PARSE_COMMAND_TO_OBJECT_FAILED.New(errors.Params{"cmd": CMD_HTTP_HEADERS_SET, "err": err})
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	for _, header := range cmdHeaders {
		if nv, ok := header.(*NameValue); ok {
			w.Header().Add(nv.Name, nv.Value)
		} else {
			err = ERR_PARSE_COMMAND_TO_OBJECT_FAILED.New(errors.Params{"cmd": CMD_HTTP_HEADERS_SET, "err": "object could not parser to headers"})
			logs.Error(err)
			p.errRespHandler(err, w, r)
			return
		}
	}
}

func (p *InletHTTP) CallBack(payload *spirit.Payload) (result interface{}, err error) {
	p.OnMessageResponse(*payload)
	return nil, nil
}

func (p *InletHTTP) OnMessageResponse(payload spirit.Payload) {
	if _, e := p.requester.OnMessageReceived(payload); e != nil {
		logs.Error(e)
	}
}
<commit_msg>move out inlet http decoder<commit_after>package inlet_http

import (
	"io/ioutil"
	"net/http"

	"github.com/go-martini/martini"
	"github.com/gogap/errors"
	"github.com/gogap/logs"
	"github.com/gogap/spirit"
)

const (
	CTX_HTTP_COOKIES = "CTX_HTTP_COOKIES"
	CTX_HTTP_HEADERS = "CTX_HTTP_HEADERS"

	CMD_HTTP_HEADERS_SET = "CMD_HTTP_HEADERS_SET"
	CMD_HTTP_COOKIES_SET = "CMD_HTTP_COOKIES_SET"
)

type NameValue struct {
	Name  string `json:"name"`
	Value string `json:"value"`
}

type InletHTTPResponseHandler func(spirit.Payload, http.ResponseWriter, *http.Request)
type InletHTTPErrorResponseHandler func(error, http.ResponseWriter, *http.Request)
type InletHTTPRequestDecoder func([]byte) (map[string]interface{}, error)

type option func(*InletHTTP)

type InletHTTP struct {
	config         Config
	requester      Requester
	graphProvider  GraphProvider
	respHandler    InletHTTPResponseHandler
	errRespHandler InletHTTPErrorResponseHandler
	requestDecoder InletHTTPRequestDecoder
}

func (p *InletHTTP) Option(opts ...option) {
	for _, opt := range opts {
		opt(p)
	}
}

func SetRequestDecoder(decoder InletHTTPRequestDecoder) option {
	return func(f *InletHTTP) {
		f.requestDecoder = decoder
	}
}

func SetRequester(requester Requester) option {
	return func(f *InletHTTP) {
		f.requester = requester
	}
}

func SetHTTPConfig(httpConfig Config) option {
	return func(f *InletHTTP) {
		f.config = httpConfig
	}
}

func SetGraphProvider(graphProvider GraphProvider) option {
	return func(f *InletHTTP) {
		f.graphProvider = graphProvider
	}
}

func SetResponseHandler(handler InletHTTPResponseHandler) option {
	return func(f *InletHTTP) {
		f.respHandler = handler
	}
}

func SetErrorResponseHandler(handler InletHTTPErrorResponseHandler) option {
	return func(f *InletHTTP) {
		f.errRespHandler = handler
	}
}

func NewInletHTTP(opts ...option) *InletHTTP {
	inletHTTP := new(InletHTTP)
	inletHTTP.Option(opts...)

	if inletHTTP.requester == nil {
		inletHTTP.requester = NewClassicRequester()
	}

	return inletHTTP
}

func (p *InletHTTP) Requester() Requester {
	return p.requester
}

func (p *InletHTTP) Run(handlers ...martini.Handler) {
	if p.graphProvider == nil {
		panic("graph provider is nil")
	}

	if p.requester == nil {
		panic("requester is nil")
	}

	if p.respHandler == nil {
		panic("response handler is nil")
	}

	if p.errRespHandler == nil {
		panic("error response handler is nil")
	}

	if p.requestDecoder == nil {
		panic("request encoder is nil")
	}

	m := martini.Classic()

	if handlers != nil {
		for _, handler := range handlers {
			m.Use(handler)
		}
	}

	m.Use(p.handler)

	if p.config.Address != "" {
		m.RunOnAddr(p.config.Address)
	} else {
		m.Run()
	}
}

func (p *InletHTTP) handler(w http.ResponseWriter, r *http.Request) {
	var err error
	var binBody []byte
	if binBody, err = ioutil.ReadAll(r.Body); err != nil {
		err = ERR_READ_HTTP_BODY_FAILED.New(errors.Params{"err": err})
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	var mapContent map[string]interface{}

	if mapContent, err = p.requestDecoder(binBody); err != nil {
		err = ERR_UNMARSHAL_HTTP_BODY_FAILED.New(errors.Params{"err": err})
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	payload := spirit.Payload{}

	payload.SetContent(mapContent)

	responseChan := make(chan spirit.Payload)
	defer close(responseChan)

	var addrs []spirit.MessageAddress
	if addrs, err = p.graphProvider.GetGraph(r); err != nil {
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	msgId := ""
	msgId, err = p.requester.Request(addrs, payload, responseChan)
	if err != nil {
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	defer p.requester.OnMessageProcessed(msgId)

	var respPayload spirit.Payload

	respPayload = <-responseChan
	//TODO add recv timeout

	p.writeCookiesAndHeaders(respPayload, w, r)
	p.respHandler(respPayload, w, r)
}

func (p *InletHTTP) writeCookiesAndHeaders(payload spirit.Payload, w http.ResponseWriter, r *http.Request) {
	var err error
	// Cookies
	cmdCookiesSize := payload.GetCommandValueSize(CMD_HTTP_COOKIES_SET)
	cmdCookies := make([]interface{}, cmdCookiesSize)
	for i := 0; i < cmdCookiesSize; i++ {
		cookie := new(http.Cookie)
		cmdCookies[i] = cookie
	}

	if err = payload.GetCommandObjectArray(CMD_HTTP_COOKIES_SET, cmdCookies); err != nil {
		err = ERR_PARSE_COMMAND_TO_OBJECT_FAILED.New(errors.Params{"cmd": CMD_HTTP_COOKIES_SET, "err": err})
		p.errRespHandler(err, w, r)
		return
	}

	for _, cookie := range cmdCookies {
		if c, ok := cookie.(*http.Cookie); ok {
			c.Domain = p.config.Domain
			c.Path = "/"
			http.SetCookie(w, c)
		} else {
			err = ERR_PARSE_COMMAND_TO_OBJECT_FAILED.New(errors.Params{"cmd": CMD_HTTP_COOKIES_SET, "err": "object could not parser to cookies"})
			logs.Error(err)
			p.errRespHandler(err, w, r)
			return
		}
	}

	cmdHeadersSize := payload.GetCommandValueSize(CMD_HTTP_HEADERS_SET)
	cmdHeaders := make([]interface{}, cmdHeadersSize)
	for i := 0; i < cmdHeadersSize; i++ {
		header := new(NameValue)
		cmdHeaders[i] = header
	}

	if err = payload.GetCommandObjectArray(CMD_HTTP_HEADERS_SET, cmdHeaders); err != nil {
		err = ERR_PARSE_COMMAND_TO_OBJECT_FAILED.New(errors.Params{"cmd": CMD_HTTP_HEADERS_SET, "err": err})
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	for _, header := range cmdHeaders {
		if nv, ok := header.(*NameValue); ok {
			w.Header().Add(nv.Name, nv.Value)
		} else {
			err = ERR_PARSE_COMMAND_TO_OBJECT_FAILED.New(errors.Params{"cmd": CMD_HTTP_HEADERS_SET, "err": "object could not parser to headers"})
			logs.Error(err)
			p.errRespHandler(err, w, r)
			return
		}
	}
}

func (p *InletHTTP) CallBack(payload *spirit.Payload) (result interface{}, err error) {
	p.OnMessageResponse(*payload)
	return nil, nil
}

func (p *InletHTTP) OnMessageResponse(payload spirit.Payload) {
	if _, e := p.requester.OnMessageReceived(payload); e != nil {
		logs.Error(e)
	}
}
<|endoftext|>


<commit_before>package registry

// inmemstore is a non-thread-safe in-memory database for the moment

import "time"

// InMemoryStore implements a non-thread-safe registry of binder templates
type InMemoryStore struct {
	templateMap map[string]Template
}

// NewInMemoryStore create a new InMemoryStore
func NewInMemoryStore() InMemoryStore {
	var store InMemoryStore
	store.templateMap = make(map[string]Template)
	return store
}

// GetTemplate retrieves the template with name, erroring otherwise
func (store InMemoryStore) GetTemplate(name string) (Template, error) {
	tmpl, ok := store.templateMap[name]
	if !ok {
		return Template{}, UnavailableTemplateError
	}

	return tmpl, nil
}

// RegisterTemplate registers the template in the Store
func (store InMemoryStore) RegisterTemplate(tmpl Template) (Template, error) {
	// Ensure tmpl.Name is available
	_, exists := store.templateMap[tmpl.Name]
	if exists {
		// Disallow registration if it exists
		return Template{}, ExistingTemplateError
	}

	// Apply creation times
	tmpl.TimeModified = time.Now().UTC()
	tmpl.TimeCreated = tmpl.TimeModified

	store.templateMap[tmpl.Name] = tmpl
	return tmpl, nil
}

// ListTemplates provides a listing of all registered templates
func (store InMemoryStore) ListTemplates() ([]Template, error) {
	templates := make([]Template, len(store.templateMap))
	i := 0
	for _, tmpl := range store.templateMap {
		templates[i] = tmpl
		i++
	}
	return templates, nil
}

// UpdateTemplate will allow for updating ImageName and Command
func (store InMemoryStore) UpdateTemplate(tmpl Template) (Template, error) {
	updatedTemplate, ok := store.templateMap[tmpl.Name]
	if !ok {
		return Template{}, UnavailableTemplateError
	}

	// For now we allow updates to image name and command
	if tmpl.ImageName != "" {
		updatedTemplate.ImageName = tmpl.ImageName
	}
	if tmpl.Command != "" {
		updatedTemplate.Command = tmpl.Command
	}

	updatedTemplate.TimeModified = time.Now().UTC()

	store.templateMap[tmpl.Name] = updatedTemplate

	return updatedTemplate, nil
}
<commit_msg>Added DeleteTemplate on InMemoryStore<commit_after>package registry

// inmemstore is a non-thread-safe in-memory database for the moment

import "time"

// InMemoryStore implements a non-thread-safe registry of binder templates
type InMemoryStore struct {
	templateMap map[string]Template
}

// NewInMemoryStore create a new InMemoryStore
func NewInMemoryStore() InMemoryStore {
	var store InMemoryStore
	store.templateMap = make(map[string]Template)
	return store
}

// GetTemplate retrieves the template with name, erroring otherwise
func (store InMemoryStore) GetTemplate(name string) (Template, error) {
	tmpl, ok := store.templateMap[name]
	if !ok {
		return Template{}, UnavailableTemplateError
	}

	return tmpl, nil
}

// RegisterTemplate registers the template in the Store
func (store InMemoryStore) RegisterTemplate(tmpl Template) (Template, error) {
	// Ensure tmpl.Name is available
	_, exists := store.templateMap[tmpl.Name]
	if exists {
		// Disallow registration if it exists
		return Template{}, ExistingTemplateError
	}

	// Apply creation times
	tmpl.TimeModified = time.Now().UTC()
	tmpl.TimeCreated = tmpl.TimeModified

	store.templateMap[tmpl.Name] = tmpl
	return tmpl, nil
}

// ListTemplates provides a listing of all registered templates
func (store InMemoryStore) ListTemplates() ([]Template, error) {
	templates := make([]Template, len(store.templateMap))
	i := 0
	for _, tmpl := range store.templateMap {
		templates[i] = tmpl
		i++
	}
	return templates, nil
}

// UpdateTemplate will allow for updating ImageName and Command
func (store InMemoryStore) UpdateTemplate(tmpl Template) (Template, error) {
	updatedTemplate, ok := store.templateMap[tmpl.Name]
	if !ok {
		return Template{}, UnavailableTemplateError
	}

	// For now we allow updates to image name and command
	if tmpl.ImageName != "" {
		updatedTemplate.ImageName = tmpl.ImageName
	}
	if tmpl.Command != "" {
		updatedTemplate.Command = tmpl.Command
	}

	updatedTemplate.TimeModified = time.Now().UTC()

	store.templateMap[tmpl.Name] = updatedTemplate

	return updatedTemplate, nil
}

func (store InMemoryStore) DeleteTemplate(name string) (Template, error) {
    template, ok := store.templateMap[name]
    if !ok {
        return Template{}, UnavailableTemplateError
    }

    delete(store.templateMap, name);

    return template, nil
}
<|endoftext|>


<commit_before>package gocassa

import (
	"time"
)

// The Connection interface only exists because one can not connect to a keyspace if it does not exist, thus having a Create on KeySpace is not possible.
// Use ConnectToKeySpace to acquire an instance of KeySpace.
type Connection interface {
	CreateKeySpace(name string) error
	DropKeySpace(name string) error
	KeySpace(name string) KeySpace
	Batcher
}

type KeySpace interface {
	OneToOneTable(tableName, id string, row interface{}) OneToOneTable
	OneToManyTable(tableName, fieldToIndexBy, uniqueKey string, row interface{}) OneToManyTable
	TimeSeriesTable(tableName, timeField, uniqueKey string, bucketSize time.Duration, row interface{}) TimeSeriesTable
	TimeSeriesBTable(tableName, fieldToIndexByField, timeField, uniqueKey string, bucketSize time.Duration, row interface{}) TimeSeriesBTable
	Table(tableName string, row interface{}, keys Keys) Table
	DebugMode(bool)
	Batcher
}

//
// OneToOne recipe
//

// Simple CRUD interface. You can do CRUD by Id.
type OneToOneTable interface {
	SetWithOptions(v interface{}, opts Options) error
	Set(v interface{}) error
	UpdateWithOptions(id interface{}, m map[string]interface{}, opts Options) error
	Update(id interface{}, m map[string]interface{}) error
	Delete(id interface{}) error
	Read(id, pointer interface{}) error
	MultiRead(ids []interface{}, pointerToASlice interface{}) error
	Batcher
	TableChanger
}

//
// OneToMany recipe
//

// OneToMany lets you list rows based on a field equality, eg. 'list all sales where seller id = v'.
type OneToManyTable interface {
	SetWithOptions(v interface{}, opts Options) error
	Set(v interface{}) error
	UpdateWithOptions(v, id interface{}, m map[string]interface{}, opts Options) error
	Update(v, id interface{}, m map[string]interface{}) error
	Delete(v, id interface{}) error
	DeleteAll(v interface{}) error
	List(v, startId interface{}, limit int, pointerToASlice interface{}) error
	Read(v, id, pointer interface{}) error
	MultiRead(id interface{}, ids []interface{}, pointerToASlice interface{}) error
	Batcher
	TableChanger
}

//
// TimeSeries recipe
//

// TimeSeries lets you list rows which have a field value between two date ranges.
type TimeSeriesTable interface {
	// timeField and idField must be present
	SetWithOptions(v interface{}, opts Options) error
	Set(v interface{}) error
	UpdateWithOptions(timeStamp time.Time, id interface{}, m map[string]interface{}, opts Options) error
	Update(timeStamp time.Time, id interface{}, m map[string]interface{}) error
	List(start, end time.Time, pointerToASlice interface{}) error
	Read(timeStamp time.Time, id, pointer interface{}) error
	Delete(timeStamp time.Time, id interface{}) error
	Batcher
	TableChanger
}

//
// TimeSeries B recipe
//

// TimeSeriesB is a cross between TimeSeries and OneToMany tables.
type TimeSeriesBTable interface {
	// timeField and idField must be present
	SetWithOptions(v interface{}, opts Options) error
	Set(v interface{}) error
	UpdateWithOptions(v interface{}, timeStamp time.Time, id interface{}, m map[string]interface{}, opts Options) error
	Update(v interface{}, timeStamp time.Time, id interface{}, m map[string]interface{}) error
	List(v interface{}, start, end time.Time, pointerToASlice interface{}) error
	Read(v interface{}, timeStamp time.Time, id, pointer interface{}) error
	Delete(v interface{}, timeStamp time.Time, id interface{}) error
	Batcher
	TableChanger
}

//
// Raw CQL
//

// A Query is a subset of a Table intended to be read
type Query interface {
	Read(pointerToASlice interface{}) error
	ReadOne(pointer interface{}) error
	Limit(int) Query
}

// A Filter is a subset of a Table, filtered by Relations.
// You can do writes or reads on a filter.
type Filter interface {
	// Selection modifiers
	Query() Query
	// Partial update.
	Update(m map[string]interface{}) error // Probably this is danger zone (can't be implemented efficiently) on a selectuinb with more than 1 document
	UpdateWithOptions(m map[string]interface{}, opts Options) error
	Delete() error
}

type Keys struct {
	PartitionKeys     []string
	ClusteringColumns []string
}

type Batcher interface{
	Start()
	Commit() error
}

// Danger zone! Do not use this interface unless you really know what you are doing
type TableChanger interface {
	Create() error
	CreateStatement() (string, error)
	Recreate() error
	//Drop() error
	//CreateIfDoesNotExist() error
}

type Table interface {
	// Set Inserts, or Replaces your row with the supplied struct. Be aware that what is not in your struct
	// will be deleted. To only overwrite some of the fields, use Query.Update.
	Set(v interface{}) error
	SetWithOptions(v interface{}, opts Options) error
	Where(relations ...Relation) Filter // Because we provide selections
	TableChanger
}

type QueryExecutor interface {
	Query(stmt string, params ...interface{}) ([]map[string]interface{}, error)
	Execute(stmt string, params ...interface{}) error
}
<commit_msg>Revisited interface to support batching<commit_after>package gocassa

import (
	"time"
)

// The Connection interface only exists because one can not connect to a keyspace if it does not exist, thus having a Create on KeySpace is not possible.
// Use ConnectToKeySpace to acquire an instance of KeySpace.
type Connection interface {
	CreateKeySpace(name string) error
	DropKeySpace(name string) error
	KeySpace(name string) KeySpace
	Batcher
}

type KeySpace interface {
	OneToOneTable(tableName, id string, row interface{}) OneToOneTable
	OneToManyTable(tableName, fieldToIndexBy, uniqueKey string, row interface{}) OneToManyTable
	TimeSeriesTable(tableName, timeField, uniqueKey string, bucketSize time.Duration, row interface{}) TimeSeriesTable
	TimeSeriesBTable(tableName, fieldToIndexByField, timeField, uniqueKey string, bucketSize time.Duration, row interface{}) TimeSeriesBTable
	Table(tableName string, row interface{}, keys Keys) Table
	DebugMode(bool)
}

//
// OneToOne recipe
//

type OneToOneWriter interface {
	SetWithOptions(v interface{}, opts Options) error
	Set(v interface{}) error
	UpdateWithOptions(id interface{}, m map[string]interface{}, opts Options) error
	Update(id interface{}, m map[string]interface{}) error
	Delete(id interface{}) error
}

type OneToOneBatchWriter interface {
	SetWithOptions(v interface{}, opts Options) WriteOp
	Set(v interface{}) WriteOp
	UpdateWithOptions(id interface{}, m map[string]interface{}, opts Options) WriteOp
	Update(id interface{}, m map[string]interface{}) WriteOp
	Delete(id interface{}) WriteOp
}

type OneToOneReader interface {
	Read(id, pointer interface{}) error
	MultiRead(ids []interface{}, pointerToASlice interface{}) error
}

// Simple CRUD interface. You can do CRUD by Id.
type OneToOneTable interface {
	OneToOneReader
	OneToOneWriter
	Batched() OneToOneBatchWriter
}

//
// OneToMany recipe
//

// OneToMany lets you list rows based on a field equality, eg. 'list all sales where seller id = v'.
type OneToManyTable interface {
	SetWithOptions(v interface{}, opts Options) error
	Set(v interface{}) error
	UpdateWithOptions(v, id interface{}, m map[string]interface{}, opts Options) error
	Update(v, id interface{}, m map[string]interface{}) error
	Delete(v, id interface{}) error
	DeleteAll(v interface{}) error
	List(v, startId interface{}, limit int, pointerToASlice interface{}) error
	Read(v, id, pointer interface{}) error
	MultiRead(id interface{}, ids []interface{}, pointerToASlice interface{}) error
	Batcher
	TableChanger
}

//
// TimeSeries recipe
//

// TimeSeries lets you list rows which have a field value between two date ranges.
type TimeSeriesTable interface {
	// timeField and idField must be present
	SetWithOptions(v interface{}, opts Options) error
	Set(v interface{}) error
	UpdateWithOptions(timeStamp time.Time, id interface{}, m map[string]interface{}, opts Options) error
	Update(timeStamp time.Time, id interface{}, m map[string]interface{}) error
	List(start, end time.Time, pointerToASlice interface{}) error
	Read(timeStamp time.Time, id, pointer interface{}) error
	Delete(timeStamp time.Time, id interface{}) error
	Batcher
	TableChanger
}

//
// TimeSeries B recipe
//

// TimeSeriesB is a cross between TimeSeries and OneToMany tables.
type TimeSeriesBTable interface {
	// timeField and idField must be present
	SetWithOptions(v interface{}, opts Options) error
	Set(v interface{}) error
	UpdateWithOptions(v interface{}, timeStamp time.Time, id interface{}, m map[string]interface{}, opts Options) error
	Update(v interface{}, timeStamp time.Time, id interface{}, m map[string]interface{}) error
	List(v interface{}, start, end time.Time, pointerToASlice interface{}) error
	Read(v interface{}, timeStamp time.Time, id, pointer interface{}) error
	Delete(v interface{}, timeStamp time.Time, id interface{}) error
	Batcher
	TableChanger
}

//
// Raw CQL
//

// A Query is a subset of a Table intended to be read
type Query interface {
	Read(pointerToASlice interface{}) error
	ReadOne(pointer interface{}) error
	Limit(int) Query
}

// A Filter is a subset of a Table, filtered by Relations.
// You can do writes or reads on a filter.
type Filter interface {
	// Selection modifiers
	Query() Query
	// Partial update.
	Update(m map[string]interface{}) WriteOp // Probably this is danger zone (can't be implemented efficiently) on a selection with more than 1 document
	UpdateWithOptions(m map[string]interface{}, opts Options) WriteOp
	Delete() WriteOp
}

type Keys struct {
	PartitionKeys     []string
	ClusteringColumns []string
}

type Batcher interface{
	Start()
	Commit() error
}

type WriteOp interface {
	// Run this write operation alone
	Commit() error
}

// Danger zone! Do not use this interface unless you really know what you are doing
type TableChanger interface {
	Create() WriteOp
	CreateStatement() (string, error)
	Recreate() WriteOp
	//Drop() error
	//CreateIfDoesNotExist() error
}

type Table interface {
	// Set Inserts, or Replaces your row with the supplied struct. Be aware that what is not in your struct
	// will be deleted. To only overwrite some of the fields, use Query.Update.
	Set(v interface{}) WriteOp
	SetWithOptions(v interface{}, opts Options) WriteOp
	Where(relations ...Relation) Filter // Because we provide selections
	TableChanger
}

type QueryExecutor interface {
	Query(stmt string, params ...interface{}) ([]map[string]interface{}, error)
	Execute(stmt string, params ...interface{}) error
}
<|endoftext|>


<commit_before>package strumt

// Prompter defines a generic common prompt
// ID returns a string id identify prompter
// PromptString returns string to diplay as prompt
// NextOnError is triggered when an error occurred during
// prompt sequence
type Prompter interface {
	ID() string
	PromptString() string
	NextOnError(error) string
}

// LinePrompter defines a one line prompter
// that will ask only for one user input.
// To mark prompter as the last prompter
// NextOnSucces must returns an empty string
type LinePrompter interface {
	Prompter
	NextOnSuccess(string) string
	Parse(string) error
}

// MultilinePrompter defines a mutiline prompter
// that will let the possibility to the user to
// provide several input, result is provided as
// an input slice.
// To mark prompter as the last prompter
// NextOnSucces must returns an empty string
type MultilinePrompter interface {
	Prompter
	NextOnSuccess([]string) string
	Parse([]string) error
}

// PromptRenderer can be implemented to customize
// the way prompt is rendered, PromptString result is given as parameter
type PromptRenderer interface {
	PrintPrompt(string)
}

// ErrorRenderer can be implemented to customize
// the way an error returned by Parse is rendered
type ErrorRenderer interface {
	PrintError(err error)
}

// SeparatorRenderer can be implemented to customize
// the way a prompt is separated from another, default
// is to add a new line
type SeparatorRenderer interface {
	PrintSeparator()
}
<commit_msg>Update doc, fix typo<commit_after>package strumt

// Prompter defines a generic common prompt
// ID returns a string id to identify prompter
// PromptString returns a string to diplay as prompt
// NextOnError is triggered when an error occurred during
// prompt sequence
type Prompter interface {
	ID() string
	PromptString() string
	NextOnError(error) string
}

// LinePrompter defines a one line prompter
// that will ask only for one user input.
// To mark prompter as the last prompter
// NextOnSucces must returns an empty string
type LinePrompter interface {
	Prompter
	NextOnSuccess(string) string
	Parse(string) error
}

// MultilinePrompter defines a mutiline prompter
// that will let the possibility to the user to
// provide several input, result is provided as
// an input slice.
// To mark prompter as the last prompter
// NextOnSucces must returns an empty string
type MultilinePrompter interface {
	Prompter
	NextOnSuccess([]string) string
	Parse([]string) error
}

// PromptRenderer can be implemented to customize
// the way prompt is rendered, PromptString result is given as parameter
type PromptRenderer interface {
	PrintPrompt(string)
}

// ErrorRenderer can be implemented to customize
// the way an error returned by Parse is rendered
type ErrorRenderer interface {
	PrintError(err error)
}

// SeparatorRenderer can be implemented to customize
// the way a prompt is separated from another, default
// is to add a new line
type SeparatorRenderer interface {
	PrintSeparator()
}
<|endoftext|>


<commit_before>package util

import (
	"net/http"
	"net/http/httputil"
	"net/url"
	"path"
)

// Creates a new http Proxy that forwards requests to the specified url.
// Differs from httputil.NewSingleHostReverseProxy only in that it properly sets the host header.
func NewSingleHostProxy(target *url.URL) *httputil.ReverseProxy {
	targetQuery := target.RawQuery
	director := func(req *http.Request) {
		req.URL.Scheme = target.Scheme
		req.URL.Host = target.Host
		req.URL.Path = path.Join(target.Path, req.URL.Path)
		if targetQuery == "" || req.URL.RawQuery == "" {
			req.URL.RawQuery = targetQuery + req.URL.RawQuery
		} else {
			req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
		}
		req.Host = target.Host
	}
	return &httputil.ReverseProxy{Director: director}
}
<commit_msg>copying a smidgen less code out of httputil<commit_after>package util

import (
	"net/http"
	"net/http/httputil"
	"net/url"
)

// Creates a new http Proxy that forwards requests to the specified url.
// Differs from httputil.NewSingleHostReverseProxy only in that it properly sets the host header.
func NewSingleHostProxy(target *url.URL) *httputil.ReverseProxy {
	proxy := httputil.NewSingleHostReverseProxy(target)
	director := func(req *http.Request) {
		proxy.Director(req)
		req.Host = target.Host
	}
	return &httputil.ReverseProxy{Director: director}
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package e2enode

import (
	"fmt"
	"path/filepath"
	"time"

	"k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/kubernetes/pkg/features"
	kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
	"k8s.io/kubernetes/pkg/volume/util/fsquota"
	"k8s.io/kubernetes/test/e2e/framework"
	e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
	imageutils "k8s.io/kubernetes/test/utils/image"
	"k8s.io/mount-utils"
	admissionapi "k8s.io/pod-security-admission/api"

	"github.com/onsi/ginkgo/v2"
)

const (
	LSCIQuotaFeature = features.LocalStorageCapacityIsolationFSQuotaMonitoring
)

func runOneQuotaTest(f *framework.Framework, quotasRequested bool) {
	evictionTestTimeout := 10 * time.Minute
	sizeLimit := resource.MustParse("100Mi")
	useOverLimit := 101 /* Mb */
	useUnderLimit := 99 /* Mb */
	// TODO: remove hardcoded kubelet volume directory path
	// framework.TestContext.KubeVolumeDir is currently not populated for node e2e
	// As for why we do this: see comment below at isXfs.
	if isXfs("/var/lib/kubelet") {
		useUnderLimit = 50 /* Mb */
	}
	priority := 0
	if quotasRequested {
		priority = 1
	}
	ginkgo.Context(fmt.Sprintf(testContextFmt, fmt.Sprintf("use quotas for LSCI monitoring (quotas enabled: %v)", quotasRequested)), func() {
		tempSetCurrentKubeletConfig(f, func(initialConfig *kubeletconfig.KubeletConfiguration) {
			defer withFeatureGate(LSCIQuotaFeature, quotasRequested)()
			// TODO: remove hardcoded kubelet volume directory path
			// framework.TestContext.KubeVolumeDir is currently not populated for node e2e
			if quotasRequested && !supportsQuotas("/var/lib/kubelet") {
				// No point in running this as a positive test if quotas are not
				// enabled on the underlying filesystem.
				e2eskipper.Skipf("Cannot run LocalStorageCapacityIsolationQuotaMonitoring on filesystem without project quota enabled")
			}
			// setting a threshold to 0% disables; non-empty map overrides default value (necessary due to omitempty)
			initialConfig.EvictionHard = map[string]string{"memory.available": "0%"}

			if initialConfig.FeatureGates == nil {
				initialConfig.FeatureGates = map[string]bool{}
			}
			initialConfig.FeatureGates[string(LSCIQuotaFeature)] = quotasRequested
		})
		runEvictionTest(f, evictionTestTimeout, noPressure, noStarvedResource, logDiskMetrics, []podEvictSpec{
			{
				evictionPriority: priority, // This pod should be evicted because of emptyDir violation only if quotas are enabled
				pod: diskConcealingPod(fmt.Sprintf("emptydir-concealed-disk-over-sizelimit-quotas-%v", quotasRequested), useOverLimit, &v1.VolumeSource{
					EmptyDir: &v1.EmptyDirVolumeSource{SizeLimit: &sizeLimit},
				}, v1.ResourceRequirements{}),
			},
			{
				evictionPriority: 0, // This pod should not be evicted because it uses less than its limit (test for quotas)
				pod: diskConcealingPod(fmt.Sprintf("emptydir-concealed-disk-under-sizelimit-quotas-%v", quotasRequested), useUnderLimit, &v1.VolumeSource{
					EmptyDir: &v1.EmptyDirVolumeSource{SizeLimit: &sizeLimit},
				}, v1.ResourceRequirements{}),
			},
		})
	})
}

// LocalStorageCapacityIsolationQuotaMonitoring tests that quotas are
// used for monitoring rather than du.  The mechanism is to create a
// pod that creates a file, deletes it, and writes data to it.  If
// quotas are used to monitor, it will detect this deleted-but-in-use
// file; if du is used to monitor, it will not detect this.
var _ = SIGDescribe("LocalStorageCapacityIsolationQuotaMonitoring [Slow] [Serial] [Disruptive] [Feature:LocalStorageCapacityIsolationQuota][NodeFeature:LSCIQuotaMonitoring]", func() {
	f := framework.NewDefaultFramework("localstorage-quota-monitoring-test")
	f.NamespacePodSecurityEnforceLevel = admissionapi.LevelPrivileged
	runOneQuotaTest(f, true)
	runOneQuotaTest(f, false)
})

const (
	writeConcealedPodCommand = `
my $file = "%s.bin";
open OUT, ">$file" || die "Cannot open $file: $!\n";
unlink "$file" || die "Cannot unlink $file: $!\n";
my $a = "a";
foreach (1..20) { $a = "$a$a"; }
foreach (1..%d) { syswrite(OUT, $a); }
sleep 999999;`
)

// This is needed for testing eviction of pods using disk space in concealed files; the shell has no convenient
// way of performing I/O to a concealed file, and the busybox image doesn't contain Perl.
func diskConcealingPod(name string, diskConsumedMB int, volumeSource *v1.VolumeSource, resources v1.ResourceRequirements) *v1.Pod {
	path := ""
	volumeMounts := []v1.VolumeMount{}
	volumes := []v1.Volume{}
	if volumeSource != nil {
		path = volumeMountPath
		volumeMounts = []v1.VolumeMount{{MountPath: volumeMountPath, Name: volumeName}}
		volumes = []v1.Volume{{Name: volumeName, VolumeSource: *volumeSource}}
	}
	return &v1.Pod{
		ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("%s-pod", name)},
		Spec: v1.PodSpec{
			RestartPolicy: v1.RestartPolicyNever,
			Containers: []v1.Container{
				{
					Image: imageutils.GetE2EImage(imageutils.Perl),
					Name:  fmt.Sprintf("%s-container", name),
					Command: []string{
						"perl",
						"-e",
						fmt.Sprintf(writeConcealedPodCommand, filepath.Join(path, "file"), diskConsumedMB),
					},
					Resources:    resources,
					VolumeMounts: volumeMounts,
				},
			},
			Volumes: volumes,
		},
	}
}

// Don't bother returning an error; if something goes wrong,
// simply treat it as "no".
func supportsQuotas(dir string) bool {
	supportsQuota, err := fsquota.SupportsQuotas(mount.New(""), dir)
	return supportsQuota && err == nil
}
<commit_msg>LocalStorageCapacityIsolationFSQuotaMonitoring: feature gate typo in e2e node test<commit_after>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package e2enode

import (
	"fmt"
	"path/filepath"
	"time"

	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/kubernetes/pkg/features"
	kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
	"k8s.io/kubernetes/pkg/volume/util/fsquota"
	"k8s.io/kubernetes/test/e2e/framework"
	e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
	imageutils "k8s.io/kubernetes/test/utils/image"
	"k8s.io/mount-utils"
	admissionapi "k8s.io/pod-security-admission/api"

	"github.com/onsi/ginkgo/v2"
)

const (
	LSCIQuotaFeature = features.LocalStorageCapacityIsolationFSQuotaMonitoring
)

func runOneQuotaTest(f *framework.Framework, quotasRequested bool) {
	evictionTestTimeout := 10 * time.Minute
	sizeLimit := resource.MustParse("100Mi")
	useOverLimit := 101 /* Mb */
	useUnderLimit := 99 /* Mb */
	// TODO: remove hardcoded kubelet volume directory path
	// framework.TestContext.KubeVolumeDir is currently not populated for node e2e
	// As for why we do this: see comment below at isXfs.
	if isXfs("/var/lib/kubelet") {
		useUnderLimit = 50 /* Mb */
	}
	priority := 0
	if quotasRequested {
		priority = 1
	}
	ginkgo.Context(fmt.Sprintf(testContextFmt, fmt.Sprintf("use quotas for LSCI monitoring (quotas enabled: %v)", quotasRequested)), func() {
		tempSetCurrentKubeletConfig(f, func(initialConfig *kubeletconfig.KubeletConfiguration) {
			defer withFeatureGate(LSCIQuotaFeature, quotasRequested)()
			// TODO: remove hardcoded kubelet volume directory path
			// framework.TestContext.KubeVolumeDir is currently not populated for node e2e
			if quotasRequested && !supportsQuotas("/var/lib/kubelet") {
				// No point in running this as a positive test if quotas are not
				// enabled on the underlying filesystem.
				e2eskipper.Skipf("Cannot run LocalStorageCapacityIsolationFSQuotaMonitoring on filesystem without project quota enabled")
			}
			// setting a threshold to 0% disables; non-empty map overrides default value (necessary due to omitempty)
			initialConfig.EvictionHard = map[string]string{"memory.available": "0%"}

			if initialConfig.FeatureGates == nil {
				initialConfig.FeatureGates = map[string]bool{}
			}
			initialConfig.FeatureGates[string(LSCIQuotaFeature)] = quotasRequested
		})
		runEvictionTest(f, evictionTestTimeout, noPressure, noStarvedResource, logDiskMetrics, []podEvictSpec{
			{
				evictionPriority: priority, // This pod should be evicted because of emptyDir violation only if quotas are enabled
				pod: diskConcealingPod(fmt.Sprintf("emptydir-concealed-disk-over-sizelimit-quotas-%v", quotasRequested), useOverLimit, &v1.VolumeSource{
					EmptyDir: &v1.EmptyDirVolumeSource{SizeLimit: &sizeLimit},
				}, v1.ResourceRequirements{}),
			},
			{
				evictionPriority: 0, // This pod should not be evicted because it uses less than its limit (test for quotas)
				pod: diskConcealingPod(fmt.Sprintf("emptydir-concealed-disk-under-sizelimit-quotas-%v", quotasRequested), useUnderLimit, &v1.VolumeSource{
					EmptyDir: &v1.EmptyDirVolumeSource{SizeLimit: &sizeLimit},
				}, v1.ResourceRequirements{}),
			},
		})
	})
}

// LocalStorageCapacityIsolationFSQuotaMonitoring tests that quotas are
// used for monitoring rather than du.  The mechanism is to create a
// pod that creates a file, deletes it, and writes data to it.  If
// quotas are used to monitor, it will detect this deleted-but-in-use
// file; if du is used to monitor, it will not detect this.
var _ = SIGDescribe("LocalStorageCapacityIsolationFSQuotaMonitoring [Slow] [Serial] [Disruptive] [Feature:LocalStorageCapacityIsolationQuota][NodeFeature:LSCIQuotaMonitoring]", func() {
	f := framework.NewDefaultFramework("localstorage-quota-monitoring-test")
	f.NamespacePodSecurityEnforceLevel = admissionapi.LevelPrivileged
	runOneQuotaTest(f, true)
	runOneQuotaTest(f, false)
})

const (
	writeConcealedPodCommand = `
my $file = "%s.bin";
open OUT, ">$file" || die "Cannot open $file: $!\n";
unlink "$file" || die "Cannot unlink $file: $!\n";
my $a = "a";
foreach (1..20) { $a = "$a$a"; }
foreach (1..%d) { syswrite(OUT, $a); }
sleep 999999;`
)

// This is needed for testing eviction of pods using disk space in concealed files; the shell has no convenient
// way of performing I/O to a concealed file, and the busybox image doesn't contain Perl.
func diskConcealingPod(name string, diskConsumedMB int, volumeSource *v1.VolumeSource, resources v1.ResourceRequirements) *v1.Pod {
	path := ""
	volumeMounts := []v1.VolumeMount{}
	volumes := []v1.Volume{}
	if volumeSource != nil {
		path = volumeMountPath
		volumeMounts = []v1.VolumeMount{{MountPath: volumeMountPath, Name: volumeName}}
		volumes = []v1.Volume{{Name: volumeName, VolumeSource: *volumeSource}}
	}
	return &v1.Pod{
		ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("%s-pod", name)},
		Spec: v1.PodSpec{
			RestartPolicy: v1.RestartPolicyNever,
			Containers: []v1.Container{
				{
					Image: imageutils.GetE2EImage(imageutils.Perl),
					Name:  fmt.Sprintf("%s-container", name),
					Command: []string{
						"perl",
						"-e",
						fmt.Sprintf(writeConcealedPodCommand, filepath.Join(path, "file"), diskConsumedMB),
					},
					Resources:    resources,
					VolumeMounts: volumeMounts,
				},
			},
			Volumes: volumes,
		},
	}
}

// Don't bother returning an error; if something goes wrong,
// simply treat it as "no".
func supportsQuotas(dir string) bool {
	supportsQuota, err := fsquota.SupportsQuotas(mount.New(""), dir)
	return supportsQuota && err == nil
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	. "github.com/logrusorgru/aurora"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
	"time"
)

var x264Profiles = map[string]string{"Baseline": "42", "Main": "4d", "High": "64"}
var AudioProfiles = map[string]string{"HE-AACv2": "mp4a.40.5", "LC": "mp4a.40.2"}

type Format struct {
	FormatName string `json:"format_name"`
	Duration   string `json:"duration"`
	BitRate    string `json:"bit_rate"`
}

type Stream struct {
	CodecType string  `json:"codec_type"`
	CodecName string  `json:"codec_name"`
	Profile   string  `json:"profile"`
	Level     float64 `json:"level"`
	Width     float64 `json:"width"`
	Height    float64 `json:"height"`
}

type Container struct {
	Streams []Stream `json:"streams"`
	Format  Format   `json:"format"`
}

type Stanza struct {
	Bandwidth  string
	Resolution string
	Level      float64
	Profile    string
	AProfile   string
}

type Job struct {
	InFile      string
	SubFile     string
	AddSubs     bool
	TopLevel    string
	WebVtt      bool
	JasonFile   string
	CmdTemplate string
	Incomplete  string
	Completed   string
	UrlPrefix   string
	Variants    []Variant
}

func (j *Job) mkFlags() {
	flag.StringVar(&j.InFile, "i", "", "Video file to segment (either -i or -b is required)")
	flag.StringVar(&j.SubFile, "s", "", "subtitle file to segment (optional)")
	flag.StringVar(&j.TopLevel, "d", "", "override top level directory for hls files (optional)")
	flag.StringVar(&j.JasonFile, "j", `./hls.json`, "JSON file of variants (optional)")
	flag.StringVar(&j.CmdTemplate, "t", `./cmd.template`, "command template file (optional)")
	flag.StringVar(&j.UrlPrefix, "u", "", "url prefix to add to index.m3u8 path in master.m3u8 (optional)")
	flag.Parse()
}

// Read json file for variants
func (j *Job) dataToVariants() {
	data, err := ioutil.ReadFile(j.JasonFile)
	chk(err, "Error reading JSON file")
	json.Unmarshal(data, &j.Variants)
}

// Set the TopLeveldir for variants by splitting video file name at the "."
func (j *Job) mkTopLevel() {
	if j.TopLevel == "" {
		j.TopLevel = strings.Split(j.InFile, `.`)[0]
		if strings.Contains(j.TopLevel, "/") {
			one := strings.Split(j.TopLevel, "/")
			j.TopLevel = one[len(one)-1]
		}
	}
	os.MkdirAll(j.TopLevel, 0755)
}

func (j *Job) mkIncomplete() {
	for _, v := range j.Variants {
		j.Incomplete += fmt.Sprintf("%s ", v.Aspect)
	}
}

//Extract 608 captions to an WebVtt file.
func (j *Job) extractCaptions() {
	fmt.Printf("%s caption file : %s \n", Cyan(" ."), Cyan(j.InFile))
	fmt.Printf(" . %s", Cyan("extracting captions \r"))
	j.SubFile = fmt.Sprintf("%s/%s.vtt", j.TopLevel, j.TopLevel)
	prefix := "ffmpeg -y -f lavfi -fix_sub_duration "
	postfix := fmt.Sprintf("-i movie=%s[out0+subcc] %s", j.InFile, j.SubFile)
	cmd := prefix + postfix
	chkExec(cmd)

}

// probes for Closed Captions in video file.
func (j *Job) hasCaptions() bool {
	cmd := fmt.Sprintf("ffprobe -i %s", j.InFile)
	data := chkExec(cmd)
	if strings.Contains(string(data), "Captions") {
		return true
	}
	return false
}

// Captions are segmented along with the first variant and then moved to toplevel/subs
func (j *Job) mvSubtitles(vardir string) {
	srcdir := fmt.Sprintf("%s/%s", j.TopLevel, vardir)
	destdir := fmt.Sprintf("%s/subs", j.TopLevel)
	os.MkdirAll(destdir, 0755)
	files, err := ioutil.ReadDir(srcdir)
	chk(err, "Error moving Captions")
	for _, f := range files {
		if strings.Contains(f.Name(), "vtt") {
			os.Rename(fmt.Sprintf("%s/%s", srcdir, f.Name()), fmt.Sprintf("%s/%s", destdir, f.Name()))
		}
	}
}

// Extract captions to segment,
// unless a subtitle file is passed in with "-s"
func (j *Job) mkSubfile() {
	j.AddSubs = false
	if !(j.WebVtt) {
		if (j.SubFile == "") && (j.hasCaptions()) {
			j.extractCaptions()
		}
		if j.SubFile != "" {
			j.AddSubs = true
		}
	}
}

// create a subtitle stanza for use in the  master.m3u8
func (j *Job) mkSubStanza() string {
	one := "#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"WebVtt\","
	two := "NAME=\"English\",DEFAULT=YES,AUTOSELECT=YES,FORCED=NO,"
	line := j.mkLine()
	three := fmt.Sprintf("LANGUAGE=\"en\",URI=\"%ssubs/vtt_index.m3u8\"\n", line)
	return one + two + three
}

// Make all variants and write master.m3u8
func (j *Job) mkAll() {
	fmt.Println(Cyan(" ."), "video file   :", Cyan(j.InFile))
	fmt.Println(Cyan(" ."), "TopLeveldir :", Cyan(j.TopLevel))
	j.mkSubfile()
	var m3u8Master = fmt.Sprintf("%s/master.m3u8", j.TopLevel)
	fp, err := os.Create(m3u8Master)
	chk(err, "in mkAll")
	defer fp.Close()
	w := bufio.NewWriter(fp)
	w.WriteString("#EXTM3U\n")
	fmt.Println(Cyan(" ."), "subtitle file:", Cyan(j.SubFile))
	j.mkIncomplete()
	for _, v := range j.Variants {
		v.job = j
		v.start()
		if j.AddSubs && !(j.WebVtt) {
			j.mvSubtitles(v.Name)
			w.WriteString(j.mkSubStanza())
			j.WebVtt = true
		}
		w.WriteString(fmt.Sprintf("%s\n", v.mkStanza()))
		line := j.mkLine()
		w.WriteString(fmt.Sprintf("%s%s/index.m3u8\n", line, v.Name))
		w.Flush()
	}
	fmt.Println()
}

func (j *Job) mkLine() string {
	line := j.UrlPrefix
	if j.UrlPrefix != "" {
		line += fmt.Sprintf("%s/", j.TopLevel)
	}
	return line
}

func (j *Job) fixUrlPrefix() {
	if (j.UrlPrefix != "") && !(strings.HasSuffix(j.UrlPrefix, "/")) {
		j.UrlPrefix += "/"
	}
}

func (j *Job) do() {
	j.mkFlags()
	if j.InFile != "" {
		j.mkTopLevel()
		j.fixUrlPrefix()
		j.dataToVariants()
		j.mkAll()
	} else {
		flag.PrintDefaults()
	}
}

// End Job

// Variant struct for HLS variants
type Variant struct {
	job       *Job
	Name      string `json:"name"`
	Aspect    string `json:"aspect"`
	Rate      string `json:"framerate"`
	Vbr       string `json:"vbitrate"`
	Abr       string `json:"abitrate"`
	Buf       string `json:"bufsize"`
	Bandwidth string
}

// Create variant's destination directory
func (v *Variant) mkDest() string {
	dest := fmt.Sprintf("%s/%s", v.job.TopLevel, v.Name)
	os.MkdirAll(dest, 0755)
	return dest
}

func (v *Variant) mkInputs() string {
	inputs := fmt.Sprintf(" -i %s", v.job.InFile)
	if v.job.AddSubs && !(v.job.WebVtt) {
		inputs = fmt.Sprintf(" -i %s -i %s  ", v.job.InFile, v.job.SubFile)
	}
	return inputs
}

// This Variant method assembles the ffmpeg command
func (v *Variant) mkCmd(CmdTemplate string) string {
	data, err := ioutil.ReadFile(CmdTemplate)
	chk(err, "Error reading template file")
	inputs := v.mkInputs()
	r := strings.NewReplacer("INPUTS", inputs, "ASPECT", v.Aspect,
		"VBITRATE", v.Vbr, "BUFSIZE", v.Buf, "FRAMERATE", v.Rate,
		"ABITRATE", v.Abr, "TOPLEVEL", v.job.TopLevel,
		"NAME", v.Name, "\n", " ")
	cmd := fmt.Sprintf("%s\n", r.Replace(string(data)))
	return cmd
}

// Start transcoding the variant
func (v *Variant) start() {
	v.mkDest()
	fmt.Printf(" . variant sizes: %s%s \r", Cyan(v.job.Completed), v.job.Incomplete)
	it := fmt.Sprintf("%s ", v.Aspect)
	v.job.Completed += it
	v.job.Incomplete = strings.Replace(v.job.Incomplete, it, "", 1)
	cmd := v.mkCmd(v.job.CmdTemplate)
	chkExec(cmd)
	//	v.readRate()
	fmt.Printf(" %s variant sizes: %s%s \r", Cyan("."), Cyan(v.job.Completed), v.job.Incomplete)
}

// #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=7483000,RESOLUTION=1920:1080,
// hd1920/index.m3u8
func (v *Variant) mkStanza() string {
	cmd := fmt.Sprintf("ffprobe -hide_banner -i %s/%s/index0.ts -show_streams -show_format -print_format json ", v.job.TopLevel, v.Name)
	parts := strings.Fields(cmd)
	data, err := exec.Command(parts[0], parts[1:]...).Output()
	chk(err, fmt.Sprintf("Error running \n %s \n %v", cmd, string(data)))
	var st Stanza
	var f Container
	json.Unmarshal(data, &f)
	st.Bandwidth = f.Format.BitRate
	for _, i := range f.Streams {
		if i.CodecType == "video" {
			st.Resolution = fmt.Sprintf("%vx%v", i.Width, i.Height)
			st.Profile = x264Profiles[i.Profile]
			st.Level = i.Level
		}
		if i.CodecType == "audio" {
			st.AProfile = "," + AudioProfiles[i.Profile]
		}
	}
	m3u8Stanza := fmt.Sprintf("#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=%v,RESOLUTION=%s,CODECS=\"avc1.%v00%x%v\"", st.Bandwidth, st.Resolution, st.Profile, int(st.Level), st.AProfile)

	if v.job.AddSubs {
		m3u8Stanza = fmt.Sprintf("%s,SUBTITLES=\"WebVtt\"", m3u8Stanza)
	}
	return m3u8Stanza
}

// End Variant

func chkExec(cmd string) []byte {
	// Executes external commands and checks for runtime errors
	parts := strings.Fields(cmd)
	data, err := exec.Command(parts[0], parts[1:]...).CombinedOutput()
	chk(err, fmt.Sprintf("Error running \n %s \n %v", cmd, string(data)))
	return data
}

// Generic catchall error checking
func chk(err error, mesg string) {
	if err != nil {
		fmt.Printf("%s\n", mesg)
		//panic(err)
	}
}

func stamp() {
	t := time.Now()
	fmt.Println(Cyan(" ."), Cyan(t.Format(time.Stamp)))
}

func main() {
	stamp()
	var j Job
	j.do()

}
<commit_msg>fixed subtitle m3u8 file name<commit_after>package main

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	. "github.com/logrusorgru/aurora"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
	"time"
)

var x264Profiles = map[string]string{"Baseline": "42", "Main": "4d", "High": "64"}
var AudioProfiles = map[string]string{"HE-AACv2": "mp4a.40.5", "LC": "mp4a.40.2"}

type Format struct {
	FormatName string `json:"format_name"`
	Duration   string `json:"duration"`
	BitRate    string `json:"bit_rate"`
}

type Stream struct {
	CodecType string  `json:"codec_type"`
	CodecName string  `json:"codec_name"`
	Profile   string  `json:"profile"`
	Level     float64 `json:"level"`
	Width     float64 `json:"width"`
	Height    float64 `json:"height"`
}

type Container struct {
	Streams []Stream `json:"streams"`
	Format  Format   `json:"format"`
}

type Stanza struct {
	Bandwidth  string
	Resolution string
	Level      float64
	Profile    string
	AProfile   string
}

type Job struct {
	InFile      string
	SubFile     string
	AddSubs     bool
	TopLevel    string
	WebVtt      bool
	JasonFile   string
	CmdTemplate string
	Incomplete  string
	Completed   string
	UrlPrefix   string
	Variants    []Variant
}

func (j *Job) mkFlags() {
	flag.StringVar(&j.InFile, "i", "", "Video file to segment (either -i or -b is required)")
	flag.StringVar(&j.SubFile, "s", "", "subtitle file to segment (optional)")
	flag.StringVar(&j.TopLevel, "d", "", "override top level directory for hls files (optional)")
	flag.StringVar(&j.JasonFile, "j", `./hls.json`, "JSON file of variants (optional)")
	flag.StringVar(&j.CmdTemplate, "t", `./cmd.template`, "command template file (optional)")
	flag.StringVar(&j.UrlPrefix, "u", "", "url prefix to add to index.m3u8 path in master.m3u8 (optional)")
	flag.Parse()
}

// Read json file for variants
func (j *Job) dataToVariants() {
	data, err := ioutil.ReadFile(j.JasonFile)
	chk(err, "Error reading JSON file")
	json.Unmarshal(data, &j.Variants)
}

// Set the TopLeveldir for variants by splitting video file name at the "."
func (j *Job) mkTopLevel() {
	if j.TopLevel == "" {
		j.TopLevel = strings.Split(j.InFile, `.`)[0]
		if strings.Contains(j.TopLevel, "/") {
			one := strings.Split(j.TopLevel, "/")
			j.TopLevel = one[len(one)-1]
		}
	}
	os.MkdirAll(j.TopLevel, 0755)
}

func (j *Job) mkIncomplete() {
	for _, v := range j.Variants {
		j.Incomplete += fmt.Sprintf("%s ", v.Aspect)
	}
}

//Extract 608 captions to an WebVtt file.
func (j *Job) extractCaptions() {
	fmt.Printf("%s caption file : %s \n", Cyan(" ."), Cyan(j.InFile))
	fmt.Printf(" . %s", Cyan("extracting captions \r"))
	j.SubFile = fmt.Sprintf("%s/%s.vtt", j.TopLevel, j.TopLevel)
	prefix := "ffmpeg -y -f lavfi -fix_sub_duration "
	postfix := fmt.Sprintf("-i movie=%s[out0+subcc] %s", j.InFile, j.SubFile)
	cmd := prefix + postfix
	chkExec(cmd)

}

// probes for Closed Captions in video file.
func (j *Job) hasCaptions() bool {
	cmd := fmt.Sprintf("ffprobe -i %s", j.InFile)
	data := chkExec(cmd)
	if strings.Contains(string(data), "Captions") {
		return true
	}
	return false
}

// Captions are segmented along with the first variant and then moved to toplevel/subs
func (j *Job) mvSubtitles(vardir string) {
	srcdir := fmt.Sprintf("%s/%s", j.TopLevel, vardir)
	destdir := fmt.Sprintf("%s/subs", j.TopLevel)
	os.MkdirAll(destdir, 0755)
	files, err := ioutil.ReadDir(srcdir)
	chk(err, "Error moving Captions")
	for _, f := range files {
		if strings.Contains(f.Name(), "vtt") {
			os.Rename(fmt.Sprintf("%s/%s", srcdir, f.Name()), fmt.Sprintf("%s/%s", destdir, f.Name()))
		}
	}
}

// Extract captions to segment,
// unless a subtitle file is passed in with "-s"
func (j *Job) mkSubfile() {
	j.AddSubs = false
	if !(j.WebVtt) {
		if (j.SubFile == "") && (j.hasCaptions()) {
			j.extractCaptions()
		}
		if j.SubFile != "" {
			j.AddSubs = true
		}
	}
}

// create a subtitle stanza for use in the  master.m3u8
func (j *Job) mkSubStanza() string {
	one := "#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"WebVtt\","
	two := "NAME=\"English\",DEFAULT=YES,AUTOSELECT=YES,FORCED=NO,"
	line := j.mkLine()
	three := fmt.Sprintf("LANGUAGE=\"en\",URI=\"%ssubs/index_vtt.m3u8\"\n", line)
	return one + two + three
}

// Make all variants and write master.m3u8
func (j *Job) mkAll() {
	fmt.Println(Cyan(" ."), "video file   :", Cyan(j.InFile))
	fmt.Println(Cyan(" ."), "TopLeveldir :", Cyan(j.TopLevel))
	j.mkSubfile()
	var m3u8Master = fmt.Sprintf("%s/master.m3u8", j.TopLevel)
	fp, err := os.Create(m3u8Master)
	chk(err, "in mkAll")
	defer fp.Close()
	w := bufio.NewWriter(fp)
	w.WriteString("#EXTM3U\n")
	fmt.Println(Cyan(" ."), "subtitle file:", Cyan(j.SubFile))
	j.mkIncomplete()
	for _, v := range j.Variants {
		v.job = j
		v.start()
		if j.AddSubs && !(j.WebVtt) {
			j.mvSubtitles(v.Name)
			w.WriteString(j.mkSubStanza())
			j.WebVtt = true
		}
		w.WriteString(fmt.Sprintf("%s\n", v.mkStanza()))
		line := j.mkLine()
		w.WriteString(fmt.Sprintf("%s%s/index.m3u8\n", line, v.Name))
		w.Flush()
	}
	fmt.Println()
}

func (j *Job) mkLine() string {
	line := j.UrlPrefix
	if j.UrlPrefix != "" {
		line += fmt.Sprintf("%s/", j.TopLevel)
	}
	return line
}

func (j *Job) fixUrlPrefix() {
	if (j.UrlPrefix != "") && !(strings.HasSuffix(j.UrlPrefix, "/")) {
		j.UrlPrefix += "/"
	}
}

func (j *Job) do() {
	j.mkFlags()
	if j.InFile != "" {
		j.mkTopLevel()
		j.fixUrlPrefix()
		j.dataToVariants()
		j.mkAll()
	} else {
		flag.PrintDefaults()
	}
}

// End Job

// Variant struct for HLS variants
type Variant struct {
	job       *Job
	Name      string `json:"name"`
	Aspect    string `json:"aspect"`
	Rate      string `json:"framerate"`
	Vbr       string `json:"vbitrate"`
	Abr       string `json:"abitrate"`
	Buf       string `json:"bufsize"`
	Bandwidth string
}

// Create variant's destination directory
func (v *Variant) mkDest() string {
	dest := fmt.Sprintf("%s/%s", v.job.TopLevel, v.Name)
	os.MkdirAll(dest, 0755)
	return dest
}

func (v *Variant) mkInputs() string {
	inputs := fmt.Sprintf(" -i %s", v.job.InFile)
	if v.job.AddSubs && !(v.job.WebVtt) {
		inputs = fmt.Sprintf(" -i %s -i %s  ", v.job.InFile, v.job.SubFile)
	}
	return inputs
}

// This Variant method assembles the ffmpeg command
func (v *Variant) mkCmd(CmdTemplate string) string {
	data, err := ioutil.ReadFile(CmdTemplate)
	chk(err, "Error reading template file")
	inputs := v.mkInputs()
	r := strings.NewReplacer("INPUTS", inputs, "ASPECT", v.Aspect,
		"VBITRATE", v.Vbr, "BUFSIZE", v.Buf, "FRAMERATE", v.Rate,
		"ABITRATE", v.Abr, "TOPLEVEL", v.job.TopLevel,
		"NAME", v.Name, "\n", " ")
	cmd := fmt.Sprintf("%s\n", r.Replace(string(data)))
	return cmd
}

// Start transcoding the variant
func (v *Variant) start() {
	v.mkDest()
	fmt.Printf(" . variant sizes: %s%s \r", Cyan(v.job.Completed), v.job.Incomplete)
	it := fmt.Sprintf("%s ", v.Aspect)
	v.job.Completed += it
	v.job.Incomplete = strings.Replace(v.job.Incomplete, it, "", 1)
	cmd := v.mkCmd(v.job.CmdTemplate)
	chkExec(cmd)
	//	v.readRate()
	fmt.Printf(" %s variant sizes: %s%s \r", Cyan("."), Cyan(v.job.Completed), v.job.Incomplete)
}

// #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=7483000,RESOLUTION=1920:1080,
// hd1920/index.m3u8
func (v *Variant) mkStanza() string {
	cmd := fmt.Sprintf("ffprobe -hide_banner -i %s/%s/index0.ts -show_streams -show_format -print_format json ", v.job.TopLevel, v.Name)
	parts := strings.Fields(cmd)
	data, err := exec.Command(parts[0], parts[1:]...).Output()
	chk(err, fmt.Sprintf("Error running \n %s \n %v", cmd, string(data)))
	var st Stanza
	var f Container
	json.Unmarshal(data, &f)
	st.Bandwidth = f.Format.BitRate
	for _, i := range f.Streams {
		if i.CodecType == "video" {
			st.Resolution = fmt.Sprintf("%vx%v", i.Width, i.Height)
			st.Profile = x264Profiles[i.Profile]
			st.Level = i.Level
		}
		if i.CodecType == "audio" {
			st.AProfile = "," + AudioProfiles[i.Profile]
		}
	}
	m3u8Stanza := fmt.Sprintf("#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=%v,RESOLUTION=%s,CODECS=\"avc1.%v00%x%v\"", st.Bandwidth, st.Resolution, st.Profile, int(st.Level), st.AProfile)

	if v.job.AddSubs {
		m3u8Stanza = fmt.Sprintf("%s,SUBTITLES=\"WebVtt\"", m3u8Stanza)
	}
	return m3u8Stanza
}

// End Variant

func chkExec(cmd string) []byte {
	// Executes external commands and checks for runtime errors
	parts := strings.Fields(cmd)
	data, err := exec.Command(parts[0], parts[1:]...).CombinedOutput()
	chk(err, fmt.Sprintf("Error running \n %s \n %v", cmd, string(data)))
	return data
}

// Generic catchall error checking
func chk(err error, mesg string) {
	if err != nil {
		fmt.Printf("%s\n", mesg)
		//panic(err)
	}
}

func stamp() {
	t := time.Now()
	fmt.Println(Cyan(" ."), Cyan(t.Format(time.Stamp)))
}

func main() {
	stamp()
	var j Job
	j.do()

}
<|endoftext|>


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

package ebiten

import (
	"github.com/hajimehoshi/ebiten/internal/bsp"
	"github.com/hajimehoshi/ebiten/internal/restorable"
)

type sharedImage struct {
	restorable *restorable.Image
	page       bsp.Page
}

var (
	theSharedImages = []*sharedImage{}
)

type sharedImagePart struct {
	sharedImage *sharedImage
	node        *bsp.Node
}

func (s *sharedImagePart) image() *restorable.Image {
	return s.sharedImage.restorable
}

func (s *sharedImagePart) region() (x, y, width, height int) {
	return s.node.Region()
}

func (s *sharedImagePart) Dispose() {
	s.sharedImage.page.Free(s.node)
	if s.sharedImage.page.IsEmpty() {
		s.sharedImage.restorable.Dispose()
		s.sharedImage.restorable = nil
		index := -1
		for i, sh := range theSharedImages {
			if sh == s.sharedImage {
				index = i
				break
			}
		}
		if index == -1 {
			panic("not reached")
		}
		theSharedImages = append(theSharedImages[:index], theSharedImages[index+1:]...)
	}
}

func newSharedImagePart(width, height int) *sharedImagePart {
	// TODO: Lock!
	if width > bsp.MaxSize || height > bsp.MaxSize {
		return nil
	}
	for _, s := range theSharedImages {
		if n := s.page.Alloc(width, height); n != nil {
			return &sharedImagePart{
				sharedImage: s,
				node:        n,
			}
		}
	}
	s := &sharedImage{
		restorable: restorable.NewImage(bsp.MaxSize, bsp.MaxSize, false),
	}
	theSharedImages = append(theSharedImages, s)

	n := s.page.Alloc(width, height)
	if n == nil {
		panic("not reached")
	}
	return &sharedImagePart{
		sharedImage: s,
		node:        n,
	}
}
<commit_msg>graphics: Bug fix: Add lock to newSharedImagePart<commit_after>// Copyright 2018 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package ebiten

import (
	"github.com/hajimehoshi/ebiten/internal/bsp"
	"github.com/hajimehoshi/ebiten/internal/restorable"
	"github.com/hajimehoshi/ebiten/internal/sync"
)

type sharedImage struct {
	restorable *restorable.Image
	page       bsp.Page
}

var (
	theSharedImages = []*sharedImage{}
)

type sharedImagePart struct {
	sharedImage *sharedImage
	node        *bsp.Node
}

func (s *sharedImagePart) image() *restorable.Image {
	return s.sharedImage.restorable
}

func (s *sharedImagePart) region() (x, y, width, height int) {
	return s.node.Region()
}

func (s *sharedImagePart) Dispose() {
	s.sharedImage.page.Free(s.node)
	if s.sharedImage.page.IsEmpty() {
		s.sharedImage.restorable.Dispose()
		s.sharedImage.restorable = nil
		index := -1
		for i, sh := range theSharedImages {
			if sh == s.sharedImage {
				index = i
				break
			}
		}
		if index == -1 {
			panic("not reached")
		}
		theSharedImages = append(theSharedImages[:index], theSharedImages[index+1:]...)
	}
}

var sharedImageLock sync.Mutex

func newSharedImagePart(width, height int) *sharedImagePart {
	sharedImageLock.Lock()
	sharedImageLock.Unlock()

	if width > bsp.MaxSize || height > bsp.MaxSize {
		return nil
	}
	for _, s := range theSharedImages {
		if n := s.page.Alloc(width, height); n != nil {
			return &sharedImagePart{
				sharedImage: s,
				node:        n,
			}
		}
	}
	s := &sharedImage{
		restorable: restorable.NewImage(bsp.MaxSize, bsp.MaxSize, false),
	}
	theSharedImages = append(theSharedImages, s)

	n := s.page.Alloc(width, height)
	if n == nil {
		panic("not reached")
	}
	return &sharedImagePart{
		sharedImage: s,
		node:        n,
	}
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"regexp"
	"strconv"
	"strings"

	"golang.org/x/net/context"
	"golang.org/x/oauth2/google"
	"gopkg.in/Iwark/spreadsheet.v2"
)

type Board struct {
	President, Vpe, Vpm, Vppr, Secretary, Treasurer, Saa string
}

type AgendaRoles struct {
	Toastmaster, Ge, Timer, AhCounter, Grammarian string
	TableTopicsMaster, JokeMaster                 string
	Speakers                                      []Speaker
	BoardMembers                                  Board
	FutureWeeks                                   [][]string
}

type Speaker struct {
	Name      string
	Speech    speech
	Evaluator string
}

func (s Speaker) firstName() string {
	return strings.Split(s.Name, " ")[0]
}

func getSheet() (*spreadsheet.Sheet, *spreadsheet.Sheet) {
	data, err := ioutil.ReadFile("client_secret.json")
	if err != nil {
		panic("cannot read client_secret.json")
	}

	conf, err := google.JWTConfigFromJSON(data, spreadsheet.Scope)
	if err != nil {
		panic("problem with google.JWTConfigFromJSON(data, spreadsheet.Scope)")
	}

	client := conf.Client(context.TODO())

	service := spreadsheet.NewServiceWithClient(client)
	spreadsheet, err := service.FetchSpreadsheet("1CBlORqCzL6YvyAUZTk8jezvhyuDzjjumghwGKk5VIK8")
	if err != nil {
		panic("cannot fetch spread sheet: ")
	}

	roles, err := spreadsheet.SheetByIndex(0)
	if err != nil {
		panic("Cannot read spreadsheet by index 0")
	}

	board, err := spreadsheet.SheetByIndex(1)
	if err != nil {
		panic("Cannot read spreadsheet by index 1")
	}

	return roles, board
}

func getBoard(sheet *spreadsheet.Sheet) Board {
	board := Board{}
	board.President = sheet.Columns[1][0].Value
	board.Vpe = sheet.Columns[1][1].Value
	board.Vpm = sheet.Columns[1][2].Value
	board.Vppr = sheet.Columns[1][3].Value
	board.Secretary = sheet.Columns[1][4].Value
	board.Treasurer = sheet.Columns[1][5].Value
	board.Saa = sheet.Columns[1][6].Value

	return board
}

func parseManualAndNumber(speaker string) (string, string, int) {
	re := regexp.MustCompile(`([a-zA-Z]+ [a-zA-Z]+)\n([a-zA-Z]+) #(\d{1,2})`)
	result := re.FindStringSubmatch(speaker)
	name := speaker
	manual := ""
	speechNum := 0

	if len(result) > 0 {
		name = result[1]
		manual = result[2]
		speechNum, _ = strconv.Atoi(result[3])
	}
	return name, manual, speechNum
}

func populateSpeaker(s string, eval string) Speaker {
	name, manual, number := parseManualAndNumber(s)
	info := speech{}.new(manual, number)

	speaker := Speaker{}
	speaker.Name = name
	speaker.Evaluator = eval
	speaker.Speech = info
	return speaker
}

func GetRoles(agendaDate string) AgendaRoles {
	sheet, roles := getSheet()
	boardMembers := getBoard(roles)

	agendaRoles := AgendaRoles{}
	agendaRoles.BoardMembers = boardMembers

	for i := range sheet.Columns {
		if sheet.Columns[i][0].Value == agendaDate {
			agendaRoles.Toastmaster = sheet.Columns[i][1].Value
			agendaRoles.JokeMaster = sheet.Columns[i][2].Value
			agendaRoles.Ge = sheet.Columns[i][3].Value
			agendaRoles.Timer = sheet.Columns[i][4].Value
			agendaRoles.AhCounter = sheet.Columns[i][5].Value
			agendaRoles.Grammarian = sheet.Columns[i][6].Value

			for j := 7; j <= 13; j += 2 {
				agendaRoles.Speakers = append(agendaRoles.Speakers, populateSpeaker(sheet.Columns[i][j].Value, sheet.Columns[i][j+1].Value))
			}

			agendaRoles.TableTopicsMaster = sheet.Columns[i][16].Value
			agendaRoles.FutureWeeks = GetFutureWeeks(agendaDate, sheet)
			break
		}
	}
	return agendaRoles
}

func GetFutureWeeks(agendaDate string, sheet *spreadsheet.Sheet) [][]string {
	week := 0
	var nextSchedule = make([][]string, 0, 4)

	for i := 0; i < len(sheet.Columns) && week < 5; i++ {
		if week == 0 {
			if sheet.Columns[i][0].Value == agendaDate {
				week = 1
			}
		} else {
			nextWeek := make([]string, 17)

			for j := 0; j < 17; j++ {
				nextWeek[j] = sheet.Columns[i][j].Value
			}
			nextSchedule = append(nextSchedule, nextWeek)
			week++
		}
	}
	return nextSchedule
}
<commit_msg>pulled out a constant.<commit_after>package main

import (
	"io/ioutil"
	"regexp"
	"strconv"
	"strings"

	"golang.org/x/net/context"
	"golang.org/x/oauth2/google"
	"gopkg.in/Iwark/spreadsheet.v2"
)

type Board struct {
	President, Vpe, Vpm, Vppr, Secretary, Treasurer, Saa string
}

type AgendaRoles struct {
	Toastmaster, Ge, Timer, AhCounter, Grammarian string
	TableTopicsMaster, JokeMaster                 string
	Speakers                                      []Speaker
	BoardMembers                                  Board
	FutureWeeks                                   [][]string
}

type Speaker struct {
	Name      string
	Speech    speech
	Evaluator string
}

func (s Speaker) firstName() string {
	return strings.Split(s.Name, " ")[0]
}

func getSheet() (*spreadsheet.Sheet, *spreadsheet.Sheet) {
	data, err := ioutil.ReadFile("client_secret.json")
	if err != nil {
		panic("cannot read client_secret.json")
	}

	conf, err := google.JWTConfigFromJSON(data, spreadsheet.Scope)
	if err != nil {
		panic("problem with google.JWTConfigFromJSON(data, spreadsheet.Scope)")
	}

	client := conf.Client(context.TODO())

	service := spreadsheet.NewServiceWithClient(client)
	spreadsheet, err := service.FetchSpreadsheet("1CBlORqCzL6YvyAUZTk8jezvhyuDzjjumghwGKk5VIK8")
	if err != nil {
		panic("cannot fetch spread sheet: ")
	}

	roles, err := spreadsheet.SheetByIndex(0)
	if err != nil {
		panic("Cannot read spreadsheet by index 0")
	}

	board, err := spreadsheet.SheetByIndex(1)
	if err != nil {
		panic("Cannot read spreadsheet by index 1")
	}

	return roles, board
}

func getBoard(sheet *spreadsheet.Sheet) Board {
	board := Board{}
	board.President = sheet.Columns[1][0].Value
	board.Vpe = sheet.Columns[1][1].Value
	board.Vpm = sheet.Columns[1][2].Value
	board.Vppr = sheet.Columns[1][3].Value
	board.Secretary = sheet.Columns[1][4].Value
	board.Treasurer = sheet.Columns[1][5].Value
	board.Saa = sheet.Columns[1][6].Value

	return board
}

func parseManualAndNumber(speaker string) (string, string, int) {
	re := regexp.MustCompile(`([a-zA-Z]+ [a-zA-Z]+)\n([a-zA-Z]+) #(\d{1,2})`)
	result := re.FindStringSubmatch(speaker)
	name := speaker
	manual := ""
	speechNum := 0

	if len(result) > 0 {
		name = result[1]
		manual = result[2]
		speechNum, _ = strconv.Atoi(result[3])
	}
	return name, manual, speechNum
}

func populateSpeaker(s string, eval string) Speaker {
	name, manual, number := parseManualAndNumber(s)
	info := speech{}.new(manual, number)

	speaker := Speaker{}
	speaker.Name = name
	speaker.Evaluator = eval
	speaker.Speech = info
	return speaker
}

func GetRoles(agendaDate string) AgendaRoles {
	sheet, roles := getSheet()
	boardMembers := getBoard(roles)

	agendaRoles := AgendaRoles{}
	agendaRoles.BoardMembers = boardMembers

	for i := range sheet.Columns {
		if sheet.Columns[i][0].Value == agendaDate {
			agendaRoles.Toastmaster = sheet.Columns[i][1].Value
			agendaRoles.JokeMaster = sheet.Columns[i][2].Value
			agendaRoles.Ge = sheet.Columns[i][3].Value
			agendaRoles.Timer = sheet.Columns[i][4].Value
			agendaRoles.AhCounter = sheet.Columns[i][5].Value
			agendaRoles.Grammarian = sheet.Columns[i][6].Value

			for j := 7; j <= 13; j += 2 {
				agendaRoles.Speakers = append(agendaRoles.Speakers, populateSpeaker(sheet.Columns[i][j].Value, sheet.Columns[i][j+1].Value))
			}

			agendaRoles.TableTopicsMaster = sheet.Columns[i][16].Value
			agendaRoles.FutureWeeks = getFutureWeeks(agendaDate, sheet)
			break
		}
	}
	return agendaRoles
}

// The number of weeks to capture.
const futureWeeks = 4

// GetFutureWeeks finds the next four weeks after the current week and their agenda roles.
func getFutureWeeks(agendaDate string, sheet *spreadsheet.Sheet) [][]string {
	week := 0
	var nextSchedule = make([][]string, 0, futureWeeks)

	for i := 0; i < len(sheet.Columns) && week <= futureWeeks; i++ {
		if week == 0 {
			if sheet.Columns[i][0].Value == agendaDate {
				week = 1
			}
		} else {
			nextWeek := make([]string, 17)

			for j := 0; j < 17; j++ {
				nextWeek[j] = sheet.Columns[i][j].Value
			}
			nextSchedule = append(nextSchedule, nextWeek)
			week++
		}
	}
	return nextSchedule
}
<|endoftext|>


<commit_before>
package main

import (
	"github.com/keybase/protocol/go"
	"github.com/keybase/go-libkb"
	"net"
)

type SignupHandler struct {
	conn net.Conn
}

func (h SignupHandler) CheckUsernameAvailable(arg *keybase_1.CheckUsernameAvailableArg, res *keybase_1.CheckUsernameAvailableRes) error {
	err := libkb.CheckUsernameAvailable(arg.Username)
	res.Status = libkb.ExportErrorAsStatus(err)
	return nil
}
func (h SignupHandler) Signup(arg *keybase_1.SignupArg, res *keybase_1.SignupRes) error {
	return nil
}
func (h SignupHandler) InviteResuest(arg *keybase_1.InviteRequestArg, res *keybase_1.InviteRequestRes) error {
	return nil
}
<commit_msg>also request invites<commit_after>
package main

import (
	"github.com/keybase/protocol/go"
	"github.com/keybase/go-libkb"
	"net"
)

type SignupHandler struct {
	conn net.Conn
}

func (h SignupHandler) CheckUsernameAvailable(arg *keybase_1.CheckUsernameAvailableArg, res *keybase_1.CheckUsernameAvailableRes) error {
	err := libkb.CheckUsernameAvailable(arg.Username)
	res.Status = libkb.ExportErrorAsStatus(err)
	return nil
}

func (h SignupHandler) Signup(arg *keybase_1.SignupArg, res *keybase_1.SignupRes) error {
	eng := libkb.NewSignupEngine()
	seres := eng.Run(libkb.SignupEngineRunArg{
		Username : arg.Username,
		Email : arg.Email,
		InviteCode : arg.InviteCode,
		Passphrase : arg.Passphrase,
	})
	res.Status = libkb.ExportErrorAsStatus(seres.Error)
	res.Body.PassphraseOk = seres.PassphraseOk
	res.Body.PostOk = seres.PostOk
	res.Body.WriteOk = seres.WriteOk

	if seres.Uid != nil {
		succ := keybase_1.SignupResSuccess{}
		copy(succ.Uid[:], (*seres.Uid)[:])
		res.Body.Success = &succ
	}
	return nil
}

func (h SignupHandler) InviteResuest(arg *keybase_1.InviteRequestArg, res *keybase_1.InviteRequestRes) error {
	err := libkb.PostInviteRequest(libkb.InviteRequestArg{
		Email : arg.Email,
		Fullname : arg.Fullname,
		Notes : arg.Notes,

	})
	res.Status = libkb.ExportErrorAsStatus(err)
	res.Body = &keybase_1.InviteRequestResBody{
		Place : 0,
		Code : "",
	}
	return nil
}
<|endoftext|>


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

package drive

import (
	"fmt"
	"path/filepath"
)

func (g *Commands) Move() (err error) {
	argc := len(g.opts.Sources)
	if argc < 2 {
		return fmt.Errorf("move: expected <src> [src...] <dest>, instead got: %v", g.opts.Sources)
	}

	var newParent *File
	rest, dest := g.opts.Sources[:argc-1], g.opts.Sources[argc-1]

	if newParent, err = g.rem.FindByPath(dest); err != nil {
		return fmt.Errorf("dest: '%s' %v", dest, err)
	}

	if newParent == nil || !newParent.IsDir {
		return fmt.Errorf("dest: '%s' must be an existant folder", dest)
	}

	for _, src := range rest {
		g.move(src, newParent)
	}

	return nil
}

func (g *Commands) move(srcPath string, newParent *File) (err error) {
	var remSrc *File
	if remSrc, err = g.rem.FindByPath(srcPath); err != nil {
		return fmt.Errorf("src('%s') %v", srcPath, err)
	}

	if remSrc == nil {
		return fmt.Errorf("src: '%s' doesn't exist", srcPath)
	}
	// Avoid self-nesting
	if remSrc.Id == newParent.Id {
		return fmt.Errorf("move: cannot move to self")
	}

	// To avoid any orphaning, firstly insert the new parent
	if err = g.rem.insertParent(remSrc.Id, newParent.Id); err != nil {
		return err
	}

	// TODO: Rollback in case popping the old parent fails? Leave in orphaned state?

	// Next let's pop the old parent
	return g.removeParent(remSrc.Id, srcPath)
}

func (g *Commands) removeParent(fileId, relToRootPath string) error {
	parentPath := g.parentPather(relToRootPath)
	parent, pErr := g.rem.FindByPath(parentPath)
	if pErr != nil {
		return pErr
	}
	if parent == nil {
		return fmt.Errorf("non existant parent '%s' for src", parentPath)
	}
	return g.rem.removeParent(fileId, parent.Id)
}

func (g *Commands) Rename() error {
	if len(g.opts.Sources) < 2 {
		return fmt.Errorf("rename: expecting <src> <newname>")
	}

	src, newName := g.opts.Sources[0], g.opts.Sources[1]
	remSrc, err := g.rem.FindByPath(src)
	if err != nil {
		return fmt.Errorf("%s: %v", src, err)
	}
	if remSrc == nil {
		return fmt.Errorf("%s does not exist", src)
	}

	parentPath := g.parentPather(src)
	newFullPath := filepath.Join(parentPath, newName)
	var dupCheck *File
	dupCheck, err = g.rem.FindByPath(newFullPath)
	if err == nil && dupCheck != nil {
		if dupCheck.Id == remSrc.Id { // Trying to rename self
			return nil
		}
		if !g.opts.Force {
			return fmt.Errorf("%s already exists. Use `%s` flag to override this behaviour", newFullPath, ForceKey)
		}
	}

	_, err = g.rem.rename(remSrc.Id, newName)
	return err
}
<commit_msg>move: first pop parent before inserting<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package drive

import (
	"fmt"
	"path/filepath"
)

func (g *Commands) Move() (err error) {
	argc := len(g.opts.Sources)
	if argc < 2 {
		return fmt.Errorf("move: expected <src> [src...] <dest>, instead got: %v", g.opts.Sources)
	}

	var newParent *File
	rest, dest := g.opts.Sources[:argc-1], g.opts.Sources[argc-1]

	if newParent, err = g.rem.FindByPath(dest); err != nil {
		return fmt.Errorf("dest: '%s' %v", dest, err)
	}

	if newParent == nil || !newParent.IsDir {
		return fmt.Errorf("dest: '%s' must be an existant folder", dest)
	}

	for _, src := range rest {
		g.move(src, newParent)
	}

	return nil
}

func (g *Commands) move(srcPath string, newParent *File) (err error) {
	var remSrc *File
	if remSrc, err = g.rem.FindByPath(srcPath); err != nil {
		return fmt.Errorf("src('%s') %v", srcPath, err)
	}

	if remSrc == nil {
		return fmt.Errorf("src: '%s' doesn't exist", srcPath)
	}
	// Avoid self-nesting
	if remSrc.Id == newParent.Id {
		return fmt.Errorf("move: cannot move to self")
	}

	if err = g.removeParent(remSrc.Id, srcPath); err != nil {
		return err
	}

	return g.rem.insertParent(remSrc.Id, newParent.Id)
}

func (g *Commands) removeParent(fileId, relToRootPath string) error {
	parentPath := g.parentPather(relToRootPath)
	parent, pErr := g.rem.FindByPath(parentPath)
	if pErr != nil {
		return pErr
	}
	if parent == nil {
		return fmt.Errorf("non existant parent '%s' for src", parentPath)
	}
	return g.rem.removeParent(fileId, parent.Id)
}

func (g *Commands) Rename() error {
	if len(g.opts.Sources) < 2 {
		return fmt.Errorf("rename: expecting <src> <newname>")
	}

	src, newName := g.opts.Sources[0], g.opts.Sources[1]
	remSrc, err := g.rem.FindByPath(src)
	if err != nil {
		return fmt.Errorf("%s: %v", src, err)
	}
	if remSrc == nil {
		return fmt.Errorf("%s does not exist", src)
	}

	parentPath := g.parentPather(src)
	newFullPath := filepath.Join(parentPath, newName)
	var dupCheck *File
	dupCheck, err = g.rem.FindByPath(newFullPath)
	if err == nil && dupCheck != nil {
		if dupCheck.Id == remSrc.Id { // Trying to rename self
			return nil
		}
		if !g.opts.Force {
			return fmt.Errorf("%s already exists. Use `%s` flag to override this behaviour", newFullPath, ForceKey)
		}
	}

	_, err = g.rem.rename(remSrc.Id, newName)
	return err
}
<|endoftext|>


<commit_before>// Copyright 2013 commandmocker 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 commandmocker is a simple utility for tests in Go. It adds command
// with expected output/failure to the path.
package commandmocker

import (
	"bufio"
	"crypto/rand"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"strings"
	"sync"
	"syscall"
	"text/template"
)

var source = `#!/bin/bash -e

output="{{.output}}"
dirname=$(dirname ${0})
echo -n "${output}"{{if .status}} >&2{{end}} | tee -a ${dirname}/.out
for i in "$@"
do
	echo $i >> ${dirname}/.params
done
touch ${dirname}/.ran
exit {{.status}}
`

func add(name, output string, status int) (string, error) {
	var buf [8]byte
	rand.Read(buf[:])
	tempdir := path.Join(os.TempDir(), fmt.Sprintf("commandmocker-%x", buf))
	_, err := os.Stat(tempdir)
	for !os.IsNotExist(err) {
		rand.Read(buf[:])
		tempdir = path.Join(os.TempDir(), fmt.Sprintf("commandmocker-%x", buf))
		_, err = os.Stat(tempdir)
	}
	err = os.MkdirAll(tempdir, 0777)
	if err != nil {
		return "", err
	}
	f, err := os.OpenFile(path.Join(tempdir, name), syscall.O_WRONLY|syscall.O_CREAT|syscall.O_TRUNC, 0755)
	if err != nil {
		return "", err
	}
	defer f.Close()
	t, err := template.New(name).Parse(source)
	if err != nil {
		return "", err
	}
	param := map[string]interface{}{
		"output": output,
		"status": status,
	}
	err = t.Execute(f, param)
	if err != nil {
		return "", err
	}
	var pathMutex sync.Mutex
	pathMutex.Lock()
	path := os.Getenv("PATH")
	path = tempdir + ":" + path
	err = os.Setenv("PATH", path)
	pathMutex.Unlock()
	return tempdir, nil
}

// Add creates a temporary directory containing an executable file named "name"
// that prints "output" when executed. It also adds the temporary directory to
// the first position of $PATH.
//
// It returns the temporary directory path (for future removing, using the
// Remove function) and an error if any happen.
func Add(name, output string) (string, error) {
	return add(name, output, 0)
}

// Error works like Add, but the created executable returns a non-zero status
// code (an error). The returned status code will be the value provided by
// status.
func Error(name, output string, status int) (string, error) {
	return add(name, output, status)
}

// Ran indicates whether the mocked executable was called or not.
//
// It just checks if the given tempdir contains a .ran file.
func Ran(tempdir string) bool {
	p := path.Join(tempdir, ".ran")
	_, err := os.Stat(p)
	return err == nil || !os.IsNotExist(err)
}

// Output returns the output generated by the previously added command
// execution.
func Output(tempdir string) string {
	p := path.Join(tempdir, ".out")
	b, err := ioutil.ReadFile(p)
	if err != nil {
		return ""
	}
	return string(b)
}

// Parameters returns a slice containing all positional parameters given to the
// command mocked in tempdir in its last execution.
func Parameters(tempdir string) []string {
	p := path.Join(tempdir, ".params")
	f, err := os.Open(p)
	if err != nil {
		return nil
	}
	defer f.Close()
	var params []string
	reader := bufio.NewReader(f)
	line, err := reader.ReadString('\n')
	for err == nil {
		params = append(params, strings.TrimSpace(line))
		line, err = reader.ReadString('\n')
	}
	return params
}

// Remove removes the tempdir from $PATH and from file system.
//
// This function is intended only to undo what Add does. It returns error if
// the given tempdir is not a temporary directory.
func Remove(tempdir string) error {
	if !strings.HasPrefix(tempdir, os.TempDir()) {
		return errors.New("Remove can only remove temporary directories, tryied to remove " + tempdir)
	}
	path := os.Getenv("PATH")
	index := strings.Index(path, tempdir)
	if index < 0 {
		return errors.New(fmt.Sprintf("%q is not in $PATH", tempdir))
	}
	path = path[:index] + path[index+len(tempdir)+1:]
	err := os.Setenv("PATH", path)
	if err != nil {
		return err
	}
	return os.RemoveAll(tempdir)
}
<commit_msg>mocker: use bourne shell instead of bash for better compatibility<commit_after>// Copyright 2013 commandmocker 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 commandmocker is a simple utility for tests in Go. It adds command
// with expected output/failure to the path.
package commandmocker

import (
	"bufio"
	"crypto/rand"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"strings"
	"sync"
	"syscall"
	"text/template"
)

var source = `#!/bin/sh -e

echo=$(which echo)
output="{{.output}}"
dirname=$(dirname ${0})
$echo -n "${output}"{{if .status}} >&2{{end}} | tee -a ${dirname}/.out
for i in "$@"
do
	$echo $i >> ${dirname}/.params
done
touch ${dirname}/.ran
exit {{.status}}
`

func add(name, output string, status int) (string, error) {
	var buf [8]byte
	rand.Read(buf[:])
	tempdir := path.Join(os.TempDir(), fmt.Sprintf("commandmocker-%x", buf))
	_, err := os.Stat(tempdir)
	for !os.IsNotExist(err) {
		rand.Read(buf[:])
		tempdir = path.Join(os.TempDir(), fmt.Sprintf("commandmocker-%x", buf))
		_, err = os.Stat(tempdir)
	}
	err = os.MkdirAll(tempdir, 0777)
	if err != nil {
		return "", err
	}
	f, err := os.OpenFile(path.Join(tempdir, name), syscall.O_WRONLY|syscall.O_CREAT|syscall.O_TRUNC, 0755)
	if err != nil {
		return "", err
	}
	defer f.Close()
	t, err := template.New(name).Parse(source)
	if err != nil {
		return "", err
	}
	param := map[string]interface{}{
		"output": output,
		"status": status,
	}
	err = t.Execute(f, param)
	if err != nil {
		return "", err
	}
	var pathMutex sync.Mutex
	pathMutex.Lock()
	path := os.Getenv("PATH")
	path = tempdir + ":" + path
	err = os.Setenv("PATH", path)
	pathMutex.Unlock()
	return tempdir, nil
}

// Add creates a temporary directory containing an executable file named "name"
// that prints "output" when executed. It also adds the temporary directory to
// the first position of $PATH.
//
// It returns the temporary directory path (for future removing, using the
// Remove function) and an error if any happen.
func Add(name, output string) (string, error) {
	return add(name, output, 0)
}

// Error works like Add, but the created executable returns a non-zero status
// code (an error). The returned status code will be the value provided by
// status.
func Error(name, output string, status int) (string, error) {
	return add(name, output, status)
}

// Ran indicates whether the mocked executable was called or not.
//
// It just checks if the given tempdir contains a .ran file.
func Ran(tempdir string) bool {
	p := path.Join(tempdir, ".ran")
	_, err := os.Stat(p)
	return err == nil || !os.IsNotExist(err)
}

// Output returns the output generated by the previously added command
// execution.
func Output(tempdir string) string {
	p := path.Join(tempdir, ".out")
	b, err := ioutil.ReadFile(p)
	if err != nil {
		return ""
	}
	return string(b)
}

// Parameters returns a slice containing all positional parameters given to the
// command mocked in tempdir in its last execution.
func Parameters(tempdir string) []string {
	p := path.Join(tempdir, ".params")
	f, err := os.Open(p)
	if err != nil {
		return nil
	}
	defer f.Close()
	var params []string
	reader := bufio.NewReader(f)
	line, err := reader.ReadString('\n')
	for err == nil {
		params = append(params, strings.TrimSpace(line))
		line, err = reader.ReadString('\n')
	}
	return params
}

// Remove removes the tempdir from $PATH and from file system.
//
// This function is intended only to undo what Add does. It returns error if
// the given tempdir is not a temporary directory.
func Remove(tempdir string) error {
	if !strings.HasPrefix(tempdir, os.TempDir()) {
		return errors.New("Remove can only remove temporary directories, tryied to remove " + tempdir)
	}
	path := os.Getenv("PATH")
	index := strings.Index(path, tempdir)
	if index < 0 {
		return errors.New(fmt.Sprintf("%q is not in $PATH", tempdir))
	}
	path = path[:index] + path[index+len(tempdir)+1:]
	err := os.Setenv("PATH", path)
	if err != nil {
		return err
	}
	return os.RemoveAll(tempdir)
}
<|endoftext|>