<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 nodeup

import (
	"strings"

	"k8s.io/kops/pkg/apis/kops"
	"k8s.io/kops/upup/pkg/fi"
	"k8s.io/kops/util/pkg/architectures"
)

// Config is the configuration for the nodeup binary
type Config struct {
	// Assets are locations where we can find files to be installed
	// TODO: Remove once everything is in containers?
	Assets map[architectures.Architecture][]string `json:",omitempty"`
	// Images are a list of images we should preload
	Images map[architectures.Architecture][]*Image `json:"images,omitempty"`
	// ClusterName is the name of the cluster
	ClusterName string `json:",omitempty"`
	// Channels is a list of channels that we should apply
	Channels []string `json:"channels,omitempty"`
	// ApiserverAdditionalIPs are additional IP address to put in the apiserver server cert.
	ApiserverAdditionalIPs []string `json:",omitempty"`
	// WarmPoolImages are the container images to pre-pull during instance pre-initialization
	WarmPoolImages []string `json:"warmPoolImages,omitempty"`
	// Packages specifies additional packages to be installed.
	Packages []string `json:"packages,omitempty"`

	// Manifests for running etcd
	EtcdManifests []string `json:"etcdManifests,omitempty"`

	// CAs are the CA certificates to trust.
	CAs map[string]string
	// KeypairIDs are the IDs of keysets used to sign things.
	KeypairIDs map[string]string
	// DefaultMachineType is the first-listed instance machine type, used if querying instance metadata fails.
	DefaultMachineType *string `json:",omitempty"`
	// EnableLifecycleHook defines whether we need to complete a lifecycle hook.
	EnableLifecycleHook bool `json:",omitempty"`
	// StaticManifests describes generic static manifests
	// Using this allows us to keep complex logic out of nodeup
	StaticManifests []*StaticManifest `json:"staticManifests,omitempty"`
	// KubeletConfig defines the kubelet configuration.
	KubeletConfig kops.KubeletConfigSpec
	// SysctlParameters will configure kernel parameters using sysctl(8). When
	// specified, each parameter must follow the form variable=value, the way
	// it would appear in sysctl.conf.
	SysctlParameters []string `json:",omitempty"`
	// UpdatePolicy determines the policy for applying upgrades automatically.
	UpdatePolicy string
	// VolumeMounts are a collection of volume mounts.
	VolumeMounts []kops.VolumeMountSpec `json:",omitempty"`

	// FileAssets are a collection of file assets for this instance group.
	FileAssets []kops.FileAssetSpec `json:",omitempty"`
	// Hooks are for custom actions, for example on first installation.
	Hooks [][]kops.HookSpec
	// ContainerdConfig config holds the configuration for containerd
	ContainerdConfig *kops.ContainerdConfig `json:"containerdConfig,omitempty"`

	// APIServerConfig is additional configuration for nodes running an APIServer.
	APIServerConfig *APIServerConfig `json:",omitempty"`
	// NvidiaGPU contains the configuration for nvidia
	NvidiaGPU *kops.NvidiaGPUConfig `json:",omitempty"`
	// UseInstanceIDForNodeName uses the instance ID instead of the hostname for the node name.
	UseInstanceIDForNodeName bool `json:"useInstanceIDForNodeName,omitempty"`
}

// BootConfig is the configuration for the nodeup binary that might be too big to fit in userdata.
type BootConfig struct {
	// CloudProvider is the cloud provider in use.
	CloudProvider string
	// ConfigBase is the base VFS path for config objects.
	ConfigBase *string `json:",omitempty"`
	// ConfigServer holds the configuration for the configuration server.
	ConfigServer *ConfigServerOptions `json:",omitempty"`
	// APIServer is the API server IP address.
	APIServer string `json:",omitempty"`
	// InstanceGroupName is the name of the instance group.
	InstanceGroupName string `json:",omitempty"`
	// InstanceGroupRole is the instance group role.
	InstanceGroupRole kops.InstanceGroupRole
	// NodeupConfigHash holds a secure hash of the nodeup.Config.
	NodeupConfigHash string
}

type ConfigServerOptions struct {
	// Server is the address of the configuration server to use (kops-controller)
	Server string `json:"server,omitempty"`
	// CACertificates are the certificates to trust for fi.CertificateIDCA.
	CACertificates string
}

// Image is a docker image we should pre-load
type Image struct {
	// This is the name we would pass to "docker run", whereas source could be a URL from which we would download an image.
	Name string `json:"name,omitempty"`
	// Sources is a list of URLs from which we should download the image
	Sources []string `json:"sources,omitempty"`
	// Hash is the hash of the file, to verify image integrity (even over http)
	Hash string `json:"hash,omitempty"`
}

// StaticManifest is a generic static manifest
type StaticManifest struct {
	// Key identifies the static manifest
	Key string `json:"key,omitempty"`
	// Path is the path to the manifest
	Path string `json:"path,omitempty"`
}

// APIServerConfig is additional configuration for nodes running an APIServer.
type APIServerConfig struct {
	// KubeAPIServer is a copy of the KubeAPIServerConfig from the cluster spec.
	KubeAPIServer *kops.KubeAPIServerConfig
	// EncryptionConfigSecretHash is a hash of the encryptionconfig secret.
	// It is empty if EncryptionConfig is not enabled.
	// TODO: give secrets IDs and look them up like we do keypairs.
	EncryptionConfigSecretHash string `json:",omitempty"`
	// ServiceAccountPublicKeys are the service-account public keys to trust.
	ServiceAccountPublicKeys string
}

func NewConfig(cluster *kops.Cluster, instanceGroup *kops.InstanceGroup) (*Config, *BootConfig) {
	role := instanceGroup.Spec.Role

	clusterHooks := filterHooks(cluster.Spec.Hooks, instanceGroup.Spec.Role)
	igHooks := filterHooks(instanceGroup.Spec.Hooks, instanceGroup.Spec.Role)

	config := Config{
		ClusterName:      cluster.ObjectMeta.Name,
		CAs:              map[string]string{},
		KeypairIDs:       map[string]string{},
		SysctlParameters: instanceGroup.Spec.SysctlParameters,
		VolumeMounts:     instanceGroup.Spec.VolumeMounts,
		FileAssets:       append(filterFileAssets(instanceGroup.Spec.FileAssets, role), filterFileAssets(cluster.Spec.FileAssets, role)...),
		Hooks:            [][]kops.HookSpec{igHooks, clusterHooks},
	}

	bootConfig := BootConfig{
		CloudProvider:     string(cluster.Spec.GetCloudProvider()),
		InstanceGroupName: instanceGroup.ObjectMeta.Name,
		InstanceGroupRole: role,
	}

	warmPool := cluster.Spec.WarmPool.ResolveDefaults(instanceGroup)
	if warmPool.IsEnabled() && warmPool.EnableLifecycleHook {
		config.EnableLifecycleHook = true
	}

	if instanceGroup.Spec.UpdatePolicy != nil {
		config.UpdatePolicy = *instanceGroup.Spec.UpdatePolicy
	} else if cluster.Spec.UpdatePolicy != nil {
		config.UpdatePolicy = *cluster.Spec.UpdatePolicy
	} else {
		config.UpdatePolicy = kops.UpdatePolicyAutomatic
	}

	if cluster.Spec.Networking != nil && cluster.Spec.Networking.AmazonVPC != nil {
		config.DefaultMachineType = fi.String(strings.Split(instanceGroup.Spec.MachineType, ",")[0])
	}

	if UsesInstanceIDForNodeName(cluster) {
		config.UseInstanceIDForNodeName = true
	}

	if instanceGroup.Spec.Kubelet != nil {
		config.KubeletConfig = *instanceGroup.Spec.Kubelet
	}

	if instanceGroup.HasAPIServer() {
		config.APIServerConfig = &APIServerConfig{
			KubeAPIServer: cluster.Spec.KubeAPIServer,
		}
	}

	return &config, &bootConfig
}

func UsesInstanceIDForNodeName(cluster *kops.Cluster) bool {
	return cluster.Spec.ExternalCloudControllerManager != nil && cluster.IsKubernetesGTE("1.22") && cluster.Spec.GetCloudProvider() == kops.CloudProviderAWS
}

func filterFileAssets(f []kops.FileAssetSpec, role kops.InstanceGroupRole) []kops.FileAssetSpec {
	var fileAssets []kops.FileAssetSpec
	for _, fileAsset := range f {
		if len(fileAsset.Roles) > 0 && !containsRole(role, fileAsset.Roles) {
			continue
		}
		fileAsset.Roles = nil
		fileAssets = append(fileAssets, fileAsset)
	}
	return fileAssets
}

func filterHooks(h []kops.HookSpec, role kops.InstanceGroupRole) []kops.HookSpec {
	var hooks []kops.HookSpec
	for _, hook := range h {
		if len(hook.Roles) > 0 && !containsRole(role, hook.Roles) {
			continue
		}
		hook.Roles = nil
		hooks = append(hooks, hook)
	}
	return hooks
}

func containsRole(v kops.InstanceGroupRole, list []kops.InstanceGroupRole) bool {
	for _, x := range list {
		if v == x {
			return true
		}
	}

	return false
}
<commit_msg>Address feedback<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 nodeup

import (
	"strings"

	"k8s.io/kops/pkg/apis/kops"
	"k8s.io/kops/upup/pkg/fi"
	"k8s.io/kops/util/pkg/architectures"
)

// Config is the configuration for the nodeup binary
type Config struct {
	// Assets are locations where we can find files to be installed
	// TODO: Remove once everything is in containers?
	Assets map[architectures.Architecture][]string `json:",omitempty"`
	// Images are a list of images we should preload
	Images map[architectures.Architecture][]*Image `json:"images,omitempty"`
	// ClusterName is the name of the cluster
	ClusterName string `json:",omitempty"`
	// Channels is a list of channels that we should apply
	Channels []string `json:"channels,omitempty"`
	// ApiserverAdditionalIPs are additional IP address to put in the apiserver server cert.
	ApiserverAdditionalIPs []string `json:",omitempty"`
	// WarmPoolImages are the container images to pre-pull during instance pre-initialization
	WarmPoolImages []string `json:"warmPoolImages,omitempty"`
	// Packages specifies additional packages to be installed.
	Packages []string `json:"packages,omitempty"`

	// Manifests for running etcd
	EtcdManifests []string `json:"etcdManifests,omitempty"`

	// CAs are the CA certificates to trust.
	CAs map[string]string
	// KeypairIDs are the IDs of keysets used to sign things.
	KeypairIDs map[string]string
	// DefaultMachineType is the first-listed instance machine type, used if querying instance metadata fails.
	DefaultMachineType *string `json:",omitempty"`
	// EnableLifecycleHook defines whether we need to complete a lifecycle hook.
	EnableLifecycleHook bool `json:",omitempty"`
	// StaticManifests describes generic static manifests
	// Using this allows us to keep complex logic out of nodeup
	StaticManifests []*StaticManifest `json:"staticManifests,omitempty"`
	// KubeletConfig defines the kubelet configuration.
	KubeletConfig kops.KubeletConfigSpec
	// SysctlParameters will configure kernel parameters using sysctl(8). When
	// specified, each parameter must follow the form variable=value, the way
	// it would appear in sysctl.conf.
	SysctlParameters []string `json:",omitempty"`
	// UpdatePolicy determines the policy for applying upgrades automatically.
	UpdatePolicy string
	// VolumeMounts are a collection of volume mounts.
	VolumeMounts []kops.VolumeMountSpec `json:",omitempty"`

	// FileAssets are a collection of file assets for this instance group.
	FileAssets []kops.FileAssetSpec `json:",omitempty"`
	// Hooks are for custom actions, for example on first installation.
	Hooks [][]kops.HookSpec
	// ContainerdConfig config holds the configuration for containerd
	ContainerdConfig *kops.ContainerdConfig `json:"containerdConfig,omitempty"`

	// APIServerConfig is additional configuration for nodes running an APIServer.
	APIServerConfig *APIServerConfig `json:",omitempty"`
	// NvidiaGPU contains the configuration for nvidia
	NvidiaGPU *kops.NvidiaGPUConfig `json:",omitempty"`
	// UseInstanceIDForNodeName uses the instance ID instead of the hostname for the node name.
	UseInstanceIDForNodeName bool `json:"useInstanceIDForNodeName,omitempty"`
}

// BootConfig is the configuration for the nodeup binary that might be too big to fit in userdata.
type BootConfig struct {
	// CloudProvider is the cloud provider in use.
	CloudProvider string
	// ConfigBase is the base VFS path for config objects.
	ConfigBase *string `json:",omitempty"`
	// ConfigServer holds the configuration for the configuration server.
	ConfigServer *ConfigServerOptions `json:",omitempty"`
	// APIServer is the API server IP address.
	// This field is used for adding an alias for api.internal. in /etc/hosts, when Topology.DNS.Type == DNSTypeNone.
	APIServer string `json:",omitempty"`
	// InstanceGroupName is the name of the instance group.
	InstanceGroupName string `json:",omitempty"`
	// InstanceGroupRole is the instance group role.
	InstanceGroupRole kops.InstanceGroupRole
	// NodeupConfigHash holds a secure hash of the nodeup.Config.
	NodeupConfigHash string
}

type ConfigServerOptions struct {
	// Server is the address of the configuration server to use (kops-controller)
	Server string `json:"server,omitempty"`
	// CACertificates are the certificates to trust for fi.CertificateIDCA.
	CACertificates string
}

// Image is a docker image we should pre-load
type Image struct {
	// This is the name we would pass to "docker run", whereas source could be a URL from which we would download an image.
	Name string `json:"name,omitempty"`
	// Sources is a list of URLs from which we should download the image
	Sources []string `json:"sources,omitempty"`
	// Hash is the hash of the file, to verify image integrity (even over http)
	Hash string `json:"hash,omitempty"`
}

// StaticManifest is a generic static manifest
type StaticManifest struct {
	// Key identifies the static manifest
	Key string `json:"key,omitempty"`
	// Path is the path to the manifest
	Path string `json:"path,omitempty"`
}

// APIServerConfig is additional configuration for nodes running an APIServer.
type APIServerConfig struct {
	// KubeAPIServer is a copy of the KubeAPIServerConfig from the cluster spec.
	KubeAPIServer *kops.KubeAPIServerConfig
	// EncryptionConfigSecretHash is a hash of the encryptionconfig secret.
	// It is empty if EncryptionConfig is not enabled.
	// TODO: give secrets IDs and look them up like we do keypairs.
	EncryptionConfigSecretHash string `json:",omitempty"`
	// ServiceAccountPublicKeys are the service-account public keys to trust.
	ServiceAccountPublicKeys string
}

func NewConfig(cluster *kops.Cluster, instanceGroup *kops.InstanceGroup) (*Config, *BootConfig) {
	role := instanceGroup.Spec.Role

	clusterHooks := filterHooks(cluster.Spec.Hooks, instanceGroup.Spec.Role)
	igHooks := filterHooks(instanceGroup.Spec.Hooks, instanceGroup.Spec.Role)

	config := Config{
		ClusterName:      cluster.ObjectMeta.Name,
		CAs:              map[string]string{},
		KeypairIDs:       map[string]string{},
		SysctlParameters: instanceGroup.Spec.SysctlParameters,
		VolumeMounts:     instanceGroup.Spec.VolumeMounts,
		FileAssets:       append(filterFileAssets(instanceGroup.Spec.FileAssets, role), filterFileAssets(cluster.Spec.FileAssets, role)...),
		Hooks:            [][]kops.HookSpec{igHooks, clusterHooks},
	}

	bootConfig := BootConfig{
		CloudProvider:     string(cluster.Spec.GetCloudProvider()),
		InstanceGroupName: instanceGroup.ObjectMeta.Name,
		InstanceGroupRole: role,
	}

	warmPool := cluster.Spec.WarmPool.ResolveDefaults(instanceGroup)
	if warmPool.IsEnabled() && warmPool.EnableLifecycleHook {
		config.EnableLifecycleHook = true
	}

	if instanceGroup.Spec.UpdatePolicy != nil {
		config.UpdatePolicy = *instanceGroup.Spec.UpdatePolicy
	} else if cluster.Spec.UpdatePolicy != nil {
		config.UpdatePolicy = *cluster.Spec.UpdatePolicy
	} else {
		config.UpdatePolicy = kops.UpdatePolicyAutomatic
	}

	if cluster.Spec.Networking != nil && cluster.Spec.Networking.AmazonVPC != nil {
		config.DefaultMachineType = fi.String(strings.Split(instanceGroup.Spec.MachineType, ",")[0])
	}

	if UsesInstanceIDForNodeName(cluster) {
		config.UseInstanceIDForNodeName = true
	}

	if instanceGroup.Spec.Kubelet != nil {
		config.KubeletConfig = *instanceGroup.Spec.Kubelet
	}

	if instanceGroup.HasAPIServer() {
		config.APIServerConfig = &APIServerConfig{
			KubeAPIServer: cluster.Spec.KubeAPIServer,
		}
	}

	return &config, &bootConfig
}

func UsesInstanceIDForNodeName(cluster *kops.Cluster) bool {
	return cluster.Spec.ExternalCloudControllerManager != nil && cluster.IsKubernetesGTE("1.22") && cluster.Spec.GetCloudProvider() == kops.CloudProviderAWS
}

func filterFileAssets(f []kops.FileAssetSpec, role kops.InstanceGroupRole) []kops.FileAssetSpec {
	var fileAssets []kops.FileAssetSpec
	for _, fileAsset := range f {
		if len(fileAsset.Roles) > 0 && !containsRole(role, fileAsset.Roles) {
			continue
		}
		fileAsset.Roles = nil
		fileAssets = append(fileAssets, fileAsset)
	}
	return fileAssets
}

func filterHooks(h []kops.HookSpec, role kops.InstanceGroupRole) []kops.HookSpec {
	var hooks []kops.HookSpec
	for _, hook := range h {
		if len(hook.Roles) > 0 && !containsRole(role, hook.Roles) {
			continue
		}
		hook.Roles = nil
		hooks = append(hooks, hook)
	}
	return hooks
}

func containsRole(v kops.InstanceGroupRole, list []kops.InstanceGroupRole) bool {
	for _, x := range list {
		if v == x {
			return true
		}
	}

	return false
}
<|endoftext|>


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

// Package derrgroup provides synchronization, error propagation, and Context
// cancelation for groups of goroutines working on subtasks of a common task.
//
// derrgroup is a fork of golang.org/x/sync/errgroup commit
// 6e8e738ad208923de99951fe0b48239bfd864f28 (2020-06-04).
package derrgroup

import (
	"sync"

	"github.com/pkg/errors"
)

type GoroutineState int

const (
	GoroutineRunning GoroutineState = iota
	GoroutineExited
	GoroutineErrored
)

func (s GoroutineState) String() string {
	switch s {
	case GoroutineRunning:
		return "running"
	case GoroutineExited:
		return "exited without error"
	case GoroutineErrored:
		return "exited with error"
	default:
		panic(errors.Errorf("invalid GoroutineState = %d", s))
	}
}

// A Group is a collection of goroutines working on subtasks that are part of
// the same overall task.
//
// A zero Group is valid and does not cancel on error.
type Group struct {
	cancel func()

	wg sync.WaitGroup

	listMu sync.RWMutex
	list   map[string]GoroutineState

	errOnce sync.Once
	err     error
}

// NewGroup returns a new Group.
//
// The provided 'cancel' function is called the first time a function passed to
// Go returns a non-nil error or the first time Wait returns, whichever occurs
// first.
func NewGroup(cancel func()) *Group {
	return &Group{cancel: cancel}
}

// Wait blocks until all function calls from the Go method have returned, then
// returns the first non-nil error (if any) from them.
func (g *Group) Wait() error {
	g.wg.Wait()
	if g.cancel != nil {
		g.cancel()
	}
	return g.err
}

// Go calls the given function in a new goroutine.
//
// The first call to return a non-nil error cancels the group; its error will be
// returned by Wait.
func (g *Group) Go(name string, f func() error) {
	g.listMu.Lock()
	if g.list == nil {
		g.list = make(map[string]GoroutineState)
	}
	if _, exists := g.list[name]; exists {
		g.wg.Add(1)
		g.listMu.Unlock()
		go func() {
			g.errOnce.Do(func() {
				g.err = errors.Errorf("a goroutine with name %q already exists", name)
				if g.cancel != nil {
					g.cancel()
				}
			})
			g.wg.Done()
		}()
	}
	g.list[name] = GoroutineRunning
	g.wg.Add(1)
	g.listMu.Unlock()

	go func() {
		exitState := GoroutineExited
		if err := f(); err != nil {
			exitState = GoroutineErrored
			g.errOnce.Do(func() {
				g.err = err
				if g.cancel != nil {
					g.cancel()
				}
			})
		}
		g.listMu.Lock()
		if g.list == nil {
			g.list = make(map[string]GoroutineState)
		}
		g.list[name] = exitState
		g.wg.Done()
		g.listMu.Unlock()
	}()
}

// List returns a listing of all goroutines launched with Go.
func (g *Group) List() map[string]GoroutineState {
	g.listMu.RLock()
	defer g.listMu.RUnlock()

	ret := make(map[string]GoroutineState, len(g.list))
	for k, v := range g.list {
		ret[k] = v
	}

	return ret
}
<commit_msg>(from AES) derrgroup: Add some docs<commit_after>// Copyright 2019-2020 Datawire. All rights reserved.
//
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package derrgroup provides synchronization, error propagation, and
// cancelation callback for groups of goroutines working on subtasks
// of a common task.
//
// The principle is that derrgroup contains the things on top of
// sync.WaitGroup that can't be solved at a higher-level without
// re-implementing the synchronization of derrgroup.  If it can be
// solved by adding another layer on top of derrgroup, then it is NOT
// solved here; contexts are trivial to add by the caller, signal
// handling can be done as a worker in the group.  This is a low-level
// primitive for implementing your more sophisticated groups.
//
// derrgroup is a fork of golang.org/x/sync/errgroup commit
// 6e8e738ad208923de99951fe0b48239bfd864f28 (2020-06-04).
package derrgroup

import (
	"sync"

	"github.com/pkg/errors"
)

type GoroutineState int

const (
	GoroutineRunning GoroutineState = iota
	GoroutineExited
	GoroutineErrored
)

func (s GoroutineState) String() string {
	switch s {
	case GoroutineRunning:
		return "running"
	case GoroutineExited:
		return "exited without error"
	case GoroutineErrored:
		return "exited with error"
	default:
		panic(errors.Errorf("invalid GoroutineState = %d", s))
	}
}

// A Group is a collection of goroutines working on subtasks that are part of
// the same overall task.
//
// A zero Group is valid and does not cancel on error.
type Group struct {
	cancel func()

	wg sync.WaitGroup

	listMu sync.RWMutex
	list   map[string]GoroutineState

	errOnce sync.Once
	err     error
}

// NewGroup returns a new Group.
//
// The provided 'cancel' function is called the first time a function passed to
// Go returns a non-nil error or the first time Wait returns, whichever occurs
// first.
func NewGroup(cancel func()) *Group {
	return &Group{cancel: cancel}
}

// Wait blocks until all function calls from the Go method have returned, then
// returns the first non-nil error (if any) from them.
func (g *Group) Wait() error {
	g.wg.Wait()
	if g.cancel != nil {
		g.cancel()
	}
	return g.err
}

// Go calls the given function in a new goroutine.
//
// The first call to return a non-nil error cancels the group; its error will be
// returned by Wait.
func (g *Group) Go(name string, f func() error) {
	g.listMu.Lock()
	if g.list == nil {
		g.list = make(map[string]GoroutineState)
	}
	if _, exists := g.list[name]; exists {
		g.wg.Add(1)
		g.listMu.Unlock()
		go func() {
			g.errOnce.Do(func() {
				g.err = errors.Errorf("a goroutine with name %q already exists", name)
				if g.cancel != nil {
					g.cancel()
				}
			})
			g.wg.Done()
		}()
	}
	g.list[name] = GoroutineRunning
	g.wg.Add(1)
	g.listMu.Unlock()

	go func() {
		exitState := GoroutineExited
		if err := f(); err != nil {
			exitState = GoroutineErrored
			g.errOnce.Do(func() {
				g.err = err
				if g.cancel != nil {
					g.cancel()
				}
			})
		}
		g.listMu.Lock()
		if g.list == nil {
			g.list = make(map[string]GoroutineState)
		}
		g.list[name] = exitState
		g.wg.Done()
		g.listMu.Unlock()
	}()
}

// List returns a listing of all goroutines launched with Go.
func (g *Group) List() map[string]GoroutineState {
	g.listMu.RLock()
	defer g.listMu.RUnlock()

	ret := make(map[string]GoroutineState, len(g.list))
	for k, v := range g.list {
		ret[k] = v
	}

	return ret
}
<|endoftext|>


<commit_before>// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Cilium

package resource

import (
	corev1 "k8s.io/api/core/v1"
	k8sRuntime "k8s.io/apimachinery/pkg/runtime"
	"k8s.io/client-go/tools/cache"
)

// Store is a read-only typed wrapper for cache.Store.
type Store[T k8sRuntime.Object] interface {
	// List returns all items currently in the store.
	List() []T

	// IterKeys returns a key iterator.
	IterKeys() KeyIter

	// Get returns the latest version by deriving the key from the given object.
	Get(obj T) (item T, exists bool, err error)

	// GetByKey returns the latest version of the object with given key.
	GetByKey(key Key) (item T, exists bool, err error)
}

// typedStore implements Store on top of an untyped cache.Store.
type typedStore[T k8sRuntime.Object] struct {
	store cache.Store
}

var _ Store[*corev1.Node] = &typedStore[*corev1.Node]{}

func (s *typedStore[T]) List() []T {
	items := s.store.List()
	result := make([]T, len(items))
	for i := range items {
		result[i] = items[i].(T)
	}
	return result
}

func (s *typedStore[T]) IterKeys() KeyIter {
	return &keyIterImpl{keys: s.store.ListKeys(), pos: -1}
}

func (s *typedStore[T]) Get(obj T) (item T, exists bool, err error) {
	return s.GetByKey(NewKey(obj))
}

func (s *typedStore[T]) GetByKey(key Key) (item T, exists bool, err error) {
	var itemAny any
	itemAny, exists, err = s.store.GetByKey(key.String())
	if exists {
		item = itemAny.(T)
	}
	return
}

type KeyIter interface {
	// Next returns true if there is a key, false if iteration has finished.
	Next() bool
	Key() Key
}

type keyIterImpl struct {
	keys []string
	pos  int
}

func (it *keyIterImpl) Next() bool {
	it.pos++
	return it.pos < len(it.keys)
}

func (it *keyIterImpl) Key() Key {
	ns, name, _ := cache.SplitMetaNamespaceKey(it.keys[it.pos])
	// ignoring error from SplitMetaNamespaceKey as the string is from
	// the cache.
	return Key{Namespace: ns, Name: name}
}
<commit_msg>k8s/resource: Expose the underlying cache.Store in Store[T]<commit_after>// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Cilium

package resource

import (
	corev1 "k8s.io/api/core/v1"
	k8sRuntime "k8s.io/apimachinery/pkg/runtime"
	"k8s.io/client-go/tools/cache"
)

// Store is a read-only typed wrapper for cache.Store.
type Store[T k8sRuntime.Object] interface {
	// List returns all items currently in the store.
	List() []T

	// IterKeys returns a key iterator.
	IterKeys() KeyIter

	// Get returns the latest version by deriving the key from the given object.
	Get(obj T) (item T, exists bool, err error)

	// GetByKey returns the latest version of the object with given key.
	GetByKey(key Key) (item T, exists bool, err error)

	// CacheStore returns the underlying cache.Store instance. Use for temporary
	// compatibility purposes only!
	CacheStore() cache.Store
}

// typedStore implements Store on top of an untyped cache.Store.
type typedStore[T k8sRuntime.Object] struct {
	store cache.Store
}

var _ Store[*corev1.Node] = &typedStore[*corev1.Node]{}

func (s *typedStore[T]) List() []T {
	items := s.store.List()
	result := make([]T, len(items))
	for i := range items {
		result[i] = items[i].(T)
	}
	return result
}

func (s *typedStore[T]) IterKeys() KeyIter {
	return &keyIterImpl{keys: s.store.ListKeys(), pos: -1}
}

func (s *typedStore[T]) Get(obj T) (item T, exists bool, err error) {
	return s.GetByKey(NewKey(obj))
}

func (s *typedStore[T]) GetByKey(key Key) (item T, exists bool, err error) {
	var itemAny any
	itemAny, exists, err = s.store.GetByKey(key.String())
	if exists {
		item = itemAny.(T)
	}
	return
}

func (s *typedStore[T]) CacheStore() cache.Store {
	return s.store
}

type KeyIter interface {
	// Next returns true if there is a key, false if iteration has finished.
	Next() bool
	Key() Key
}

type keyIterImpl struct {
	keys []string
	pos  int
}

func (it *keyIterImpl) Next() bool {
	it.pos++
	return it.pos < len(it.keys)
}

func (it *keyIterImpl) Key() Key {
	ns, name, _ := cache.SplitMetaNamespaceKey(it.keys[it.pos])
	// ignoring error from SplitMetaNamespaceKey as the string is from
	// the cache.
	return Key{Namespace: ns, Name: name}
}
<|endoftext|>


<commit_before>// Copyright 2014-2019 the u-root 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 libinit creates the environment and root file system for u-root.
package libinit

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"syscall"

	"github.com/u-root/u-root/pkg/cmdline"
	"github.com/u-root/u-root/pkg/kmodule"
	"github.com/u-root/u-root/pkg/ulog"
	"golang.org/x/sys/unix"
)

type creator interface {
	create() error
	fmt.Stringer
}

type dir struct {
	Name string
	Mode os.FileMode
}

func (d dir) create() error {
	return os.MkdirAll(d.Name, d.Mode)
}

func (d dir) String() string {
	return fmt.Sprintf("dir %q (mode %#o)", d.Name, d.Mode)
}

type symlink struct {
	Target  string
	NewPath string
}

func (s symlink) create() error {
	os.Remove(s.NewPath)
	return os.Symlink(s.Target, s.NewPath)
}

func (s symlink) String() string {
	return fmt.Sprintf("symlink %q -> %q", s.NewPath, s.Target)
}

type dev struct {
	Name string
	Mode uint32
	Dev  int
}

func (d dev) create() error {
	os.Remove(d.Name)
	return syscall.Mknod(d.Name, d.Mode, d.Dev)
}

func (d dev) String() string {
	return fmt.Sprintf("dev %q (mode %#o; magic %d)", d.Name, d.Mode, d.Dev)
}

type mount struct {
	Source string
	Target string
	FSType string
	Flags  uintptr
	Opts   string
}

func (m mount) create() error {
	return syscall.Mount(m.Source, m.Target, m.FSType, m.Flags, m.Opts)
}

func (m mount) String() string {
	return fmt.Sprintf("mount -t %q -o %s %q %q flags %#x", m.FSType, m.Opts, m.Source, m.Target, m.Flags)
}

var (
	// These have to be created / mounted first, so that the logging works correctly.
	preNamespace = []creator{
		dir{Name: "/dev", Mode: 0777},

		// Kernel must be compiled with CONFIG_DEVTMPFS.
		mount{Source: "devtmpfs", Target: "/dev", FSType: "devtmpfs"},
	}
	namespace = []creator{
		dir{Name: "/buildbin", Mode: 0777},
		dir{Name: "/ubin", Mode: 0777},
		dir{Name: "/tmp", Mode: 0777},
		dir{Name: "/env", Mode: 0777},
		dir{Name: "/tcz", Mode: 0777},
		dir{Name: "/lib", Mode: 0777},
		dir{Name: "/usr/lib", Mode: 0777},
		dir{Name: "/var/log", Mode: 0777},
		dir{Name: "/go/pkg/linux_amd64", Mode: 0777},

		dir{Name: "/etc", Mode: 0777},

		dir{Name: "/proc", Mode: 0555},
		mount{Source: "proc", Target: "/proc", FSType: "proc"},
		mount{Source: "tmpfs", Target: "/tmp", FSType: "tmpfs"},

		dev{Name: "/dev/tty", Mode: syscall.S_IFCHR | 0666, Dev: 0x0500},
		dev{Name: "/dev/urandom", Mode: syscall.S_IFCHR | 0444, Dev: 0x0109},
		dev{Name: "/dev/port", Mode: syscall.S_IFCHR | 0640, Dev: 0x0104},

		dir{Name: "/dev/pts", Mode: 0777},
		mount{Source: "devpts", Target: "/dev/pts", FSType: "devpts", Opts: "newinstance,ptmxmode=666,gid=5,mode=620"},
		// Note: if we mount /dev/pts with "newinstance", we *must* make "/dev/ptmx" a symlink to "/dev/pts/ptmx"
		symlink{NewPath: "/dev/ptmx", Target: "/dev/pts/ptmx"},
		// Note: shm is required at least for Chrome. If you don't mount
		// it chrome throws a bogus "out of memory" error, not the more
		// useful "I can't open /dev/shm/whatever". SAD!
		dir{Name: "/dev/shm", Mode: 0777},
		mount{Source: "tmpfs", Target: "/dev/shm", FSType: "tmpfs"},

		dir{Name: "/sys", Mode: 0555},
		mount{Source: "sysfs", Target: "/sys", FSType: "sysfs"},
		mount{Source: "securityfs", Target: "/sys/kernel/security", FSType: "securityfs"},
	}

	// cgroups are optional for most u-root users, especially
	// LinuxBoot/NERF. Some users use u-root for container stuff.
	cgroupsnamespace = []creator{
		mount{Source: "cgroup", Target: "/sys/fs/cgroup", FSType: "tmpfs"},
		dir{Name: "/sys/fs/cgroup/memory", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/freezer", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/devices", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/cpu,cpuacct", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/blkio", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/cpuset", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/pids", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/net_cls,net_prio", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/hugetlb", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/perf_event", Mode: 0555},
		symlink{NewPath: "/sys/fs/cgroup/cpu", Target: "/sys/fs/cgroup/cpu,cpuacct"},
		symlink{NewPath: "/sys/fs/cgroup/cpuacct", Target: "/sys/fs/cgroup/cpu,cpuacct"},
		symlink{NewPath: "/sys/fs/cgroup/net_cls", Target: "/sys/fs/cgroup/net_cls,net_prio"},
		symlink{NewPath: "/sys/fs/cgroup/net_prio", Target: "/sys/fs/cgroup/net_cls,net_prio"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/memory", FSType: "cgroup", Opts: "memory"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/freezer", FSType: "cgroup", Opts: "freezer"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/devices", FSType: "cgroup", Opts: "devices"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/cpu,cpuacct", FSType: "cgroup", Opts: "cpu,cpuacct"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/blkio", FSType: "cgroup", Opts: "blkio"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/cpuset", FSType: "cgroup", Opts: "cpuset"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/pids", FSType: "cgroup", Opts: "pids"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/net_cls,net_prio", FSType: "cgroup", Opts: "net_cls,net_prio"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/hugetlb", FSType: "cgroup", Opts: "hugetlb"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/perf_event", FSType: "cgroup", Opts: "perf_event"},
	}
)

func goBin() string {
	return fmt.Sprintf("/go/bin/%s_%s:/go/bin:/go/pkg/tool/%s_%s", runtime.GOOS, runtime.GOARCH, runtime.GOOS, runtime.GOARCH)
}

func create(namespace []creator, optional bool) {
	// Clear umask bits so that we get stuff like ptmx right.
	m := unix.Umask(0)
	defer unix.Umask(m)
	for _, c := range namespace {
		if err := c.create(); err != nil {
			if optional {
				ulog.KernelLog.Printf("u-root init [optional]: warning creating %s: %v", c, err)
			} else {
				ulog.KernelLog.Printf("u-root init: error creating %s: %v", c, err)
			}
		}
	}
}

// SetEnv sets the default u-root environment.
func SetEnv() {
	env := map[string]string{
		"LD_LIBRARY_PATH": "/usr/local/lib",
		"GOROOT":          "/go",
		"GOPATH":          "/",
		"GOBIN":           "/ubin",
		"CGO_ENABLED":     "0",
		"USER":            "root",
	}

	// Not all these paths may be populated or even exist but OTOH they might.
	path := "/ubin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/bin:/usr/local/sbin:/buildbin:/bbin"

	env["PATH"] = fmt.Sprintf("%v:%v", goBin(), path)
	for k, v := range env {
		os.Setenv(k, v)
	}
}

// CreateRootfs creates the default u-root file system.
func CreateRootfs() {
	// Mount devtmpfs, then open /dev/kmsg with Reinit.
	create(preNamespace, false)
	ulog.KernelLog.Reinit()

	create(namespace, false)

	// systemd gets upset when it discovers something has already setup cgroups
	// We have to do this after the base namespace is created, so we have /proc
	initFlags := cmdline.GetInitFlagMap()
	systemd, present := initFlags["systemd"]
	systemdEnabled, boolErr := strconv.ParseBool(systemd)
	if !present || boolErr != nil || !systemdEnabled {
		create(cgroupsnamespace, true)
	}
}

var (
	excludedMods = map[string]bool{
		"idpf":     true,
		"idpf_imc": true,
	}
)

// InstallAllModules installs kernel modules (.ko files) from /lib/modules.
// Useful for modules that need to be loaded for boot (ie a network
// driver needed for netboot). It skips over blacklisted modules in
// excludedMods.
func InstallAllModules() {
	modulePattern := "/lib/modules/*.ko"
	if err := InstallModules(modulePattern, excludedMods); err != nil {
		log.Print(err)
	}
}

// InstallModules installs kernel modules (.ko files) from /lib/modules that
// match the given pattern, skipping those in the exclude list.
func InstallModules(pattern string, exclude map[string]bool) error {
	files, err := filepath.Glob(pattern)
	if err != nil {
		return err
	}
	if len(files) == 0 {
		return fmt.Errorf("no modules found matching '%s'", pattern)
	}

	for _, filename := range files {
		f, err := os.Open(filename)
		if err != nil {
			log.Printf("installModules: can't open %q: %v", filename, err)
			continue
		}
		// Module flags are passed to the command line in the form modulename.flag=val
		// And must be passed to FileInit as flag=val to be installed properly
		moduleName := strings.TrimSuffix(filepath.Base(filename), filepath.Ext(filename))
		if _, ok := exclude[moduleName]; ok {
			log.Printf("Skipping module %s", moduleName)
			continue
		}

		flags := cmdline.FlagsForModule(moduleName)
		err = kmodule.FileInit(f, flags, 0)
		f.Close()
		if err != nil {
			log.Printf("installModules: can't install %q: %v", filename, err)
		}
	}

	return nil
}
<commit_msg>Copy etc files to tmpfs and mount on etc<commit_after>// Copyright 2014-2019 the u-root 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 libinit creates the environment and root file system for u-root.
package libinit

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"syscall"

	"github.com/u-root/u-root/pkg/cmdline"
	"github.com/u-root/u-root/pkg/cp"
	"github.com/u-root/u-root/pkg/kmodule"
	"github.com/u-root/u-root/pkg/ulog"
	"golang.org/x/sys/unix"
)

type creator interface {
	create() error
	fmt.Stringer
}

type dir struct {
	Name string
	Mode os.FileMode
}

func (d dir) create() error {
	return os.MkdirAll(d.Name, d.Mode)
}

func (d dir) String() string {
	return fmt.Sprintf("dir %q (mode %#o)", d.Name, d.Mode)
}

type symlink struct {
	Target  string
	NewPath string
}

func (s symlink) create() error {
	os.Remove(s.NewPath)
	return os.Symlink(s.Target, s.NewPath)
}

func (s symlink) String() string {
	return fmt.Sprintf("symlink %q -> %q", s.NewPath, s.Target)
}

type dev struct {
	Name string
	Mode uint32
	Dev  int
}

func (d dev) create() error {
	os.Remove(d.Name)
	return syscall.Mknod(d.Name, d.Mode, d.Dev)
}

func (d dev) String() string {
	return fmt.Sprintf("dev %q (mode %#o; magic %d)", d.Name, d.Mode, d.Dev)
}

type mount struct {
	Source string
	Target string
	FSType string
	Flags  uintptr
	Opts   string
}

func (m mount) create() error {
	return syscall.Mount(m.Source, m.Target, m.FSType, m.Flags, m.Opts)
}

func (m mount) String() string {
	return fmt.Sprintf("mount -t %q -o %s %q %q flags %#x", m.FSType, m.Opts, m.Source, m.Target, m.Flags)
}

type cpdir struct {
	Source string
	Target string
}

func (c cpdir) create() error {
	return cp.CopyTree(c.Source, c.Target)
}

func (c cpdir) String() string {
	return fmt.Sprintf("cp -a %q %q", c.Source, c.Target)
}

var (
	// These have to be created / mounted first, so that the logging works correctly.
	preNamespace = []creator{
		dir{Name: "/dev", Mode: 0777},

		// Kernel must be compiled with CONFIG_DEVTMPFS.
		mount{Source: "devtmpfs", Target: "/dev", FSType: "devtmpfs"},
	}
	namespace = []creator{
		dir{Name: "/buildbin", Mode: 0777},
		dir{Name: "/ubin", Mode: 0777},
		dir{Name: "/tmp", Mode: 0777},
		dir{Name: "/env", Mode: 0777},
		dir{Name: "/tcz", Mode: 0777},
		dir{Name: "/lib", Mode: 0777},
		dir{Name: "/usr/lib", Mode: 0777},
		dir{Name: "/var/log", Mode: 0777},
		dir{Name: "/go/pkg/linux_amd64", Mode: 0777},

		dir{Name: "/etc", Mode: 0777},

		dir{Name: "/proc", Mode: 0555},
		mount{Source: "proc", Target: "/proc", FSType: "proc"},
		mount{Source: "tmpfs", Target: "/tmp", FSType: "tmpfs"},

		dev{Name: "/dev/tty", Mode: syscall.S_IFCHR | 0666, Dev: 0x0500},
		dev{Name: "/dev/urandom", Mode: syscall.S_IFCHR | 0444, Dev: 0x0109},
		dev{Name: "/dev/port", Mode: syscall.S_IFCHR | 0640, Dev: 0x0104},

		dir{Name: "/dev/pts", Mode: 0777},
		mount{Source: "devpts", Target: "/dev/pts", FSType: "devpts", Opts: "newinstance,ptmxmode=666,gid=5,mode=620"},
		// Note: if we mount /dev/pts with "newinstance", we *must* make "/dev/ptmx" a symlink to "/dev/pts/ptmx"
		symlink{NewPath: "/dev/ptmx", Target: "/dev/pts/ptmx"},
		// Note: shm is required at least for Chrome. If you don't mount
		// it chrome throws a bogus "out of memory" error, not the more
		// useful "I can't open /dev/shm/whatever". SAD!
		dir{Name: "/dev/shm", Mode: 0777},
		mount{Source: "tmpfs", Target: "/dev/shm", FSType: "tmpfs"},

		dir{Name: "/sys", Mode: 0555},
		mount{Source: "sysfs", Target: "/sys", FSType: "sysfs"},
		mount{Source: "securityfs", Target: "/sys/kernel/security", FSType: "securityfs"},

		cpdir{Source: "/etc", Target: "/tmp/etc"},
		mount{Source: "/tmp/etc", Target: "/etc", FSType: "tmpfs", Flags: unix.MS_BIND},
	}

	// cgroups are optional for most u-root users, especially
	// LinuxBoot/NERF. Some users use u-root for container stuff.
	cgroupsnamespace = []creator{
		mount{Source: "cgroup", Target: "/sys/fs/cgroup", FSType: "tmpfs"},
		dir{Name: "/sys/fs/cgroup/memory", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/freezer", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/devices", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/cpu,cpuacct", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/blkio", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/cpuset", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/pids", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/net_cls,net_prio", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/hugetlb", Mode: 0555},
		dir{Name: "/sys/fs/cgroup/perf_event", Mode: 0555},
		symlink{NewPath: "/sys/fs/cgroup/cpu", Target: "/sys/fs/cgroup/cpu,cpuacct"},
		symlink{NewPath: "/sys/fs/cgroup/cpuacct", Target: "/sys/fs/cgroup/cpu,cpuacct"},
		symlink{NewPath: "/sys/fs/cgroup/net_cls", Target: "/sys/fs/cgroup/net_cls,net_prio"},
		symlink{NewPath: "/sys/fs/cgroup/net_prio", Target: "/sys/fs/cgroup/net_cls,net_prio"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/memory", FSType: "cgroup", Opts: "memory"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/freezer", FSType: "cgroup", Opts: "freezer"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/devices", FSType: "cgroup", Opts: "devices"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/cpu,cpuacct", FSType: "cgroup", Opts: "cpu,cpuacct"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/blkio", FSType: "cgroup", Opts: "blkio"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/cpuset", FSType: "cgroup", Opts: "cpuset"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/pids", FSType: "cgroup", Opts: "pids"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/net_cls,net_prio", FSType: "cgroup", Opts: "net_cls,net_prio"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/hugetlb", FSType: "cgroup", Opts: "hugetlb"},
		mount{Source: "cgroup", Target: "/sys/fs/cgroup/perf_event", FSType: "cgroup", Opts: "perf_event"},
	}
)

func goBin() string {
	return fmt.Sprintf("/go/bin/%s_%s:/go/bin:/go/pkg/tool/%s_%s", runtime.GOOS, runtime.GOARCH, runtime.GOOS, runtime.GOARCH)
}

func create(namespace []creator, optional bool) {
	// Clear umask bits so that we get stuff like ptmx right.
	m := unix.Umask(0)
	defer unix.Umask(m)
	for _, c := range namespace {
		if err := c.create(); err != nil {
			if optional {
				ulog.KernelLog.Printf("u-root init [optional]: warning creating %s: %v", c, err)
			} else {
				ulog.KernelLog.Printf("u-root init: error creating %s: %v", c, err)
			}
		}
	}
}

// SetEnv sets the default u-root environment.
func SetEnv() {
	env := map[string]string{
		"LD_LIBRARY_PATH": "/usr/local/lib",
		"GOROOT":          "/go",
		"GOPATH":          "/",
		"GOBIN":           "/ubin",
		"CGO_ENABLED":     "0",
		"USER":            "root",
	}

	// Not all these paths may be populated or even exist but OTOH they might.
	path := "/ubin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/bin:/usr/local/sbin:/buildbin:/bbin"

	env["PATH"] = fmt.Sprintf("%v:%v", goBin(), path)
	for k, v := range env {
		os.Setenv(k, v)
	}
}

// CreateRootfs creates the default u-root file system.
func CreateRootfs() {
	// Mount devtmpfs, then open /dev/kmsg with Reinit.
	create(preNamespace, false)
	ulog.KernelLog.Reinit()

	create(namespace, false)

	// systemd gets upset when it discovers something has already setup cgroups
	// We have to do this after the base namespace is created, so we have /proc
	initFlags := cmdline.GetInitFlagMap()
	systemd, present := initFlags["systemd"]
	systemdEnabled, boolErr := strconv.ParseBool(systemd)
	if !present || boolErr != nil || !systemdEnabled {
		create(cgroupsnamespace, true)
	}
}

var (
	excludedMods = map[string]bool{
		"idpf":     true,
		"idpf_imc": true,
	}
)

// InstallAllModules installs kernel modules (.ko files) from /lib/modules.
// Useful for modules that need to be loaded for boot (ie a network
// driver needed for netboot). It skips over blacklisted modules in
// excludedMods.
func InstallAllModules() {
	modulePattern := "/lib/modules/*.ko"
	if err := InstallModules(modulePattern, excludedMods); err != nil {
		log.Print(err)
	}
}

// InstallModules installs kernel modules (.ko files) from /lib/modules that
// match the given pattern, skipping those in the exclude list.
func InstallModules(pattern string, exclude map[string]bool) error {
	files, err := filepath.Glob(pattern)
	if err != nil {
		return err
	}
	if len(files) == 0 {
		return fmt.Errorf("no modules found matching '%s'", pattern)
	}

	for _, filename := range files {
		f, err := os.Open(filename)
		if err != nil {
			log.Printf("installModules: can't open %q: %v", filename, err)
			continue
		}
		// Module flags are passed to the command line in the form modulename.flag=val
		// And must be passed to FileInit as flag=val to be installed properly
		moduleName := strings.TrimSuffix(filepath.Base(filename), filepath.Ext(filename))
		if _, ok := exclude[moduleName]; ok {
			log.Printf("Skipping module %s", moduleName)
			continue
		}

		flags := cmdline.FlagsForModule(moduleName)
		err = kmodule.FileInit(f, flags, 0)
		f.Close()
		if err != nil {
			log.Printf("installModules: can't install %q: %v", filename, err)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package logger

import (
	"testing"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/go-redis/redis"
	"github.com/stretchr/testify/assert"
)

func TestDebugDomain(t *testing.T) {
	err := Init(Options{Level: "info"})
	assert.NoError(t, err)

	err = AddDebugDomain("foo.bar")
	assert.NoError(t, err)
	err = AddDebugDomain("foo.bar")
	assert.NoError(t, err)

	log := WithDomain("foo.bar")
	assert.Equal(t, logrus.DebugLevel, log.Logger.Level)

	err = RemoveDebugDomain("foo.bar")
	assert.NoError(t, err)
	log = WithDomain("foo.bar")
	assert.Equal(t, logrus.InfoLevel, log.Logger.Level)
}

func TestDebugDomainWithRedis(t *testing.T) {
	opt, err := redis.ParseURL("redis://localhost:6379/0")
	assert.NoError(t, err)
	err = Init(Options{
		Level: "info",
		Redis: redis.NewClient(opt),
	})
	assert.NoError(t, err)

	err = AddDebugDomain("foo.bar.redis")
	assert.NoError(t, err)
	err = AddDebugDomain("foo.bar.redis")
	assert.NoError(t, err)

	time.Sleep(1 * time.Second)

	log := WithDomain("foo.bar.redis")
	assert.Equal(t, logrus.DebugLevel, log.Logger.Level)

	err = RemoveDebugDomain("foo.bar.redis")
	assert.NoError(t, err)

	time.Sleep(1 * time.Second)

	log = WithDomain("foo.bar.redis")
	assert.Equal(t, logrus.InfoLevel, log.Logger.Level)
}
<commit_msg>Increase time sleep for logger tests<commit_after>package logger

import (
	"testing"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/go-redis/redis"
	"github.com/stretchr/testify/assert"
)

func TestDebugDomain(t *testing.T) {
	err := Init(Options{Level: "info"})
	assert.NoError(t, err)

	err = AddDebugDomain("foo.bar")
	assert.NoError(t, err)
	err = AddDebugDomain("foo.bar")
	assert.NoError(t, err)

	log := WithDomain("foo.bar")
	assert.Equal(t, logrus.DebugLevel, log.Logger.Level)

	err = RemoveDebugDomain("foo.bar")
	assert.NoError(t, err)
	log = WithDomain("foo.bar")
	assert.Equal(t, logrus.InfoLevel, log.Logger.Level)
}

func TestDebugDomainWithRedis(t *testing.T) {
	opt, err := redis.ParseURL("redis://localhost:6379/0")
	assert.NoError(t, err)
	err = Init(Options{
		Level: "info",
		Redis: redis.NewClient(opt),
	})
	assert.NoError(t, err)

	err = AddDebugDomain("foo.bar.redis")
	assert.NoError(t, err)
	err = AddDebugDomain("foo.bar.redis")
	assert.NoError(t, err)

	time.Sleep(2 * time.Second)

	log := WithDomain("foo.bar.redis")
	assert.Equal(t, logrus.DebugLevel, log.Logger.Level)

	err = RemoveDebugDomain("foo.bar.redis")
	assert.NoError(t, err)

	time.Sleep(2 * time.Second)

	log = WithDomain("foo.bar.redis")
	assert.Equal(t, logrus.InfoLevel, log.Logger.Level)
}
<|endoftext|>


<commit_before>package route

import (
	"testing"
)

func TestNext(t *testing.T) {
	input := []byte("0")
	s := newScanner(input)

	ch := s.Current()
	if ch != '0' {
		t.Errorf("ch expect 0 but %c", ch)
	}

	s.Next()
	if ch != eoi {
		t.Errorf("ch expect eoi but %c", ch)
	}
}

func TestNextTokenAndScanString(t *testing.T) {
	input := []byte("0/1(2|3:4)")
	s := newScanner(input)

	s.NextToken()
	token := s.Token()
	if token != tokenSlash {
		t.Errorf("token expect / but %d", token)
	}
	value := string(s.ScanString())
	if value != "0" {
		t.Errorf("scanstring expect 0 but %s", value)
	}

	s.NextToken()
	token = s.Token()
	if token != tokenLParen {
		t.Errorf("token expect ( but %d", token)
	}
	value = string(s.ScanString())
	if value != "1" {
		t.Errorf("scanstring expect 1 but %s", value)
	}

	s.NextToken()
	token = s.Token()
	if token != tokenVertical {
		t.Errorf("token expect | but %d", token)
	}
	value = string(s.ScanString())
	if value != "2" {
		t.Errorf("scanstring expect 2 but %s", value)
	}

	s.NextToken()
	token = s.Token()
	if token != tokenColon {
		t.Errorf("token expect : but %d", token)
	}
	value = string(s.ScanString())
	if value != "3" {
		t.Errorf("scanstring expect 3 but %s", value)
	}

	s.NextToken()
	token = s.Token()
	if token != tokenRParen {
		t.Errorf("token expect ) but %d", token)
	}
	value = string(s.ScanString())
	if value != "4" {
		t.Errorf("scanstring expect 4 but %s", value)
	}

	s.NextToken()
	token = s.Token()
	if token != tokenEOF {
		t.Errorf("token expect eof but %d", token)
	}
	value = string(s.ScanString())
	if value != "" {
		t.Errorf("scanstring expect empty but %s", value)
	}
}
<commit_msg>fix: test<commit_after>package route

import (
	"testing"
)

func TestNext(t *testing.T) {
	input := []byte("0")
	s := newScanner(input)

	ch := s.Current()
	if ch != '0' {
		t.Errorf("ch expect 0 but %c", ch)
	}

	s.Next()
	ch = s.Current()
	if ch != eoi {
		t.Errorf("ch expect eoi but %c", ch)
	}
}

func TestNextTokenAndScanString(t *testing.T) {
	input := []byte("0/1(2|3:4)")
	s := newScanner(input)

	s.NextToken()
	token := s.Token()
	if token != tokenSlash {
		t.Errorf("token expect / but %d", token)
	}
	value := string(s.ScanString())
	if value != "0" {
		t.Errorf("scanstring expect 0 but %s", value)
	}

	s.NextToken()
	token = s.Token()
	if token != tokenLParen {
		t.Errorf("token expect ( but %d", token)
	}
	value = string(s.ScanString())
	if value != "1" {
		t.Errorf("scanstring expect 1 but %s", value)
	}

	s.NextToken()
	token = s.Token()
	if token != tokenVertical {
		t.Errorf("token expect | but %d", token)
	}
	value = string(s.ScanString())
	if value != "2" {
		t.Errorf("scanstring expect 2 but %s", value)
	}

	s.NextToken()
	token = s.Token()
	if token != tokenColon {
		t.Errorf("token expect : but %d", token)
	}
	value = string(s.ScanString())
	if value != "3" {
		t.Errorf("scanstring expect 3 but %s", value)
	}

	s.NextToken()
	token = s.Token()
	if token != tokenRParen {
		t.Errorf("token expect ) but %d", token)
	}
	value = string(s.ScanString())
	if value != "4" {
		t.Errorf("scanstring expect 4 but %s", value)
	}

	s.NextToken()
	token = s.Token()
	if token != tokenEOF {
		t.Errorf("token expect eof but %d", token)
	}
	value = string(s.ScanString())
	if value != "" {
		t.Errorf("scanstring expect empty but %s", value)
	}
}
<|endoftext|>


<commit_before>package main

const NGINX_BUILD_VERSION = "0.1.0"

// nginx
const (
	NGINX_VERSION             = "1.7.8"
	NGINX_DOWNLOAD_URL_PREFIX = "http://nginx.org/download"
)

// pcre
const (
	PCRE_VERSION             = "8.36"
	PCRE_DOWNLOAD_URL_PREFIX = "http://ftp.csx.cam.ac.uk/pub/software/programming/pcre"
)

// openssl
const (
	OPENSSL_VERSION             = "1.0.1j"
	OPENSSL_DOWNLOAD_URL_PREFIX = "http://www.openssl.org/source"
)

// zlib
const (
	ZLIB_VERSION             = "1.2.8"
	ZLIB_DOWNLOAD_URL_PREFIX = "http://zlib.net"
)

// openResty
const (
	OPENRESTY_VERSION             = "1.7.4.1"
	OPENRESTY_DOWNLOAD_URL_PREFIX = "http://openresty.org/download"
)

// component enumerations
const (
	COMPONENT_NGINX = iota
	COMPONENT_OPENRESTY
	COMPONENT_PCRE
	COMPONENT_OPENSSL
	COMPONENT_ZLIB
	COMPONENT_MAX
)
<commit_msg>bumped version to 0.2.0.<commit_after>package main

const NGINX_BUILD_VERSION = "0.2.0"

// nginx
const (
	NGINX_VERSION             = "1.7.8"
	NGINX_DOWNLOAD_URL_PREFIX = "http://nginx.org/download"
)

// pcre
const (
	PCRE_VERSION             = "8.36"
	PCRE_DOWNLOAD_URL_PREFIX = "http://ftp.csx.cam.ac.uk/pub/software/programming/pcre"
)

// openssl
const (
	OPENSSL_VERSION             = "1.0.1j"
	OPENSSL_DOWNLOAD_URL_PREFIX = "http://www.openssl.org/source"
)

// zlib
const (
	ZLIB_VERSION             = "1.2.8"
	ZLIB_DOWNLOAD_URL_PREFIX = "http://zlib.net"
)

// openResty
const (
	OPENRESTY_VERSION             = "1.7.4.1"
	OPENRESTY_DOWNLOAD_URL_PREFIX = "http://openresty.org/download"
)

// component enumerations
const (
	COMPONENT_NGINX = iota
	COMPONENT_OPENRESTY
	COMPONENT_PCRE
	COMPONENT_OPENSSL
	COMPONENT_ZLIB
	COMPONENT_MAX
)
<|endoftext|>


<commit_before>package scipipe

const (
	// BUFSIZE is the standard buffer size used for channels connecting processes
	BUFSIZE = 16
	// Version is the SciPipe version in string format
	Version = "0.8.1"
)
<commit_msg>Bump version to 0.9.1<commit_after>package scipipe

const (
	// BUFSIZE is the standard buffer size used for channels connecting processes
	BUFSIZE = 16
	// Version is the SciPipe version in string format
	Version = "0.9.1"
)
<|endoftext|>


<commit_before><commit_msg>TestCheckRunningWithoutDesiredImageAndNoRemoveExisting<commit_after><|endoftext|>


<commit_before>package fullerene

import (
	"time"
)

type Fullerene struct {
	t time.Time
}

func Now() Fullerene {
	return Fullerene{
		t: time.Now(),
	}
}

func (fr Fullerene) Date() (year int, month time.Month, day int) {
	return fr.t.Date()
}

func (fr Fullerene) After(u Fullerene) bool {
	return fr.t.After(u.t)
}

func (fr Fullerene) Before(u Fullerene) bool {
	return fr.t.Before(u.t)
}

func (fr Fullerene) Equal(u Fullerene) bool {
	return fr.t.Equal(u.t)
}

func (fr Fullerene) IsZero() bool {
	return fr.t.IsZero()
}

func Date(year int, month time.Month, day, hour, min, sec, nsec int, loc *time.Location) Fullerene {
	return Fullerene{t: time.Date(year, month, day, hour, min, sec, nsec, loc)}
}

func (fr Fullerene) Year() int {
	return fr.t.Year()
}

func (fr Fullerene) Month() time.Month {
	return fr.t.Month()
}

func (fr Fullerene) Day() int {
	return fr.t.Day()
}

func (fr Fullerene) AddDate(years int, months int, days int) Fullerene {
	return Fullerene{t: fr.t.AddDate(years, months, days)}
}

func (fr Fullerene) IsLeapYear() bool {
	y := fr.Year()
	return (y%4 == 0 && (y%100 != 0 || y%400 == 0))
}

func (fr Fullerene) IsLeapDay() bool {
	_, m, d := fr.Date()
	return (m == 2 && d == 29)
}

func (fr Fullerene) IsBirthday(targetTime Fullerene, beforeDayIfLeap bool) bool {
	_, m, d := fr.Date()           // birthday
	_, mm, dd := targetTime.Date() // check if it is birthday.
	if m == mm && d == dd && !fr.IsLeapDay() {
		// consider leap year.
		return true
	}

	// there are countries which a person get old at the day before leap day, and the day after in a leap year.
	return fr.isBirthdayEx(targetTime, beforeDayIfLeap)
}

func (fr Fullerene) isBirthdayEx(targetTime Fullerene, beforeDayIfLeap bool) bool {
	_, m, d := targetTime.Date()
	if targetTime.IsLeapYear() {
		return false
	}
	if beforeDayIfLeap && m == 2 && d == 28 {
		return true
	}
	if !beforeDayIfLeap && m == 3 && d == 1 {
		return true
	}
	return false
}

func (fr Fullerene) Age(targetTime Fullerene) int {
	y, m, d := targetTime.Date()
	age := y - fr.Year()
	if m < fr.Month() {
		return age - 1
	}
	if m > fr.Month() {
		return age
	}
	// month of targetTime is equal to birthday.
	if d <= fr.Day() {
		return age
	}
	if d > fr.Day() {
		return age - 1
	}
	return age
}

func (fr Fullerene) CurrentAge() int {
	return fr.Age(Now())
}

func (fr *Fullerene) String() string {
	return fr.t.String()
}
<commit_msg>Add Format method.<commit_after>package fullerene

import (
	"time"
)

type Fullerene struct {
	t time.Time
}

func Now() Fullerene {
	return Fullerene{
		t: time.Now(),
	}
}

func (fr Fullerene) Date() (year int, month time.Month, day int) {
	return fr.t.Date()
}

func (fr Fullerene) After(u Fullerene) bool {
	return fr.t.After(u.t)
}

func (fr Fullerene) Before(u Fullerene) bool {
	return fr.t.Before(u.t)
}

func (fr Fullerene) Equal(u Fullerene) bool {
	return fr.t.Equal(u.t)
}

func (fr Fullerene) IsZero() bool {
	return fr.t.IsZero()
}

func Date(year int, month time.Month, day, hour, min, sec, nsec int, loc *time.Location) Fullerene {
	return Fullerene{t: time.Date(year, month, day, hour, min, sec, nsec, loc)}
}

func (fr Fullerene) Year() int {
	return fr.t.Year()
}

func (fr Fullerene) Month() time.Month {
	return fr.t.Month()
}

func (fr Fullerene) Day() int {
	return fr.t.Day()
}

func (fr Fullerene) AddDate(years int, months int, days int) Fullerene {
	return Fullerene{t: fr.t.AddDate(years, months, days)}
}

func (fr Fullerene) IsLeapYear() bool {
	y := fr.Year()
	return (y%4 == 0 && (y%100 != 0 || y%400 == 0))
}

func (fr Fullerene) IsLeapDay() bool {
	_, m, d := fr.Date()
	return (m == 2 && d == 29)
}

func (fr Fullerene) IsBirthday(targetTime Fullerene, beforeDayIfLeap bool) bool {
	_, m, d := fr.Date()           // birthday
	_, mm, dd := targetTime.Date() // check if it is birthday.
	if m == mm && d == dd && !fr.IsLeapDay() {
		// consider leap year.
		return true
	}

	// there are countries which a person get old at the day before leap day, and the day after in a leap year.
	return fr.isBirthdayEx(targetTime, beforeDayIfLeap)
}

func (fr Fullerene) isBirthdayEx(targetTime Fullerene, beforeDayIfLeap bool) bool {
	_, m, d := targetTime.Date()
	if targetTime.IsLeapYear() {
		return false
	}
	if beforeDayIfLeap && m == 2 && d == 28 {
		return true
	}
	if !beforeDayIfLeap && m == 3 && d == 1 {
		return true
	}
	return false
}

func (fr Fullerene) Age(targetTime Fullerene) int {
	y, m, d := targetTime.Date()
	age := y - fr.Year()
	if m < fr.Month() {
		return age - 1
	}
	if m > fr.Month() {
		return age
	}
	// month of targetTime is equal to birthday.
	if d <= fr.Day() {
		return age
	}
	if d > fr.Day() {
		return age - 1
	}
	return age
}

func (fr Fullerene) CurrentAge() int {
	return fr.Age(Now())
}

func (fr *Fullerene) String() string {
	return fr.t.String()
}

func (fr *Fullerene) Format(layout string) string {
	return fr.t.Format(layout)
}
<|endoftext|>


<commit_before>package flying

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"bitbucket.org/kardianos/osext"
	"github.com/rjeczalik/rw"
)

var nl = "\n"

var errAlreadyStarted = errors.New("flying: command already started")
var errEmptyCommnd = errors.New("flying: empty command")
var errNotRunning = errors.New("flying: command is not running")

// SourceDir TODO
var SourceDir string

func init() {
	if dir, err := osext.ExecutableFolder(); err == nil {
		SourceDir = dir
	}
	if runtime.GOOS == "windows" {
		nl = "\r\n"
	}
}

func now() string {
	return time.Now().Format("2006-01-02 15:04:05")
}

func prefix(app string) func() string {
	return func() string {
		return fmt.Sprintf("[%s] [%s] ", now(), app)
	}
}

// Client TODO
type Client struct {
	// Log TODO
	Log io.WriteCloser

	// Env TODO
	Env []string

	cmd *exec.Cmd
	wc  io.WriteCloser
}

// Start TODO
func (c *Client) Start(cmd []string) error {
	if c.cmd != nil {
		return errAlreadyStarted
	}
	if len(cmd) == 0 {
		return errEmptyCommnd
	}
	cmdname := filepath.Base(cmd[0])
	cwd := "<nil>"
	if wd, err := os.Getwd(); err == nil {
		cwd = wd
	}
	c.printf("flying: started with command=%s, args=[%v], CWD=%s", cmdname,
		strings.Join(cmd[1:], ", "), cwd)
	path, err := exec.LookPath(cmd[0])
	if err != nil {
		return c.exit(err)
	}
	if abspath, err := filepath.Abs(path); err == nil {
		path = abspath
	}
	c.printf("flying: %s is %s", cmdname, path)
	c.cmd = command(path, cmd[1:]...)
	c.cmd.Env = mergenv(os.Environ(), c.Env...)
	c.cmd.Stdout = rw.PrefixWriter(c.log(), prefix(cmdname))
	c.cmd.Stderr = rw.PrefixWriter(c.log(), prefix(cmdname+"] [error"))
	if err = c.cmd.Start(); err != nil {
		return c.exit(err)
	}
	return nil
}

// Interrupt TODO
func (c *Client) Interrupt() error {
	if c.cmd == nil {
		return errNotRunning
	}
	// Interrupt is a wrapper for (*os.Process).Signal(os.Interrupt) - remove it
	// after golang.org/issue/6720.
	return interrupt(c.cmd.Process)
}

// Wait TODO
func (c *Client) Wait() error {
	if c.cmd == nil {
		return errNotRunning
	}
	return c.exit(c.cmd.Wait())
}

// Run TODO
func (c *Client) Run(cmd []string) error {
	return run(c, cmd)
}

func (c *Client) log() io.WriteCloser {
	if c.Log != nil {
		return c.Log
	}
	if c.wc != nil {
		return c.wc
	}
	name := filepath.Join(SourceDir, "flying.log")
	// TODO(rjeczalik): Rotate log each x MiB?
	wc, err := os.OpenFile(name, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0664)
	if err != nil {
		return nopCloser(ioutil.Discard)
	}
	c.wc = wc
	return c.wc
}

func (c *Client) exit(err error) error {
	if err != nil {
		c.printf("flying: failed with: %v", err)
	} else {
		c.printf("flying: exited successfully")
	}
	c.log().Close()
	return err
}

func (c *Client) printf(format string, v ...interface{}) {
	c.log().Write([]byte("[" + now() + "] " + fmt.Sprintf(format, v...) + nl))
}

func runconsole(c *Client, cmd []string) error {
	ch, errch := make(chan os.Signal, 1), make(chan error, 1)
	signal.Notify(ch, Signals...)
	if err := c.Start(cmd); err != nil {
		return err
	}
	go func() {
		for _ = range ch {
			errch <- c.Interrupt()
		}
	}()
	err := c.Wait()
	select {
	case e := <-errch:
		err = nonil(err, e)
	default:
	}
	return err
}

var defaultClient Client

// Run TODO
func Run(cmd []string) error {
	return defaultClient.Run(cmd)
}
<commit_msg>flying: Update osext's repo.<commit_after>package flying

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/kardianos/osext"
	"github.com/rjeczalik/rw"
)

var nl = "\n"

var errAlreadyStarted = errors.New("flying: command already started")
var errEmptyCommnd = errors.New("flying: empty command")
var errNotRunning = errors.New("flying: command is not running")

// SourceDir TODO
var SourceDir string

func init() {
	if dir, err := osext.ExecutableFolder(); err == nil {
		SourceDir = dir
	}
	if runtime.GOOS == "windows" {
		nl = "\r\n"
	}
}

func now() string {
	return time.Now().Format("2006-01-02 15:04:05")
}

func prefix(app string) func() string {
	return func() string {
		return fmt.Sprintf("[%s] [%s] ", now(), app)
	}
}

// Client TODO
type Client struct {
	// Log TODO
	Log io.WriteCloser

	// Env TODO
	Env []string

	cmd *exec.Cmd
	wc  io.WriteCloser
}

// Start TODO
func (c *Client) Start(cmd []string) error {
	if c.cmd != nil {
		return errAlreadyStarted
	}
	if len(cmd) == 0 {
		return errEmptyCommnd
	}
	cmdname := filepath.Base(cmd[0])
	cwd := "<nil>"
	if wd, err := os.Getwd(); err == nil {
		cwd = wd
	}
	c.printf("flying: started with command=%s, args=[%v], CWD=%s", cmdname,
		strings.Join(cmd[1:], ", "), cwd)
	path, err := exec.LookPath(cmd[0])
	if err != nil {
		return c.exit(err)
	}
	if abspath, err := filepath.Abs(path); err == nil {
		path = abspath
	}
	c.printf("flying: %s is %s", cmdname, path)
	c.cmd = command(path, cmd[1:]...)
	c.cmd.Env = mergenv(os.Environ(), c.Env...)
	c.cmd.Stdout = rw.PrefixWriter(c.log(), prefix(cmdname))
	c.cmd.Stderr = rw.PrefixWriter(c.log(), prefix(cmdname+"] [error"))
	if err = c.cmd.Start(); err != nil {
		return c.exit(err)
	}
	return nil
}

// Interrupt TODO
func (c *Client) Interrupt() error {
	if c.cmd == nil {
		return errNotRunning
	}
	// Interrupt is a wrapper for (*os.Process).Signal(os.Interrupt) - remove it
	// after golang.org/issue/6720.
	return interrupt(c.cmd.Process)
}

// Wait TODO
func (c *Client) Wait() error {
	if c.cmd == nil {
		return errNotRunning
	}
	return c.exit(c.cmd.Wait())
}

// Run TODO
func (c *Client) Run(cmd []string) error {
	return run(c, cmd)
}

func (c *Client) log() io.WriteCloser {
	if c.Log != nil {
		return c.Log
	}
	if c.wc != nil {
		return c.wc
	}
	name := filepath.Join(SourceDir, "flying.log")
	// TODO(rjeczalik): Rotate log each x MiB?
	wc, err := os.OpenFile(name, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0664)
	if err != nil {
		return nopCloser(ioutil.Discard)
	}
	c.wc = wc
	return c.wc
}

func (c *Client) exit(err error) error {
	if err != nil {
		c.printf("flying: failed with: %v", err)
	} else {
		c.printf("flying: exited successfully")
	}
	c.log().Close()
	return err
}

func (c *Client) printf(format string, v ...interface{}) {
	c.log().Write([]byte("[" + now() + "] " + fmt.Sprintf(format, v...) + nl))
}

func runconsole(c *Client, cmd []string) error {
	ch, errch := make(chan os.Signal, 1), make(chan error, 1)
	signal.Notify(ch, Signals...)
	if err := c.Start(cmd); err != nil {
		return err
	}
	go func() {
		for _ = range ch {
			errch <- c.Interrupt()
		}
	}()
	err := c.Wait()
	select {
	case e := <-errch:
		err = nonil(err, e)
	default:
	}
	return err
}

var defaultClient Client

// Run TODO
func Run(cmd []string) error {
	return defaultClient.Run(cmd)
}
<|endoftext|>


<commit_before>package langs

import (
	"fmt"
	"os"
	"path/filepath"
	"errors"
	"bytes"
	"strings"
	"net/url"
	"io/ioutil"
)

// JavaLangHelper provides a set of helper methods for the lifecycle of Java Maven projects
type JavaLangHelper struct {
	BaseHelper
}

// BuildFromImage returns the Docker image used to compile the Maven function project
func (lh *JavaLangHelper) BuildFromImage() string { return "maven:3.5-jdk-8-alpine" }

// RunFromImage returns the Docker image used to run the Java function.
func (lh *JavaLangHelper) RunFromImage() string { return "registry.oracledx.com/skeppare/jfaas-runtime:latest" }

// HasPreBuild returns whether the Java runtime has boilerplate that can be generated.
func (lh *JavaLangHelper) HasBoilerplate() bool { return true }

// GenerateBoilerplate will generate function boilerplate for a Java runtime. The default boilerplate is for a Maven
// project.
func (lh *JavaLangHelper) GenerateBoilerplate() error {
	wd, err := os.Getwd()
	if err != nil {
		return err
	}

	pathToPomFile := filepath.Join(wd, "pom.xml")
	if exists(pathToPomFile) {
		return ErrBoilerplateExists
	}

	if err := ioutil.WriteFile(pathToPomFile, []byte(pomFile), os.FileMode(0644)); err != nil {
		return err
	}

	mkDirAndWriteFile := func(dir, filename, content string) error {
		fullPath := filepath.Join(wd, dir)
		if err = os.MkdirAll(fullPath, os.FileMode(0755)); err != nil {
			return err
		}

		fullFilePath := filepath.Join(fullPath, filename)
		return ioutil.WriteFile(fullFilePath, []byte(content), os.FileMode(0644))
	}

	err = mkDirAndWriteFile("src/main/java/com/example/faas", "HelloFunction.java", helloJavaSrcBoilerplate)
	if err != nil {
		return err
	}

	return mkDirAndWriteFile("src/test/java/com/example/faas", "HelloFunctionTest.java", helloJavaTestBoilerplate)
}

// Entrypoint returns the Java runtime Docker entrypoint that will be executed when the function is executed.
func (lh *JavaLangHelper) Cmd() string {
	return "com.example.faas.HelloFunction::handleRequest"
}

// DockerfileCopyCmds returns the Docker COPY command to copy the compiled Java function jar and dependencies.
func (lh *JavaLangHelper) DockerfileCopyCmds() []string {
	return []string{
		"COPY --from=build-stage /function/target/*.jar /function/app/",
		"COPY --from=build-stage /function/target/dependency/*.jar /function/lib/",
	}
}

// DockerfileBuildCmds returns the build stage steps to compile the Maven function project.
func (lh *JavaLangHelper) DockerfileBuildCmds() []string {
	return []string{
		fmt.Sprintf("ENV MAVEN_OPTS %s", mavenOpts()),
		"ADD pom.xml /function/pom.xml",
		"RUN [\"mvn\", \"package\", \"dependency:copy-dependencies\", \"-DincludeScope=runtime\", \"-DskipTests=true\", \"-Dmdep.prependGroupId=true\"]",
		"ADD src /function/src",
		"RUN [\"mvn\", \"package\"]",
	}
}

// HasPreBuild returns whether the Java Maven runtime has a pre-build step.
func (lh *JavaLangHelper) HasPreBuild() bool { return true }

// PreBuild ensures that the expected the function is based is a maven project.
func (lh *JavaLangHelper) PreBuild() error {
	wd, err := os.Getwd()
	if err != nil {
		return err
	}

	if !exists(filepath.Join(wd, "pom.xml")) {
		return errors.New("Could not find pom.xml - are you sure this is a Maven project?")
	}

	return nil
}

func mavenOpts() string {
	var opts bytes.Buffer

	if parsedURL, err := url.Parse(os.Getenv("http_proxy")); err == nil {
		opts.WriteString(fmt.Sprintf("-Dhttp.proxyHost=%s ", parsedURL.Hostname()))
		opts.WriteString(fmt.Sprintf("-Dhttp.proxyPort=%s ", parsedURL.Port()))
	}

	if parsedURL, err := url.Parse(os.Getenv("https_proxy")); err == nil {
		opts.WriteString(fmt.Sprintf("-Dhttps.proxyHost=%s ", parsedURL.Hostname()))
		opts.WriteString(fmt.Sprintf("-Dhttps.proxyPort=%s ", parsedURL.Port()))
	}

	nonProxyHost := os.Getenv("no_proxy")
	opts.WriteString(fmt.Sprintf("-Dhttp.nonProxyHosts=%s ", strings.Replace(nonProxyHost, ",", "|", -1)))

	opts.WriteString("-Dmaven.repo.local=/usr/share/maven/ref/repository")

	return opts.String()
}

/*	TODO temporarily generate maven project boilerplate from hardcoded values.
 	Will eventually move to using a maven archetype.
*/

const (
	pomFile = `<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <groupId>com.example.faas</groupId>
    <artifactId>hello</artifactId>
    <version>1.0.0</version>

    <repositories>
        <repository>
            <id>nexus-box</id>
            <url>http://10.167.103.241:8081/repository/maven-snapshots/</url>
        </repository>
    </repositories>

    <dependencies>
        <dependency>
            <groupId>com.oracle.faas</groupId>
            <artifactId>api</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.oracle.faas</groupId>
            <artifactId>testing</artifactId>
            <version>1.0.0-SNAPSHOT</version>
            <scope>test</scope>
        </dependency>
		<dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
`

	helloJavaSrcBoilerplate = `package com.example.faas;

public class HelloFunction {

    public String handleRequest(String input) {
        String name = (input == null || input.isEmpty()) ? "world"  : input;

        return "Hello, " + name + "!";
    }

}`

	helloJavaTestBoilerplate = `package com.example.faas;

import com.oracle.faas.testing.*;
import org.junit.*;

import static org.junit.Assert.*;

public class HelloFunctionTest {

    @Rule
    public final FnTesting testing = FnTesting.createDefault();

    @Test
    public void shouldReturnGreeting() {
        testing.givenEvent().enqueue();
        testing.thenRun(HelloFunction.class, "handleRequest");

        FnResult result = testing.getOnlyResult();
        assertEquals("Hello, world!", result.getBodyAsString());
    }

}`
)
<commit_msg>Fix formatting to make tests<commit_after>package langs

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"net/url"
	"os"
	"path/filepath"
	"strings"
)

// JavaLangHelper provides a set of helper methods for the lifecycle of Java Maven projects
type JavaLangHelper struct {
	BaseHelper
}

// BuildFromImage returns the Docker image used to compile the Maven function project
func (lh *JavaLangHelper) BuildFromImage() string { return "maven:3.5-jdk-8-alpine" }

// RunFromImage returns the Docker image used to run the Java function.
func (lh *JavaLangHelper) RunFromImage() string {
	return "registry.oracledx.com/skeppare/jfaas-runtime:latest"
}

// HasPreBuild returns whether the Java runtime has boilerplate that can be generated.
func (lh *JavaLangHelper) HasBoilerplate() bool { return true }

// GenerateBoilerplate will generate function boilerplate for a Java runtime. The default boilerplate is for a Maven
// project.
func (lh *JavaLangHelper) GenerateBoilerplate() error {
	wd, err := os.Getwd()
	if err != nil {
		return err
	}

	pathToPomFile := filepath.Join(wd, "pom.xml")
	if exists(pathToPomFile) {
		return ErrBoilerplateExists
	}

	if err := ioutil.WriteFile(pathToPomFile, []byte(pomFile), os.FileMode(0644)); err != nil {
		return err
	}

	mkDirAndWriteFile := func(dir, filename, content string) error {
		fullPath := filepath.Join(wd, dir)
		if err = os.MkdirAll(fullPath, os.FileMode(0755)); err != nil {
			return err
		}

		fullFilePath := filepath.Join(fullPath, filename)
		return ioutil.WriteFile(fullFilePath, []byte(content), os.FileMode(0644))
	}

	err = mkDirAndWriteFile("src/main/java/com/example/faas", "HelloFunction.java", helloJavaSrcBoilerplate)
	if err != nil {
		return err
	}

	return mkDirAndWriteFile("src/test/java/com/example/faas", "HelloFunctionTest.java", helloJavaTestBoilerplate)
}

// Entrypoint returns the Java runtime Docker entrypoint that will be executed when the function is executed.
func (lh *JavaLangHelper) Cmd() string {
	return "com.example.faas.HelloFunction::handleRequest"
}

// DockerfileCopyCmds returns the Docker COPY command to copy the compiled Java function jar and dependencies.
func (lh *JavaLangHelper) DockerfileCopyCmds() []string {
	return []string{
		"COPY --from=build-stage /function/target/*.jar /function/app/",
		"COPY --from=build-stage /function/target/dependency/*.jar /function/lib/",
	}
}

// DockerfileBuildCmds returns the build stage steps to compile the Maven function project.
func (lh *JavaLangHelper) DockerfileBuildCmds() []string {
	return []string{
		fmt.Sprintf("ENV MAVEN_OPTS %s", mavenOpts()),
		"ADD pom.xml /function/pom.xml",
		"RUN [\"mvn\", \"package\", \"dependency:copy-dependencies\", \"-DincludeScope=runtime\", \"-DskipTests=true\", \"-Dmdep.prependGroupId=true\"]",
		"ADD src /function/src",
		"RUN [\"mvn\", \"package\"]",
	}
}

// HasPreBuild returns whether the Java Maven runtime has a pre-build step.
func (lh *JavaLangHelper) HasPreBuild() bool { return true }

// PreBuild ensures that the expected the function is based is a maven project.
func (lh *JavaLangHelper) PreBuild() error {
	wd, err := os.Getwd()
	if err != nil {
		return err
	}

	if !exists(filepath.Join(wd, "pom.xml")) {
		return errors.New("Could not find pom.xml - are you sure this is a Maven project?")
	}

	return nil
}

func mavenOpts() string {
	var opts bytes.Buffer

	if parsedURL, err := url.Parse(os.Getenv("http_proxy")); err == nil {
		opts.WriteString(fmt.Sprintf("-Dhttp.proxyHost=%s ", parsedURL.Hostname()))
		opts.WriteString(fmt.Sprintf("-Dhttp.proxyPort=%s ", parsedURL.Port()))
	}

	if parsedURL, err := url.Parse(os.Getenv("https_proxy")); err == nil {
		opts.WriteString(fmt.Sprintf("-Dhttps.proxyHost=%s ", parsedURL.Hostname()))
		opts.WriteString(fmt.Sprintf("-Dhttps.proxyPort=%s ", parsedURL.Port()))
	}

	nonProxyHost := os.Getenv("no_proxy")
	opts.WriteString(fmt.Sprintf("-Dhttp.nonProxyHosts=%s ", strings.Replace(nonProxyHost, ",", "|", -1)))

	opts.WriteString("-Dmaven.repo.local=/usr/share/maven/ref/repository")

	return opts.String()
}

/*	TODO temporarily generate maven project boilerplate from hardcoded values.
	Will eventually move to using a maven archetype.
*/

const (
	pomFile = `<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <groupId>com.example.faas</groupId>
    <artifactId>hello</artifactId>
    <version>1.0.0</version>

    <repositories>
        <repository>
            <id>nexus-box</id>
            <url>http://10.167.103.241:8081/repository/maven-snapshots/</url>
        </repository>
    </repositories>

    <dependencies>
        <dependency>
            <groupId>com.oracle.faas</groupId>
            <artifactId>api</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.oracle.faas</groupId>
            <artifactId>testing</artifactId>
            <version>1.0.0-SNAPSHOT</version>
            <scope>test</scope>
        </dependency>
		<dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
`

	helloJavaSrcBoilerplate = `package com.example.faas;

public class HelloFunction {

    public String handleRequest(String input) {
        String name = (input == null || input.isEmpty()) ? "world"  : input;

        return "Hello, " + name + "!";
    }

}`

	helloJavaTestBoilerplate = `package com.example.faas;

import com.oracle.faas.testing.*;
import org.junit.*;

import static org.junit.Assert.*;

public class HelloFunctionTest {

    @Rule
    public final FnTesting testing = FnTesting.createDefault();

    @Test
    public void shouldReturnGreeting() {
        testing.givenEvent().enqueue();
        testing.thenRun(HelloFunction.class, "handleRequest");

        FnResult result = testing.getOnlyResult();
        assertEquals("Hello, world!", result.getBodyAsString());
    }

}`
)
<|endoftext|>


<commit_before>package rewrite

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"regexp"
	"strings"

	"github.com/mailgun/vulcand/Godeps/_workspace/src/github.com/codegangsta/cli"
	"github.com/mailgun/vulcand/Godeps/_workspace/src/github.com/mailgun/log"
	"github.com/mailgun/vulcand/Godeps/_workspace/src/github.com/mailgun/oxy/utils"
	"github.com/mailgun/vulcand/plugin"
)

const Type = "rewrite"

type Rewrite struct {
	Regexp      string
	Replacement string
	RewriteBody bool
	Redirect    bool
}

func NewRewrite(regex, replacement string, rewriteBody, redirect bool) (*Rewrite, error) {
	return &Rewrite{regex, replacement, rewriteBody, redirect}, nil
}

func (rw *Rewrite) NewHandler(next http.Handler) (http.Handler, error) {
	return newRewriteHandler(next, rw)
}

func (rw *Rewrite) String() string {
	return fmt.Sprintf("regexp=%v, replacement=%v, rewriteBody=%v, redirect=%v",
		rw.Regexp, rw.Replacement, rw.RewriteBody, rw.Redirect)
}

type rewriteHandler struct {
	next        http.Handler
	errHandler  utils.ErrorHandler
	regexp      *regexp.Regexp
	replacement string
	rewriteBody bool
	redirect    bool
}

func newRewriteHandler(next http.Handler, spec *Rewrite) (*rewriteHandler, error) {
	re, err := regexp.Compile(spec.Regexp)
	if err != nil {
		return nil, err
	}
	return &rewriteHandler{
		regexp:      re,
		replacement: spec.Replacement,
		rewriteBody: spec.RewriteBody,
		redirect:    spec.Redirect,
		next:        next,
		errHandler:  utils.DefaultHandler,
	}, nil
}

func (rw *rewriteHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	oldURL := rawURL(req)

	// apply a rewrite regexp to the URL
	newURL := rw.regexp.ReplaceAllString(oldURL, rw.replacement)

	// replace any variables that may be in there
	rewrittenURL := &bytes.Buffer{}
	if err := ApplyString(newURL, rewrittenURL, req); err != nil {
		rw.errHandler.ServeHTTP(w, req, err)
		return
	}

	// parse the rewritten URL and replace request URL with it
	parsedURL, err := url.Parse(rewrittenURL.String())
	if err != nil {
		rw.errHandler.ServeHTTP(w, req, err)
		return
	}

	if rw.redirect {
		(&redirectHandler{u: parsedURL}).ServeHTTP(w, req)
		return
	}

	req.URL = parsedURL
	req.RequestURI = req.URL.Path

	if !rw.rewriteBody {
		rw.next.ServeHTTP(w, req)
		return
	}

	bw := &bufferWriter{header: make(http.Header), buffer: &bytes.Buffer{}}
	newBody := &bytes.Buffer{}

	rw.next.ServeHTTP(bw, req)

	if err := Apply(bw.buffer, newBody, req); err != nil {
		log.Errorf("Failed to rewrite response body: %v", err)
		return
	}

	utils.CopyHeaders(w.Header(), bw.Header())
	w.WriteHeader(bw.code)
	io.Copy(w, newBody)
}

func FromOther(rw Rewrite) (plugin.Middleware, error) {
	return NewRewrite(rw.Regexp, rw.Replacement, rw.RewriteBody, rw.Redirect)
}

func FromCli(c *cli.Context) (plugin.Middleware, error) {
	return NewRewrite(c.String("regexp"), c.String("replacement"), c.Bool("rewriteBody"), c.Bool("redirect"))
}

func GetSpec() *plugin.MiddlewareSpec {
	return &plugin.MiddlewareSpec{
		Type:      Type,
		FromOther: FromOther,
		FromCli:   FromCli,
		CliFlags:  CliFlags(),
	}
}

func CliFlags() []cli.Flag {
	return []cli.Flag{
		cli.StringFlag{
			Name:  "regexp",
			Usage: "regex to match against http request path",
		},
		cli.StringFlag{
			Name:  "replacement",
			Usage: "replacement text into which regex expansions are inserted",
		},
		cli.BoolFlag{
			Name:  "rewriteBody",
			Usage: "if provided, response body is treated as as template and all variables in it are replaced",
		},
		cli.BoolFlag{
			Name:  "redirect",
			Usage: "if provided, request is redirected to the rewritten URL",
		},
	}
}

func rawURL(request *http.Request) string {
	scheme := "http"
	if request.URL.Scheme != "" {
		scheme = request.URL.Scheme
	}
	return strings.Join([]string{scheme, "://", request.Host, request.RequestURI}, "")
}

type redirectHandler struct {
	u *url.URL
}

func (f *redirectHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	w.Header().Set("Location", f.u.String())
	w.WriteHeader(http.StatusFound)
	w.Write([]byte(http.StatusText(http.StatusFound)))
}

type bufferWriter struct {
	header http.Header
	code   int
	buffer *bytes.Buffer
}

func (b *bufferWriter) Close() error {
	return nil
}

func (b *bufferWriter) Header() http.Header {
	return b.header
}

func (b *bufferWriter) Write(buf []byte) (int, error) {
	return b.buffer.Write(buf)
}

// WriteHeader sets rw.Code.
func (b *bufferWriter) WriteHeader(code int) {
	b.code = code
}
<commit_msg>Fix rewrite.go: redirect http to https<commit_after>package rewrite

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"regexp"
	"strings"

	"github.com/mailgun/vulcand/Godeps/_workspace/src/github.com/codegangsta/cli"
	"github.com/mailgun/vulcand/Godeps/_workspace/src/github.com/mailgun/log"
	"github.com/mailgun/vulcand/Godeps/_workspace/src/github.com/mailgun/oxy/utils"
	"github.com/mailgun/vulcand/plugin"
)

const Type = "rewrite"

type Rewrite struct {
	Regexp      string
	Replacement string
	RewriteBody bool
	Redirect    bool
}

func NewRewrite(regex, replacement string, rewriteBody, redirect bool) (*Rewrite, error) {
	return &Rewrite{regex, replacement, rewriteBody, redirect}, nil
}

func (rw *Rewrite) NewHandler(next http.Handler) (http.Handler, error) {
	return newRewriteHandler(next, rw)
}

func (rw *Rewrite) String() string {
	return fmt.Sprintf("regexp=%v, replacement=%v, rewriteBody=%v, redirect=%v",
		rw.Regexp, rw.Replacement, rw.RewriteBody, rw.Redirect)
}

type rewriteHandler struct {
	next        http.Handler
	errHandler  utils.ErrorHandler
	regexp      *regexp.Regexp
	replacement string
	rewriteBody bool
	redirect    bool
}

func newRewriteHandler(next http.Handler, spec *Rewrite) (*rewriteHandler, error) {
	re, err := regexp.Compile(spec.Regexp)
	if err != nil {
		return nil, err
	}
	return &rewriteHandler{
		regexp:      re,
		replacement: spec.Replacement,
		rewriteBody: spec.RewriteBody,
		redirect:    spec.Redirect,
		next:        next,
		errHandler:  utils.DefaultHandler,
	}, nil
}

func (rw *rewriteHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	oldURL := rawURL(req)

	// apply a rewrite regexp to the URL
	newURL := rw.regexp.ReplaceAllString(oldURL, rw.replacement)

	// replace any variables that may be in there
	rewrittenURL := &bytes.Buffer{}
	if err := ApplyString(newURL, rewrittenURL, req); err != nil {
		rw.errHandler.ServeHTTP(w, req, err)
		return
	}

	// parse the rewritten URL and replace request URL with it
	parsedURL, err := url.Parse(rewrittenURL.String())
	if err != nil {
		rw.errHandler.ServeHTTP(w, req, err)
		return
	}

	if rw.redirect && newURL != oldURL {
		(&redirectHandler{u: parsedURL}).ServeHTTP(w, req)
		return
	}

	req.URL = parsedURL
	req.RequestURI = req.URL.Path

	if !rw.rewriteBody {
		rw.next.ServeHTTP(w, req)
		return
	}

	bw := &bufferWriter{header: make(http.Header), buffer: &bytes.Buffer{}}
	newBody := &bytes.Buffer{}

	rw.next.ServeHTTP(bw, req)

	if err := Apply(bw.buffer, newBody, req); err != nil {
		log.Errorf("Failed to rewrite response body: %v", err)
		return
	}

	utils.CopyHeaders(w.Header(), bw.Header())
	w.WriteHeader(bw.code)
	io.Copy(w, newBody)
}

func FromOther(rw Rewrite) (plugin.Middleware, error) {
	return NewRewrite(rw.Regexp, rw.Replacement, rw.RewriteBody, rw.Redirect)
}

func FromCli(c *cli.Context) (plugin.Middleware, error) {
	return NewRewrite(c.String("regexp"), c.String("replacement"), c.Bool("rewriteBody"), c.Bool("redirect"))
}

func GetSpec() *plugin.MiddlewareSpec {
	return &plugin.MiddlewareSpec{
		Type:      Type,
		FromOther: FromOther,
		FromCli:   FromCli,
		CliFlags:  CliFlags(),
	}
}

func CliFlags() []cli.Flag {
	return []cli.Flag{
		cli.StringFlag{
			Name:  "regexp",
			Usage: "regex to match against http request path",
		},
		cli.StringFlag{
			Name:  "replacement",
			Usage: "replacement text into which regex expansions are inserted",
		},
		cli.BoolFlag{
			Name:  "rewriteBody",
			Usage: "if provided, response body is treated as as template and all variables in it are replaced",
		},
		cli.BoolFlag{
			Name:  "redirect",
			Usage: "if provided, request is redirected to the rewritten URL",
		},
	}
}

func rawURL(request *http.Request) string {
	scheme := "http"
	if request.TLS != nil {
		scheme = "https"
	}
	return strings.Join([]string{scheme, "://", request.Host, request.RequestURI}, "")
}

type redirectHandler struct {
	u *url.URL
}

func (f *redirectHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	w.Header().Set("Location", f.u.String())
	w.WriteHeader(http.StatusFound)
	w.Write([]byte(http.StatusText(http.StatusFound)))
}

type bufferWriter struct {
	header http.Header
	code   int
	buffer *bytes.Buffer
}

func (b *bufferWriter) Close() error {
	return nil
}

func (b *bufferWriter) Header() http.Header {
	return b.header
}

func (b *bufferWriter) Write(buf []byte) (int, error) {
	return b.buffer.Write(buf)
}

// WriteHeader sets rw.Code.
func (b *bufferWriter) WriteHeader(code int) {
	b.code = code
}
<|endoftext|>


<commit_before>package functions

import (
	"html/template"
)

var (
	Bold = func(content string) (template.HTML, error) {
		return template.HTML("" + content + ""),nil
	}
	Italic = func(content string) (template.HTML, error) {
		return template.HTML("" + content + ""),nil
	}
	Underline = func(content string) (template.HTML, error) {
		return template.HTML("" + content + ""),nil
	}
)

func RemoveDuplicates(a []string) []string {
	result := []string{}
	seen := map[string]string{}
	for _, val := range a {
		if _, ok := seen[val]; !ok {
			result = append(result, val)
			seen[val] = val
		}
	}
	return result
}
<commit_msg>Made functions public<commit_after>package functions

import (
	"html/template"
	"os"
)

var (
	Bold = func(content string) (template.HTML, error) {
		return template.HTML("" + content + ""), nil
	}
	Italic = func(content string) (template.HTML, error) {
		return template.HTML("" + content + ""), nil
	}
	Underline = func(content string) (template.HTML, error) {
		return template.HTML("" + content + ""), nil
	}
)

func Exists(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}
	if os.IsNotExist(err) {
		return false
	}
	return true
}

func RemoveDuplicates(a []string) []string {
	result := []string{}
	seen := map[string]string{}
	for _, val := range a {
		if _, ok := seen[val]; !ok {
			result = append(result, val)
			seen[val] = val
		}
	}
	return result
}
<|endoftext|>


<commit_before>// A Gesture interface to various YouTubery
package youtube

import (
	"net/http"
	"errors"
	"github.com/sdstrowes/gesture/core"
	"log"
	"math/rand"
	"github.com/google/google-api-go-client/googleapi/transport"
	"github.com/google/google-api-go-client/youtube/v3"
)

const developerKey = "nope"

func Create(bot *core.Gobot, config map[string]interface{}) {
	results, ok := config["results"].(float64)
	if !ok {
		log.Print("Failed to load config for 'youtube' plugin. Using default result count of 1")
		results = 1
	}

	bot.ListenFor("^yt (.*)", func(msg core.Message, matches []string) core.Response {
		link, err := search(matches[1], int64(results))
		if err != nil {
			return bot.Error(err)
		}
		if link != "" {
			msg.Ftfy(link)
		}
		return bot.Stop()
	})
}

// Search youtube for the given query string. Returns one of the first N youtube
// results for that search at random (everyone loves entropy!)
// Returns an empty string if there were no results for that query
func search(q string, results int64) (link string, err error) {
	client := &http.Client{
		Transport: &transport.APIKey{Key: developerKey},
	}

	service, err := youtube.New(client)
	if err != nil {
		log.Fatalf("Error creating new YouTube client: %v", err)
	}

	call := service.Search.List("id,snippet").Q(q).MaxResults(results)
	response, err := call.Do()
	if err != nil {
		return
	}

	switch l := len(response.Items); {
	case l == 0:
		err = errors.New("No results for \"" + q + "\"")
	case l > 0:
		var n = rand.Intn(len(response.Items))
		link = "\""+response.Items[n].Snippet.Title+"\": https://www.youtube.com/watch?v="+response.Items[n].Id.VideoId;
	}

	return
}
<commit_msg>update location of google go api code<commit_after>// A Gesture interface to various YouTubery
package youtube

import (
	"net/http"
	"errors"
	"github.com/sdstrowes/gesture/core"
	"log"
	"math/rand"
	"google.golang.org/api/googleapi/transport"
	"google.golang.org/api/youtube/v3"
)

const developerKey = "nope"

func Create(bot *core.Gobot, config map[string]interface{}) {
	results, ok := config["results"].(float64)
	if !ok {
		log.Print("Failed to load config for 'youtube' plugin. Using default result count of 1")
		results = 1
	}

	bot.ListenFor("^yt (.*)", func(msg core.Message, matches []string) core.Response {
		link, err := search(matches[1], int64(results))
		if err != nil {
			return bot.Error(err)
		}
		if link != "" {
			msg.Ftfy(link)
		}
		return bot.Stop()
	})
}

// Search youtube for the given query string. Returns one of the first N youtube
// results for that search at random (everyone loves entropy!)
// Returns an empty string if there were no results for that query
func search(q string, results int64) (link string, err error) {
	client := &http.Client{
		Transport: &transport.APIKey{Key: developerKey},
	}

	service, err := youtube.New(client)
	if err != nil {
		log.Fatalf("Error creating new YouTube client: %v", err)
	}

	call := service.Search.List("id,snippet").Q(q).MaxResults(results)
	response, err := call.Do()
	if err != nil {
		return
	}

	switch l := len(response.Items); {
	case l == 0:
		err = errors.New("No results for \"" + q + "\"")
	case l > 0:
		var n = rand.Intn(len(response.Items))
		link = "\""+response.Items[n].Snippet.Title+"\": https://www.youtube.com/watch?v="+response.Items[n].Id.VideoId;
	}

	return
}
<|endoftext|>