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

package buffered

import (
	"image"
	"image/color"

	"github.com/hajimehoshi/ebiten/internal/affine"
	"github.com/hajimehoshi/ebiten/internal/driver"
	"github.com/hajimehoshi/ebiten/internal/mipmap"
)

type Image struct {
	img    *mipmap.Mipmap
	width  int
	height int

	pixels               []byte
	needsToResolvePixels bool
}

func BeginFrame() error {
	if err := mipmap.BeginFrame(); err != nil {
		return err
	}
	flushDelayedCommands()
	return nil
}

func EndFrame() error {
	return mipmap.EndFrame()
}

func NewImage(width, height int, volatile bool) *Image {
	i := &Image{}
	delayedCommandsM.Lock()
	if needsToDelayCommands {
		delayedCommands = append(delayedCommands, func() {
			i.img = mipmap.New(width, height, volatile)
			i.width = width
			i.height = height
		})
		delayedCommandsM.Unlock()
		return i
	}
	delayedCommandsM.Unlock()

	i.img = mipmap.New(width, height, volatile)
	i.width = width
	i.height = height
	return i
}

func NewScreenFramebufferImage(width, height int) *Image {
	i := &Image{}
	delayedCommandsM.Lock()
	if needsToDelayCommands {
		delayedCommands = append(delayedCommands, func() {
			i.img = mipmap.NewScreenFramebufferMipmap(width, height)
			i.width = width
			i.height = height
		})
		delayedCommandsM.Unlock()
		return i
	}
	delayedCommandsM.Unlock()

	i.img = mipmap.NewScreenFramebufferMipmap(width, height)
	i.width = width
	i.height = height
	return i
}

func (i *Image) invalidatePendingPixels() {
	i.pixels = nil
	i.needsToResolvePixels = false
}

func (i *Image) resolvePendingPixels(keepPendingPixels bool) {
	if !i.needsToResolvePixels {
		return
	}

	i.img.ReplacePixels(i.pixels)
	if !keepPendingPixels {
		i.pixels = nil
	}
	i.needsToResolvePixels = false
}

func (i *Image) MarkDisposed() {
	delayedCommandsM.Lock()
	if needsToDelayCommands {
		delayedCommands = append(delayedCommands, func() {
			i.img.MarkDisposed()
		})
		delayedCommandsM.Unlock()
		return
	}
	delayedCommandsM.Unlock()

	i.invalidatePendingPixels()
}

func (i *Image) At(x, y int) (r, g, b, a byte) {
	delayedCommandsM.Lock()
	defer delayedCommandsM.Unlock()
	if needsToDelayCommands {
		panic("buffered: the command queue is not available yet at At")
	}
	// TODO: Use pending pixels
	i.resolvePendingPixels(true)
	return i.img.At(x, y)
}

func (i *Image) Set(x, y int, r, g, b, a byte) {
	delayedCommandsM.Lock()
	if needsToDelayCommands {
		delayedCommands = append(delayedCommands, func() {
			i.set(x, y, r, g, b, a)
		})
		delayedCommandsM.Unlock()
		return
	}
	delayedCommandsM.Unlock()

	i.set(x, y, r, g, b, a)
}

func (img *Image) set(x, y int, r, g, b, a byte) {
	w, h := img.width, img.height
	if img.pixels == nil {
		pix := make([]byte, 4*w*h)
		idx := 0
		for j := 0; j < h; j++ {
			for i := 0; i < w; i++ {
				r, g, b, a := img.img.At(i, j)
				pix[4*idx] = r
				pix[4*idx+1] = g
				pix[4*idx+2] = b
				pix[4*idx+3] = a
				idx++
			}
		}
		img.pixels = pix
	}
	img.pixels[4*(x+y*w)] = r
	img.pixels[4*(x+y*w)+1] = g
	img.pixels[4*(x+y*w)+2] = b
	img.pixels[4*(x+y*w)+3] = a
	img.needsToResolvePixels = true
}

func (i *Image) Dump(name string) error {
	delayedCommandsM.Lock()
	defer delayedCommandsM.Unlock()
	if needsToDelayCommands {
		panic("buffered: the command queue is not available yet at Dump")
	}
	return i.img.Dump(name)
}

func (i *Image) Fill(clr color.RGBA) {
	delayedCommandsM.Lock()
	if needsToDelayCommands {
		delayedCommands = append(delayedCommands, func() {
			i.img.Fill(clr)
		})
		delayedCommandsM.Unlock()
		return
	}
	delayedCommandsM.Unlock()

	i.invalidatePendingPixels()
	i.img.Fill(clr)
}

func (i *Image) ReplacePixels(pix []byte) {
	delayedCommandsM.Lock()
	if needsToDelayCommands {
		delayedCommands = append(delayedCommands, func() {
			copied := make([]byte, len(pix))
			copy(copied, pix)
			i.img.ReplacePixels(copied)
		})
		delayedCommandsM.Unlock()
		return
	}
	delayedCommandsM.Unlock()

	i.invalidatePendingPixels()
	i.img.ReplacePixels(pix)
}

func (i *Image) DrawImage(src *Image, bounds image.Rectangle, a, b, c, d, tx, ty float32, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter) {
	if i == src {
		panic("buffered: Image.DrawImage: src must be different from the receiver")
	}

	g := &mipmap.GeoM{
		A:  a,
		B:  b,
		C:  c,
		D:  d,
		Tx: tx,
		Ty: ty,
	}

	delayedCommandsM.Lock()
	if needsToDelayCommands {
		delayedCommands = append(delayedCommands, func() {
			i.img.DrawImage(src.img, bounds, g, colorm, mode, filter)
		})
		delayedCommandsM.Unlock()
		return
	}
	delayedCommandsM.Unlock()

	src.resolvePendingPixels(true)
	i.resolvePendingPixels(false)
	i.img.DrawImage(src.img, bounds, g, colorm, mode, filter)
}

func (i *Image) DrawTriangles(src *Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address) {
	if i == src {
		panic("buffered: Image.DrawTriangles: src must be different from the receiver")
	}

	delayedCommandsM.Lock()
	if needsToDelayCommands {
		delayedCommands = append(delayedCommands, func() {
			i.img.DrawTriangles(src.img, vertices, indices, colorm, mode, filter, address)
		})
		delayedCommandsM.Unlock()
		return
	}
	delayedCommandsM.Unlock()

	src.resolvePendingPixels(true)
	i.resolvePendingPixels(false)
	i.img.DrawTriangles(src.img, vertices, indices, colorm, mode, filter, address)
}
<commit_msg>buffered: Fix delayed DrawImage() (#1050)<commit_after>// Copyright 2019 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package buffered

import (
	"image"
	"image/color"

	"github.com/hajimehoshi/ebiten/internal/affine"
	"github.com/hajimehoshi/ebiten/internal/driver"
	"github.com/hajimehoshi/ebiten/internal/mipmap"
)

type Image struct {
	img    *mipmap.Mipmap
	width  int
	height int

	pixels               []byte
	needsToResolvePixels bool
}

func BeginFrame() error {
	if err := mipmap.BeginFrame(); err != nil {
		return err
	}
	flushDelayedCommands()
	return nil
}

func EndFrame() error {
	return mipmap.EndFrame()
}

func NewImage(width, height int, volatile bool) *Image {
	i := &Image{}
	delayedCommandsM.Lock()
	if needsToDelayCommands {
		delayedCommands = append(delayedCommands, func() {
			i.img = mipmap.New(width, height, volatile)
			i.width = width
			i.height = height
		})
		delayedCommandsM.Unlock()
		return i
	}
	delayedCommandsM.Unlock()

	i.img = mipmap.New(width, height, volatile)
	i.width = width
	i.height = height
	return i
}

func NewScreenFramebufferImage(width, height int) *Image {
	i := &Image{}
	delayedCommandsM.Lock()
	if needsToDelayCommands {
		delayedCommands = append(delayedCommands, func() {
			i.img = mipmap.NewScreenFramebufferMipmap(width, height)
			i.width = width
			i.height = height
		})
		delayedCommandsM.Unlock()
		return i
	}
	delayedCommandsM.Unlock()

	i.img = mipmap.NewScreenFramebufferMipmap(width, height)
	i.width = width
	i.height = height
	return i
}

func (i *Image) invalidatePendingPixels() {
	i.pixels = nil
	i.needsToResolvePixels = false
}

func (i *Image) resolvePendingPixels(keepPendingPixels bool) {
	if !i.needsToResolvePixels {
		return
	}

	i.img.ReplacePixels(i.pixels)
	if !keepPendingPixels {
		i.pixels = nil
	}
	i.needsToResolvePixels = false
}

func (i *Image) MarkDisposed() {
	delayedCommandsM.Lock()
	if needsToDelayCommands {
		delayedCommands = append(delayedCommands, func() {
			i.img.MarkDisposed()
		})
		delayedCommandsM.Unlock()
		return
	}
	delayedCommandsM.Unlock()

	i.invalidatePendingPixels()
}

func (i *Image) At(x, y int) (r, g, b, a byte) {
	delayedCommandsM.Lock()
	defer delayedCommandsM.Unlock()
	if needsToDelayCommands {
		panic("buffered: the command queue is not available yet at At")
	}
	// TODO: Use pending pixels
	i.resolvePendingPixels(true)
	return i.img.At(x, y)
}

func (i *Image) Set(x, y int, r, g, b, a byte) {
	delayedCommandsM.Lock()
	if needsToDelayCommands {
		delayedCommands = append(delayedCommands, func() {
			i.set(x, y, r, g, b, a)
		})
		delayedCommandsM.Unlock()
		return
	}
	delayedCommandsM.Unlock()

	i.set(x, y, r, g, b, a)
}

func (img *Image) set(x, y int, r, g, b, a byte) {
	w, h := img.width, img.height
	if img.pixels == nil {
		pix := make([]byte, 4*w*h)
		idx := 0
		for j := 0; j < h; j++ {
			for i := 0; i < w; i++ {
				r, g, b, a := img.img.At(i, j)
				pix[4*idx] = r
				pix[4*idx+1] = g
				pix[4*idx+2] = b
				pix[4*idx+3] = a
				idx++
			}
		}
		img.pixels = pix
	}
	img.pixels[4*(x+y*w)] = r
	img.pixels[4*(x+y*w)+1] = g
	img.pixels[4*(x+y*w)+2] = b
	img.pixels[4*(x+y*w)+3] = a
	img.needsToResolvePixels = true
}

func (i *Image) Dump(name string) error {
	delayedCommandsM.Lock()
	defer delayedCommandsM.Unlock()
	if needsToDelayCommands {
		panic("buffered: the command queue is not available yet at Dump")
	}
	return i.img.Dump(name)
}

func (i *Image) Fill(clr color.RGBA) {
	delayedCommandsM.Lock()
	if needsToDelayCommands {
		delayedCommands = append(delayedCommands, func() {
			i.img.Fill(clr)
		})
		delayedCommandsM.Unlock()
		return
	}
	delayedCommandsM.Unlock()

	i.invalidatePendingPixels()
	i.img.Fill(clr)
}

func (i *Image) ReplacePixels(pix []byte) {
	delayedCommandsM.Lock()
	if needsToDelayCommands {
		delayedCommands = append(delayedCommands, func() {
			copied := make([]byte, len(pix))
			copy(copied, pix)
			i.img.ReplacePixels(copied)
		})
		delayedCommandsM.Unlock()
		return
	}
	delayedCommandsM.Unlock()

	i.invalidatePendingPixels()
	i.img.ReplacePixels(pix)
}

func (i *Image) DrawImage(src *Image, bounds image.Rectangle, a, b, c, d, tx, ty float32, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter) {
	if i == src {
		panic("buffered: Image.DrawImage: src must be different from the receiver")
	}

	g := &mipmap.GeoM{
		A:  a,
		B:  b,
		C:  c,
		D:  d,
		Tx: tx,
		Ty: ty,
	}

	delayedCommandsM.Lock()
	if needsToDelayCommands {
		delayedCommands = append(delayedCommands, func() {
			src.resolvePendingPixels(true)
			i.resolvePendingPixels(false)
			i.img.DrawImage(src.img, bounds, g, colorm, mode, filter)
		})
		delayedCommandsM.Unlock()
		return
	}
	delayedCommandsM.Unlock()

	src.resolvePendingPixels(true)
	i.resolvePendingPixels(false)
	i.img.DrawImage(src.img, bounds, g, colorm, mode, filter)
}

func (i *Image) DrawTriangles(src *Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address) {
	if i == src {
		panic("buffered: Image.DrawTriangles: src must be different from the receiver")
	}

	delayedCommandsM.Lock()
	if needsToDelayCommands {
		delayedCommands = append(delayedCommands, func() {
			src.resolvePendingPixels(true)
			i.resolvePendingPixels(false)
			i.img.DrawTriangles(src.img, vertices, indices, colorm, mode, filter, address)
		})
		delayedCommandsM.Unlock()
		return
	}
	delayedCommandsM.Unlock()

	src.resolvePendingPixels(true)
	i.resolvePendingPixels(false)
	i.img.DrawTriangles(src.img, vertices, indices, colorm, mode, filter, address)
}
<|endoftext|>


<commit_before>package gmock

import (
	"reflect"
)

type GMock struct {
	Target   reflect.Value
	Original reflect.Value
}

func MockTarget(targetVar interface{}) *GMock {
	mock := &GMock{}
	mock.Target = reflect.ValueOf(targetVar).Elem()
	mock.Target = reflect.New(mock.Target.Type()).Elem()
	mock.Original.Set(mock.Target)
	return mock
}

func MockTargetWithValue(targetVar interface{}, mockValue interface{}) *GMock {
	mock := MockTarget(targetVar)
	mock.Replace(mockValue)
	return mock
}

func (self *GMock) Replace(mockValue interface{}) {
	replacement := reflect.ValueOf(mockValue)

	if !replacement.IsValid() {
		replacement = reflect.Zero(self.Target.Type())
	}

	self.Target.Set(replacement)
}

func (self *GMock) Restore() {
	self.Target.Set(self.Original)
}
<commit_msg>RS - Made member variables of GMock private and added accessors.<commit_after>package gmock

import (
	"reflect"
)

type GMock struct {
	target   reflect.Value
	original reflect.Value
}

func MockTarget(targetVar interface{}) *GMock {
	mock := &GMock{}
	mock.target = reflect.ValueOf(targetVar).Elem()
	mock.target = reflect.New(mock.target.Type()).Elem()
	mock.original.Set(mock.target)
	return mock
}

func MockTargetWithValue(targetVar interface{}, mockValue interface{}) *GMock {
	mock := MockTarget(targetVar)
	mock.Replace(mockValue)
	return mock
}

func (self *GMock) Replace(mockValue interface{}) {
	replacement := reflect.ValueOf(mockValue)

	if !replacement.IsValid() {
		replacement = reflect.Zero(self.target.Type())
	}

	self.target.Set(replacement)
}

func (self *GMock) Restore() {
	self.target.Set(self.original)
}

func (self *GMock) GetTarget() reflect.Value {
	return self.target
}

func (self *GMock) GetOriginal() reflect.Value {
	return self.original
}
<|endoftext|>


<commit_before>package swarm

import (
	"fmt"
	"io/ioutil"
	"strconv"
	"strings"
	"time"

	types "github.com/docker/docker/api/types"
	context "golang.org/x/net/context"

	"github.com/ovh/cds/sdk"
	"github.com/ovh/cds/sdk/hatchery"
	"github.com/ovh/cds/sdk/log"
)

const (
	bridge  = "bridge"
	docker0 = "docker0"
)

func (h *HatcherySwarm) killAndRemove(dockerClient *dockerClient, ID string) error {
	ctxList, cancelList := context.WithTimeout(context.Background(), 3*time.Second)
	defer cancelList()
	container, err := dockerClient.ContainerInspect(ctxList, ID)
	if err != nil {
		//If there is an error, we try to remove the container
		if strings.Contains(err.Error(), "No such container") {
			log.Debug("hatchery> swarm> killAndRemove> cannot InspectContainer: %v on %s", err, dockerClient.name)
			return nil
		}
		log.Info("hatchery> swarm> killAndRemove> cannot InspectContainer: %v on %s", err, dockerClient.name)
	} else {
		// If its a worker "register", check registration before deleting it
		if strings.Contains(container.Name, "register-") {
			modelID, err := strconv.ParseInt(container.Config.Labels["worker_model"], 10, 64)
			if err != nil {
				log.Error("hatchery> swarm> killAndRemove> unable to get model from registering container %s", container.Name)
			} else {
				if err := hatchery.CheckWorkerModelRegister(h, modelID); err != nil {
					ctx, cancel := context.WithTimeout(context.Background(), time.Minute*2)
					defer cancel()
					logsOpts := types.ContainerLogsOptions{
						Details:    true,
						ShowStderr: true,
						ShowStdout: true,
						Timestamps: true,
						Since:      "10s",
					}
					var spawnErr = sdk.SpawnErrorForm{
						Error: err.Error(),
					}

					logsReader, errL := dockerClient.ContainerLogs(ctx, container.ID, logsOpts)
					if errL != nil {
						log.Error("hatchery> swarm> killAndRemove> cannot get logs from docker for containers service %s %v : %v", container.ID, container.Name, errL)
						spawnErr.Logs = []byte(fmt.Sprintf("unable to get container logs: %v", errL))

					} else if logsReader != nil {
						defer logsReader.Close()
						logs, errR := ioutil.ReadAll(logsReader)
						if errR != nil {
							log.Error("hatchery> swarm> killAndRemove> cannot read logs for containers service %s %v : %v", container.ID, container.Name, errR)
						} else if logs != nil {
							spawnErr.Logs = logs
						}
					}

					if err := h.CDSClient().WorkerModelSpawnError(modelID, spawnErr); err != nil {
						log.Error("hatchery> swarm> killAndRemove> error on call client.WorkerModelSpawnError on worker model %d for register: %s", modelID, err)
					}
				}
			}
		}
	}

	if err := h.killAndRemoveContainer(dockerClient, ID); err != nil {
		return sdk.WrapError(err, "%s on %s", ID[:7], dockerClient.name)
	}

	//If there is no network settings, stop here
	if container.NetworkSettings == nil {
		return nil
	}

	for _, cnetwork := range container.NetworkSettings.Networks {
		//Get the network
		ctxList, cancelList := context.WithTimeout(context.Background(), 3*time.Second)
		defer cancelList()
		network, err := dockerClient.NetworkInspect(ctxList, cnetwork.NetworkID, types.NetworkInspectOptions{})
		if err != nil {
			if !strings.Contains(err.Error(), "No such network") {
				return sdk.WrapError(err, "unable to get network for %s on %s", ID[:7], dockerClient.name)
			}
			continue
		}

		//If it's the default docker bridge... skip
		if network.Driver != bridge || network.Name == docker0 || network.Name == bridge {
			continue
		}

		// If we succeed to get the network, kill and remove all the container on the network
		if netname, ok := network.Labels["worker_net"]; ok {
			log.Debug("hatchery> swarm> killAndRemove> Remove network %s", netname)
			for id := range network.Containers {
				if err := h.killAndRemoveContainer(dockerClient, id); err != nil {
					log.Error("hatchery> swarm> killAndRemove> unable to kill and remove container %s on %s err:%s", id[:12], dockerClient.name, err)
				}
			}
		}

		//Finally remove the network
		log.Info("hatchery> swarm> remove network %s (%s)", network.Name, network.ID)
		ctxDocker, cancelList := context.WithTimeout(context.Background(), 10*time.Second)
		defer cancelList()
		if err := dockerClient.NetworkRemove(ctxDocker, network.ID); err != nil {
			log.Error("hatchery> swarm> killAndRemove> unable to kill and remove network %s from %s err:%s", network.ID[:12], dockerClient.name, err)
		}
	}
	return nil
}

func (h *HatcherySwarm) killAndRemoveContainer(dockerClient *dockerClient, ID string) error {
	log.Debug("hatchery> swarm> killAndRemove> remove container %s on %s", ID, dockerClient.name)
	ctxDocker, cancelList := context.WithTimeout(context.Background(), 20*time.Second)
	defer cancelList()
	if err := dockerClient.ContainerKill(ctxDocker, ID, "SIGKILL"); err != nil {
		if !strings.Contains(err.Error(), "is not running") && !strings.Contains(err.Error(), "No such container") {
			return sdk.WrapError(err, "err on kill container %v from %s", err, dockerClient.name)
		}
	}

	ctxDockerRemove, cancelList := context.WithTimeout(context.Background(), 20*time.Second)
	defer cancelList()
	if err := dockerClient.ContainerRemove(ctxDockerRemove, ID, types.ContainerRemoveOptions{Force: true}); err != nil {
		// container could be already removed by a previous call to docker
		if !strings.Contains(err.Error(), "No such container") {
			return sdk.WrapError(err, "Unable to remove container %s form %s", ID, dockerClient.name)
		}
	}

	return nil
}

func (h *HatcherySwarm) killAwolNetworks() error {
	for _, dockerClient := range h.dockerClients {
		//Checking networks
		ctxDocker, cancelList := context.WithTimeout(context.Background(), 5*time.Second)
		defer cancelList()
		nets, errLN := dockerClient.NetworkList(ctxDocker, types.NetworkListOptions{})
		if errLN != nil {
			log.Warning("hatchery> swarm> killAwolNetworks> Cannot get networks on %s: %s", dockerClient.name, errLN)
			return errLN
		}

		for i := range nets {
			ctxDocker, cancelList := context.WithTimeout(context.Background(), 5*time.Second)
			defer cancelList()
			n, err := dockerClient.NetworkInspect(ctxDocker, nets[i].ID, types.NetworkInspectOptions{})
			if err != nil {
				log.Warning("hatchery> swarm> killAwolNetworks> Unable to get network info: %v", err)
				continue
			}

			if n.Driver != bridge || n.Name == docker0 || n.Name == bridge {
				continue
			}

			if _, ok := n.Labels["worker_net"]; !ok {
				continue
			}

			if len(n.Containers) > 0 {
				continue
			}

			// if network created less than 10 min, keep it alive for now
			if time.Since(n.Created) < 10*time.Minute {
				continue
			}

			log.Info("hatchery> swarm> killAwolNetworks> remove network[%s] %s on %s (created on %v)", n.ID, n.Name, dockerClient.name, n.Created)
			ctxDocker2, cancel := context.WithTimeout(context.Background(), 5*time.Second)
			defer cancel()
			if err := dockerClient.NetworkRemove(ctxDocker2, n.ID); err != nil {
				log.Warning("hatchery> swarm> killAwolNetworks> Unable to delete network %s err:%s", n.Name, err)
			}
		}
	}
	return nil
}
<commit_msg>fix(hatchery/swarm): improve some logs (#4303)<commit_after>package swarm

import (
	"fmt"
	"io/ioutil"
	"strconv"
	"strings"
	"time"

	types "github.com/docker/docker/api/types"
	context "golang.org/x/net/context"

	"github.com/ovh/cds/sdk"
	"github.com/ovh/cds/sdk/hatchery"
	"github.com/ovh/cds/sdk/log"
)

const (
	bridge  = "bridge"
	docker0 = "docker0"
)

func (h *HatcherySwarm) killAndRemove(dockerClient *dockerClient, ID string) error {
	ctxList, cancelList := context.WithTimeout(context.Background(), 3*time.Second)
	defer cancelList()
	container, err := dockerClient.ContainerInspect(ctxList, ID)
	if err != nil {
		//If there is an error, we try to remove the container
		if strings.Contains(err.Error(), "No such container") {
			log.Debug("hatchery> swarm> killAndRemove> cannot InspectContainer: %v on %s", err, dockerClient.name)
			return nil
		}
		log.Info("hatchery> swarm> killAndRemove> cannot InspectContainer: %v on %s", err, dockerClient.name)
	} else {
		// If its a worker "register", check registration before deleting it
		if strings.Contains(container.Name, "register-") {
			modelID, err := strconv.ParseInt(container.Config.Labels["worker_model"], 10, 64)
			if err != nil {
				log.Error("hatchery> swarm> killAndRemove> unable to get model from registering container %s", container.Name)
			} else {
				if err := hatchery.CheckWorkerModelRegister(h, modelID); err != nil {
					ctx, cancel := context.WithTimeout(context.Background(), time.Minute*2)
					defer cancel()
					logsOpts := types.ContainerLogsOptions{
						Details:    true,
						ShowStderr: true,
						ShowStdout: true,
						Timestamps: true,
						Since:      "10s",
					}
					var spawnErr = sdk.SpawnErrorForm{
						Error: err.Error(),
					}

					logsReader, errL := dockerClient.ContainerLogs(ctx, container.ID, logsOpts)
					if errL != nil {
						log.Error("hatchery> swarm> killAndRemove> cannot get logs from docker for containers service %s %v : %v", container.ID, container.Name, errL)
						spawnErr.Logs = []byte(fmt.Sprintf("unable to get container logs: %v", errL))

					} else if logsReader != nil {
						defer logsReader.Close()
						logs, errR := ioutil.ReadAll(logsReader)
						if errR != nil {
							log.Error("hatchery> swarm> killAndRemove> cannot read logs for containers service %s %v : %v", container.ID, container.Name, errR)
						} else if logs != nil {
							spawnErr.Logs = logs
						}
					}

					if err := h.CDSClient().WorkerModelSpawnError(modelID, spawnErr); err != nil {
						log.Error("hatchery> swarm> killAndRemove> error on call client.WorkerModelSpawnError on worker model %d for register: %s", modelID, err)
					}
				}
			}
		}
	}

	if err := h.killAndRemoveContainer(dockerClient, ID); err != nil {
		return sdk.WrapError(err, "%s on %s", ID[:7], dockerClient.name)
	}

	//If there is no network settings, stop here
	if container.NetworkSettings == nil {
		return nil
	}

	for _, cnetwork := range container.NetworkSettings.Networks {
		//Get the network
		ctxList, cancelList := context.WithTimeout(context.Background(), 3*time.Second)
		defer cancelList()
		network, err := dockerClient.NetworkInspect(ctxList, cnetwork.NetworkID, types.NetworkInspectOptions{})
		if err != nil {
			if !strings.Contains(err.Error(), "No such network") {
				return sdk.WrapError(err, "unable to get network for %s on %s", ID[:7], dockerClient.name)
			}
			continue
		}

		//If it's the default docker bridge... skip
		if network.Driver != bridge || network.Name == docker0 || network.Name == bridge {
			continue
		}

		// If we succeed to get the network, kill and remove all the container on the network
		if netname, ok := network.Labels["worker_net"]; ok {
			log.Debug("hatchery> swarm> killAndRemove> Remove network %s", netname)
			for id := range network.Containers {
				if err := h.killAndRemoveContainer(dockerClient, id); err != nil {
					log.Error("hatchery> swarm> killAndRemove> unable to kill and remove container %s on %s err:%s", id[:12], dockerClient.name, err)
				}
			}
		}

		//Finally remove the network
		log.Info("hatchery> swarm> remove network %s (%s)", network.Name, network.ID)
		ctxDocker, cancelList := context.WithTimeout(context.Background(), 10*time.Second)
		defer cancelList()
		if err := dockerClient.NetworkRemove(ctxDocker, network.ID); err != nil {
			log.Error("hatchery> swarm> killAndRemove> unable to kill and remove network %s from %s err:%s", network.ID[:12], dockerClient.name, err)
		}
	}
	return nil
}

func (h *HatcherySwarm) killAndRemoveContainer(dockerClient *dockerClient, ID string) error {
	log.Debug("hatchery> swarm> killAndRemove> remove container %s on %s", ID, dockerClient.name)
	ctxDocker, cancelList := context.WithTimeout(context.Background(), 20*time.Second)
	defer cancelList()
	if err := dockerClient.ContainerKill(ctxDocker, ID, "SIGKILL"); err != nil {
		if !strings.Contains(err.Error(), "is not running") && !strings.Contains(err.Error(), "No such container") {
			return sdk.WrapError(err, "err on kill container %v from %s", err, dockerClient.name)
		}
	}

	ctxDockerRemove, cancelList := context.WithTimeout(context.Background(), 20*time.Second)
	defer cancelList()
	if err := dockerClient.ContainerRemove(ctxDockerRemove, ID, types.ContainerRemoveOptions{Force: true}); err != nil {
		// container could be already removed by a previous call to docker
		if !strings.Contains(err.Error(), "No such container") && !strings.Contains(err.Error(), "is already in progress") {
			return sdk.WrapError(err, "Unable to remove container %s from %s", ID, dockerClient.name)
		}
	}

	return nil
}

func (h *HatcherySwarm) killAwolNetworks() error {
	for _, dockerClient := range h.dockerClients {
		//Checking networks
		ctxDocker, cancelList := context.WithTimeout(context.Background(), 5*time.Second)
		defer cancelList()
		nets, errLN := dockerClient.NetworkList(ctxDocker, types.NetworkListOptions{})
		if errLN != nil {
			log.Warning("hatchery> swarm> killAwolNetworks> Cannot get networks on %s: %s", dockerClient.name, errLN)
			return errLN
		}

		for i := range nets {
			ctxDocker, cancelList := context.WithTimeout(context.Background(), 5*time.Second)
			defer cancelList()
			n, err := dockerClient.NetworkInspect(ctxDocker, nets[i].ID, types.NetworkInspectOptions{})
			if err != nil {
				log.Warning("hatchery> swarm> killAwolNetworks> Unable to get network info: %v", err)
				continue
			}

			if n.Driver != bridge || n.Name == docker0 || n.Name == bridge {
				continue
			}

			if _, ok := n.Labels["worker_net"]; !ok {
				continue
			}

			if len(n.Containers) > 0 {
				continue
			}

			// if network created less than 10 min, keep it alive for now
			if time.Since(n.Created) < 10*time.Minute {
				continue
			}

			log.Info("hatchery> swarm> killAwolNetworks> remove network[%s] %s on %s (created on %v)", n.ID, n.Name, dockerClient.name, n.Created)
			ctxDocker2, cancel := context.WithTimeout(context.Background(), 5*time.Second)
			defer cancel()
			if err := dockerClient.NetworkRemove(ctxDocker2, n.ID); err != nil {
				log.Warning("hatchery> swarm> killAwolNetworks> Unable to delete network %s err:%s", n.Name, err)
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package eventmaster

import (
	"database/sql"
	"fmt"

	_ "github.com/lib/pq"
	"github.com/pkg/errors"
	log "github.com/sirupsen/logrus"
	eventmaster "github.com/wish/eventmaster/proto"
)

// implements datastore
type PostgresStore struct {
	db *sql.DB
}

type PostgresConfig struct {
	Addr        string `json:"addr"`
	Port        int    `json:"port"`
	Database    string `json:"database"`
	ServiceName string `json:"service_name"`
	Username    string `json:"username"`
	Password    string `json:"password"`
}

func NewPostgresStore(c PostgresConfig) (*PostgresStore, error) {
	var host string
	if c.ServiceName != "" {
		host = c.ServiceName + ".service.consul"
	} else {
		host = c.Addr
	}
	log.Infof("Connecting to postgres: %v", host)
	psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
		"password=%s dbname=%s sslmode=disable",
		host, c.Port, c.Username, c.Password, c.Database)
	db, err := sql.Open("postgres", psqlInfo)
	if err != nil {
		return nil, errors.Wrap(err, "Error creating postgres session")
	}
	err = db.Ping()
	if err != nil {
		return nil, errors.Wrap(err, "Error creating postgres session")
	}
	log.Infof("Successfully connected to postgres %s", host)

	return &PostgresStore{
		db: db,
	}, nil
}

func (p *PostgresStore) AddEvent(*Event) error {
	// TODO: implement this function
	return nil
}

func (p *PostgresStore) Find(q *eventmaster.Query, topicIDs []string, dcIDs []string) (Events, error) {
	// TODO: implement this function
	return nil, nil
}

func (p *PostgresStore) FindByID(string, bool) (*Event, error) {
	// TODO: implement this function
	return nil, nil
}

func (p *PostgresStore) FindIDs(*eventmaster.TimeQuery, HandleEvent) error {
	// TODO: implement this function
	return nil
}

func (p *PostgresStore) GetTopics() ([]Topic, error) {
	// TODO: implement this function
	return nil, nil
}

func (p *PostgresStore) AddTopic(RawTopic) error {
	// TODO: implement this function
	return nil
}

func (p *PostgresStore) UpdateTopic(RawTopic) error {
	// TODO: implement this function
	return nil
}

func (p *PostgresStore) DeleteTopic(string) error {
	// TODO: implement this function
	return nil
}

func (p *PostgresStore) GetDCs() ([]DC, error) {
	// TODO: implement this function
	return nil, nil
}

func (p *PostgresStore) AddDC(DC) error {
	// TODO: implement this function
	return nil
}

func (p *PostgresStore) UpdateDC(string, string) error {
	// TODO: implement this function
	return nil
}

func (p *PostgresStore) CloseSession() {
	// TODO: implement this function
	return
}
<commit_msg>Implement AddDC<commit_after>package eventmaster

import (
	"database/sql"
	"fmt"

	_ "github.com/lib/pq"
	"github.com/pkg/errors"
	log "github.com/sirupsen/logrus"
	eventmaster "github.com/wish/eventmaster/proto"
)

// implements datastore
type PostgresStore struct {
	db *sql.DB
}

type PostgresConfig struct {
	Addr        string `json:"addr"`
	Port        int    `json:"port"`
	Database    string `json:"database"`
	ServiceName string `json:"service_name"`
	Username    string `json:"username"`
	Password    string `json:"password"`
}

func NewPostgresStore(c PostgresConfig) (*PostgresStore, error) {
	var host string
	if c.ServiceName != "" {
		host = c.ServiceName + ".service.consul"
	} else {
		host = c.Addr
	}
	log.Infof("Connecting to postgres: %v", host)
	psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
		"password=%s dbname=%s sslmode=disable",
		host, c.Port, c.Username, c.Password, c.Database)
	db, err := sql.Open("postgres", psqlInfo)
	if err != nil {
		return nil, errors.Wrap(err, "Error creating postgres session")
	}
	err = db.Ping()
	if err != nil {
		return nil, errors.Wrap(err, "Error creating postgres session")
	}
	log.Infof("Successfully connected to postgres %s", host)

	return &PostgresStore{
		db: db,
	}, nil
}

func (p *PostgresStore) AddEvent(*Event) error {
	// TODO: implement this function
	return nil
}

func (p *PostgresStore) Find(q *eventmaster.Query, topicIDs []string, dcIDs []string) (Events, error) {
	// TODO: implement this function
	return nil, nil
}

func (p *PostgresStore) FindByID(string, bool) (*Event, error) {
	// TODO: implement this function
	return nil, nil
}

func (p *PostgresStore) FindIDs(*eventmaster.TimeQuery, HandleEvent) error {
	// TODO: implement this function
	return nil
}

func (p *PostgresStore) GetTopics() ([]Topic, error) {
	// TODO: implement this function
	return nil, nil
}

func (p *PostgresStore) AddTopic(RawTopic) error {
	// TODO: implement this function
	return nil
}

func (p *PostgresStore) UpdateTopic(RawTopic) error {
	// TODO: implement this function
	return nil
}

func (p *PostgresStore) DeleteTopic(string) error {
	// TODO: implement this function
	return nil
}

func (p *PostgresStore) GetDCs() ([]DC, error) {
	// TODO: implement this function
	return nil, nil
}

func (p *PostgresStore) AddDC(dc DC) error {
	stmt, err := p.db.Prepare("INSERT INTO event_dc (dc_id, dc) VALUES ($1, $2)")
	if err != nil {
		return errors.Wrap(err, "Failed preparing insert DC statement")
	}
	_, err = stmt.Exec(dc.ID, dc.Name)
	if err != nil {
		return errors.Wrap(err, "Failed executing insert DC statement")
	}

	return nil
}

func (p *PostgresStore) UpdateDC(string, string) error {
	// TODO: implement this function
	return nil
}

func (p *PostgresStore) CloseSession() {
	// TODO: implement this function
	return
}
<|endoftext|>


<commit_before>package models

import (
	"fmt"
	"math/rand"
	"sort"

	"github.com/mrap/stringutil"
	wordpatterns "github.com/mrap/wordpatterns"
)

const (
	MinCombosCount = 0
	MinMaxComboLen = 2
	MinMinComboLen = 2
)

// TODO: Might provide other languages/wordlists in the future.
//       We would need to store lookups/wordmaps in a db
var (
	_sharedLookup  = make(wordpatterns.Wordmap)
	_sharedWordmap = make(wordpatterns.Wordmap)
)

func init() {
	StoreWords("wordlists/google-10000-english.txt")
}

func GenerateCombos(chars string, count, minLen, maxLen int) []string {
	// Validate and normalize params
	if len(chars) == 0 {
		return []string{}
	}

	if count < MinCombosCount {
		count = MinCombosCount
	}

	if minLen < MinMinComboLen {
		minLen = MinMinComboLen
	}

	if maxLen < MinMaxComboLen {
		maxLen = MinMaxComboLen
	}

	if maxLen < minLen {
		maxLen = minLen
	}

	combos := RankedCombos(_sharedLookup, chars, minLen, maxLen)
	return generateComboList(_sharedWordmap, combos, count)
}

// StoreWords stores words from a word list file into
func StoreWords(filename string) {
	wm := wordpatterns.CreateWordmap(filename)
	_sharedWordmap = wm
	_sharedLookup = CreateCharWordLookup(_sharedWordmap)
}

// CreateCharWordLookup creates a lookup structure that makes it efficient
// to query for sub-words that only contain specific characters
func CreateCharWordLookup(wm wordpatterns.Wordmap) wordpatterns.Wordmap {
	var (
		lookup = make(wordpatterns.Wordmap)
		sorted string
	)

	for subword, _ := range wm {
		sorted = stringutil.SortString(subword)
		lookup[sorted] = append(lookup[sorted], subword)
	}
	return lookup
}

func CombosWithChars(lookup wordpatterns.Wordmap, chars string, minLen int, maxLen int) []string {
	if maxLen < 0 {
		maxLen = 0
	}
	if minLen < 0 {
		minLen = 0
	}

	var combos []string
	sortedChars := stringutil.SortString(chars)

	for _, subsorted := range stringutil.Substrs(sortedChars, 2) {
		if (minLen != 0 && len(subsorted) < minLen) || (maxLen != 0 && len(subsorted) > maxLen) {
			continue
		} else {
			combos = append(combos, lookup[subsorted]...)
		}
	}
	return combos
}

func RankedCombos(lookup wordpatterns.Wordmap, chars string, minLen, maxLen int) []string {
	combos := CombosWithChars(lookup, chars, minLen, maxLen)
	sort.Sort(ByWordCount(combos))
	return combos
}

// generateComboList returns a slice of combos that are distributed based on rank
// More occurring combos will appear more frequently
func generateComboList(wm wordpatterns.Wordmap, combos []string, count int) []string {
	total := 0
	for _, c := range combos {
		total += len(wm[c])
	}

	list := make([]string, count)
	var r, cur int
	for i := 0; i < count; i++ {
		cur = 0
		r = rand.Intn(total) + 1
		for _, c := range combos {
			cur += len(wm[c])
			if r <= cur {
				list[i] = c
				break
			}
		}
	}
	return list
}

type ByWordCount []string

func (a ByWordCount) Len() int      { return len(a) }
func (a ByWordCount) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByWordCount) Less(i, j int) bool {
	return _sharedWordmap.Compare(a[i], a[j]) >= 0
}

func printComboListCounts(combos []string) {
	counts := make(map[string]int)
	for _, c := range combos {
		counts[c]++
	}
	for key, count := range counts {
		fmt.Printf("%s -> %d\n", key, count)
	}
	fmt.Println()
}
<commit_msg>Simplifies combo ranking<commit_after>package models

import (
	"fmt"
	"math/rand"
	"sort"

	"golang.org/x/tools/container/intsets"

	"github.com/mrap/stringutil"
	"github.com/mrap/wordpatterns"
)

const (
	MinCombosCount = 0
	MinMaxComboLen = 2
	MinMinComboLen = 2
)

// TODO: Might provide other languages/wordlists in the future.
//       We would need to store lookups/wordmaps in a db
var (
	_sharedLookup = make(wordpatterns.Wordmap)
)

func init() {
	StoreWords("wordlists/google-10000-english.txt")
}

type Combo struct {
	S     string
	Count int
}

func GenerateCombos(chars string, count, minLen, maxLen int) []string {
	// Validate and normalize params
	if len(chars) == 0 {
		return []string{}
	}

	if count < MinCombosCount {
		count = MinCombosCount
	}

	if minLen < MinMinComboLen {
		minLen = MinMinComboLen
	}

	if maxLen < MinMaxComboLen {
		maxLen = MinMaxComboLen
	}

	if maxLen < minLen {
		maxLen = minLen
	}

	combos := SortedCombos(_sharedLookup, chars, minLen, maxLen)
	return generateComboList(combos, count)
}

// StoreWords stores words from a word list file into
func StoreWords(filename string) {
	wm := wordpatterns.CreateWordmap(filename)
	_sharedLookup = CreateCharWordLookup(wm)
}

// CreateCharWordLookup creates a lookup structure that makes it efficient
// to query for sub-words that only contain specific characters
func CreateCharWordLookup(wm wordpatterns.Wordmap) wordpatterns.Wordmap {
	var (
		lookup = make(wordpatterns.Wordmap)
		sorted string
	)

	for subword, _ := range wm {
		sorted = stringutil.SortString(subword)
		lookup[sorted] = append(lookup[sorted], subword)
	}
	return lookup
}

func CombosWithChars(lookup wordpatterns.Wordmap, chars string, minLen int, maxLen int) []Combo {
	if maxLen < 0 {
		maxLen = intsets.MaxInt
	}
	if minLen < 0 {
		minLen = 0
	}

	var combos []Combo
	for _, sub := range sortedSubstrs(chars, minLen) {
		if (len(sub) >= minLen) && (len(sub) <= maxLen) {
			combos = append(combos, Combo{sub, len(lookup[sub])})
		}
	}
	return combos
}

func sortedSubstrs(chars string, minLen int) []string {
	sortedChars := stringutil.SortString(chars)
	return stringutil.Substrs(sortedChars, minLen)
}

// SortedCombos returns combos ranked by most occuring in the wordmap to least.
// i.e. a combo is more occurant if it is a substring of more words in the wordmap.
func SortedCombos(lookup wordpatterns.Wordmap, chars string, minLen, maxLen int) []Combo {
	combos := CombosWithChars(lookup, chars, minLen, maxLen)
	sort.Sort(ByCount(combos))
	return combos
}

// generateComboList returns a slice of combos that are distributed based on rank
// More occurring combos will appear more frequently
func generateComboList(combos []Combo, count int) []string {
	matchCount := sumCount(combos)
	list := make([]string, count)
	for i := 0; i < count; i++ {
		list[i] = probableCombo(combos, matchCount).S
	}
	return list
}

func sumCount(combos []Combo) int {
	total := 0
	for _, c := range combos {
		total += c.Count
	}
	return total
}

// probableCombo returns probable combo based on occurances.
// i.e. the higher the combo count, the more likely to chose it.
func probableCombo(sortedCombos []Combo, totalMatches int) Combo {
	i := 0
	for rem := rand.Intn(totalMatches) + 1; rem > 0; i++ {
		rem -= sortedCombos[i].Count
	}
	return sortedCombos[i]
}

type ByCount []Combo

func (a ByCount) Len() int      { return len(a) }
func (a ByCount) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByCount) Less(i, j int) bool {
	return a[i].Count < a[j].Count
}

func printComboListCounts(combos []string) {
	counts := make(map[string]int)
	for _, c := range combos {
		counts[c]++
	}
	for key, count := range counts {
		fmt.Printf("%s -> %d\n", key, count)
	}
	fmt.Println()
}
<|endoftext|>


<commit_before>package fipple

import (
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"strings"
	"testing"
)

type Recorder struct {
	t       *testing.T
	client  *http.Client
	baseURL string
}

func NewRecorder(t *testing.T, baseURL string) *Recorder {
	jar, err := cookiejar.New(nil)
	if err != nil {
		t.Fatal(err)
	}
	return &Recorder{
		t:       t,
		client:  &http.Client{Jar: jar},
		baseURL: baseURL,
	}
}

func (r *Recorder) newResponse(resp *http.Response) *Response {
	return &Response{
		Response: resp,
		recorder: r,
	}
}

func (r *Recorder) NewRequest(method string, path string) *http.Request {
	fullURL := r.baseURL + path
	req, err := http.NewRequest(method, fullURL, nil)
	if err != nil {
		r.t.Fatal(err)
	}
	return req
}

func (r *Recorder) NewRequestWithData(method string, path string, data map[string]string) *http.Request {
	fullURL := r.baseURL + path
	v := url.Values{}
	for key, value := range data {
		v.Add(key, value)
	}
	req, err := http.NewRequest(method, fullURL, strings.NewReader(v.Encode()))
	if err != nil {
		r.t.Fatal(err)
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	return req
}

// Get sends req and records the results into a fipple.Response.
// Note that because an http.Request should have already been created
// with a full, valid url, the baseURL of the Recorder will not be prepended
// to the url for req. You can run methods on the response to check
// the results.
func (r *Recorder) Do(req *http.Request) *Response {
	httpResp, err := r.client.Do(req)
	if err != nil {
		r.t.Fatal(err)
	}
	resp := r.newResponse(httpResp)
	resp.ReadBody()
	return resp
}

// Get sends a GET request to the given path and records the results into
// a fipple.Response. You can run methods on the response
// to check the results.
func (r *Recorder) Get(path string) *Response {
	req := r.newRequest("GET", path)
	return r.Do(req)
}

// Post sends a POST request to the given path using the given data as post
// parameters and records the results into a fipple.Response. You
// can run methods on the response to check the results.
func (r *Recorder) Post(path string, data map[string]string) *Response {
	req := r.newRequestWithData("POST", path, data)
	return r.Do(req)
}

// Put sends a PUT request to the given path using the given data as
// parameters and records the results into a fipple.Response. You
// can run methods on the response to check the results.
func (r *Recorder) Put(path string, data map[string]string) *Response {
	req := r.newRequestWithData("PUT", path, data)
	return r.Do(req)
}

// Delete sends a DELETE request to the given path and records the results
// into a fipple.Response. You can run methods on the response to check the
// results.
func (r *Recorder) Delete(path string) *Response {
	req := r.newRequest("DELETE", path)
	return r.Do(req)
}

func (r *Recorder) GetCookies() []*http.Cookie {
	fullURL, err := url.Parse(r.baseURL)
	if err != nil {
		r.t.Fatal(err)
	}
	return r.client.Jar.Cookies(fullURL)
}
<commit_msg>Fix syntax errors<commit_after>package fipple

import (
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"strings"
	"testing"
)

type Recorder struct {
	t       *testing.T
	client  *http.Client
	baseURL string
}

func NewRecorder(t *testing.T, baseURL string) *Recorder {
	jar, err := cookiejar.New(nil)
	if err != nil {
		t.Fatal(err)
	}
	return &Recorder{
		t:       t,
		client:  &http.Client{Jar: jar},
		baseURL: baseURL,
	}
}

func (r *Recorder) newResponse(resp *http.Response) *Response {
	return &Response{
		Response: resp,
		recorder: r,
	}
}

func (r *Recorder) NewRequest(method string, path string) *http.Request {
	fullURL := r.baseURL + path
	req, err := http.NewRequest(method, fullURL, nil)
	if err != nil {
		r.t.Fatal(err)
	}
	return req
}

func (r *Recorder) NewRequestWithData(method string, path string, data map[string]string) *http.Request {
	fullURL := r.baseURL + path
	v := url.Values{}
	for key, value := range data {
		v.Add(key, value)
	}
	req, err := http.NewRequest(method, fullURL, strings.NewReader(v.Encode()))
	if err != nil {
		r.t.Fatal(err)
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	return req
}

// Get sends req and records the results into a fipple.Response.
// Note that because an http.Request should have already been created
// with a full, valid url, the baseURL of the Recorder will not be prepended
// to the url for req. You can run methods on the response to check
// the results.
func (r *Recorder) Do(req *http.Request) *Response {
	httpResp, err := r.client.Do(req)
	if err != nil {
		r.t.Fatal(err)
	}
	resp := r.newResponse(httpResp)
	resp.ReadBody()
	return resp
}

// Get sends a GET request to the given path and records the results into
// a fipple.Response. You can run methods on the response
// to check the results.
func (r *Recorder) Get(path string) *Response {
	req := r.NewRequest("GET", path)
	return r.Do(req)
}

// Post sends a POST request to the given path using the given data as post
// parameters and records the results into a fipple.Response. You
// can run methods on the response to check the results.
func (r *Recorder) Post(path string, data map[string]string) *Response {
	req := r.NewRequestWithData("POST", path, data)
	return r.Do(req)
}

// Put sends a PUT request to the given path using the given data as
// parameters and records the results into a fipple.Response. You
// can run methods on the response to check the results.
func (r *Recorder) Put(path string, data map[string]string) *Response {
	req := r.NewRequestWithData("PUT", path, data)
	return r.Do(req)
}

// Delete sends a DELETE request to the given path and records the results
// into a fipple.Response. You can run methods on the response to check the
// results.
func (r *Recorder) Delete(path string) *Response {
	req := r.NewRequest("DELETE", path)
	return r.Do(req)
}

func (r *Recorder) GetCookies() []*http.Cookie {
	fullURL, err := url.Parse(r.baseURL)
	if err != nil {
		r.t.Fatal(err)
	}
	return r.client.Jar.Cookies(fullURL)
}
<|endoftext|>


<commit_before>// Copyright 2016, RadiantBlue Technologies, Inc.
//
// 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 pzse

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"os/exec"
	"strconv"
	"time"

	"github.com/venicegeo/pzsvc-exec/pzsvc"
)

// ParseConfig parses the config file on starting up
func ParseConfig(configObj *ConfigType) ConfigParseOut {

	canReg := CheckConfig(configObj)
	canPzFile := configObj.CanUpload || configObj.CanDownlPz

	var authKey string
	if configObj.AuthEnVar != "" && (canReg || canPzFile) {
		authKey = os.Getenv(configObj.AuthEnVar)
		if authKey == "" {
			errStr := "Error: no auth key at AuthEnVar."
			if canReg {
				errStr += "  Registration disabled."
			}
			if canPzFile {
				errStr += "  Client will have to provide authKey for Pz file interactions."
			}
			fmt.Println(errStr)
			canReg = false
		}
	}

	if configObj.Port <= 0 {
		configObj.Port = 8080
	}
	portStr := ":" + strconv.Itoa(configObj.Port)

	version := GetVersion(configObj)

	if canReg {
		fmt.Println("About to manage registration.")
		err := pzsvc.ManageRegistration(configObj.SvcName,
			configObj.Description,
			configObj.URL+"/execute",
			configObj.PzAddr,
			version,
			authKey,
			configObj.Attributes)
		if err != nil {
			fmt.Println("pzsvc-exec error in managing registration: ", err.Error())
		}
		fmt.Println("Registration managed.")
	}

	var procPool = pzsvc.Semaphore(nil)
	if configObj.NumProcs > 0 {
		procPool = make(pzsvc.Semaphore, configObj.NumProcs)
	}

	return ConfigParseOut{authKey, portStr, version, procPool}
}

// Execute does the primary work for pzsvc-exec.  Given a request and various
// blocks of config data, it creates a temporary folder to work in, downloads
// any files indicated in the request (if the configs support it), executes
// the command indicated by the combination of request and configs, uploads
// any files indicated by the request (if the configs support it) and cleans
// up after itself
func Execute(w http.ResponseWriter, r *http.Request, configObj ConfigType, pzConfigAuth, version string, procPool pzsvc.Semaphore) OutStruct {

	// Makes sure that you only have a certain number of execution tasks firing at once.
	// pzsvc-exec calls can get pretty resource-intensive, and this keeps them from
	// trampling each other into messy deadlock
	procPool.Lock()
	defer procPool.Unlock()

	var (
		output OutStruct
		inpObj InpStruct
		byts   []byte
		err    error
	)
	output.InFiles = make(map[string]string)
	output.OutFiles = make(map[string]string)
	output.HTTPStatus = http.StatusOK

	if r.Method != "POST" {
		addOutputError(&output, r.Method+" not supported.  Please us POST.", http.StatusMethodNotAllowed)
		return output
	}

	if byts, err = pzsvc.ReadBodyJSON(&inpObj, r.Body); err != nil {
		fmt.Printf("pzsvc-exec: could not interpret input Body as json.  Attempting to interpret as Form.  Original Body: " + string(byts))
		inpObj.Command = r.FormValue("cmd")
		inpObj.InPzFiles = splitOrNil(r.FormValue("inFiles"), ",")
		inpObj.InExtFiles = splitOrNil(r.FormValue("inFileURLs"), ",")
		inpObj.InPzNames = splitOrNil(r.FormValue("inPzFileNames"), ",")
		inpObj.InExtNames = splitOrNil(r.FormValue("inExtFileNames"), ",")
		inpObj.OutTiffs = splitOrNil(r.FormValue("outTiffs"), ",")
		inpObj.OutTxts = splitOrNil(r.FormValue("outTxts"), ",")
		inpObj.OutGeoJs = splitOrNil(r.FormValue("outGeoJson"), ",")
		inpObj.ExtAuth = r.FormValue("inUrlAuthKey")
		inpObj.PzAuth = r.FormValue("authKey")
		inpObj.PzAddr = r.FormValue("pzAddr")
		byts, _ = json.Marshal(inpObj)
	}
	fmt.Println(`pzsvc-exec called.  Input: ` + string(byts))

	cmdParamSlice := splitOrNil(inpObj.Command, " ")
	cmdConfigSlice := splitOrNil(configObj.CliCmd, " ")
	cmdSlice := append(cmdConfigSlice, cmdParamSlice...)

	if inpObj.PzAuth == "" {
		inpObj.PzAuth = pzConfigAuth
	}
	if inpObj.PzAddr == "" {
		inpObj.PzAddr = configObj.PzAddr
	}

	if inpObj.PzAddr == "" && (len(inpObj.InPzFiles)+len(inpObj.OutTiffs)+len(inpObj.OutTxts)+len(inpObj.OutGeoJs) != 0) {
		addOutputError(&output, "Cannot complete.  No Piazza address provided for file upload/download.", http.StatusForbidden)
		return output
	}

	if inpObj.PzAuth == "" && (len(inpObj.InPzFiles)+len(inpObj.OutTiffs)+len(inpObj.OutTxts)+len(inpObj.OutGeoJs) != 0) {
		addOutputError(&output, "Cannot complete.  Auth Key not available.", http.StatusForbidden)
		return output
	}

	if !configObj.CanDownlExt && (len(inpObj.InExtFiles) != 0) {
		addOutputError(&output, "Cannot complete.  Configuration does not allow external file download.", http.StatusForbidden)
		return output
	}
	if !configObj.CanDownlPz && (len(inpObj.InPzFiles) != 0) {
		addOutputError(&output, "Cannot complete.  Configuration does not allow Piazza file download.", http.StatusForbidden)
		return output
	}
	if !configObj.CanUpload && (len(inpObj.OutTiffs)+len(inpObj.OutTxts)+len(inpObj.OutGeoJs) != 0) {
		addOutputError(&output, "Cannot complete.  Configuration does not allow file upload.", http.StatusForbidden)
		return output
	}

	runID, err := pzsvc.PsuUUID()
	if err != nil {
		pzsvc.LogSimpleErr("psuUUID error: ", err)
		addOutputError(&output, "pzsvc-exec internal error.  Check logs for further information.", http.StatusInternalServerError)
	}
	err = os.Mkdir("./"+runID, 0777)
	if err != nil {
		pzsvc.LogSimpleErr("os.Mkdir error: ", err)
		addOutputError(&output, "pzsvc-exec internal error.  Check logs for further information.", http.StatusInternalServerError)
	}
	defer os.RemoveAll("./" + runID)

	err = os.Chmod("./"+runID, 0777)
	if err != nil {
		pzsvc.LogSimpleErr("os.Chmod error: ", err)
		addOutputError(&output, "pzsvc-exec internal error.  Check logs for further information.", http.StatusInternalServerError)
	}

	// this is done to enable use of handleFList, which lets us
	// reduce a fair bit of code duplication in plowing through
	// our upload/download lists.  handleFList gets used a fair
	// bit more after the execute call.
	pzDownlFunc := func(dataID, fname, fType string) (string, error) {
		return pzsvc.DownloadByID(dataID, fname, runID, inpObj.PzAddr, inpObj.PzAuth)
	}
	handleFList(inpObj.InPzFiles, inpObj.InPzNames, pzDownlFunc, "", &output, output.InFiles, w)

	extDownlFunc := func(url, fname, fType string) (string, error) {
		return pzsvc.DownloadByURL(url, fname, runID, inpObj.ExtAuth)
	}
	handleFList(inpObj.InExtFiles, inpObj.InExtNames, extDownlFunc, "", &output, output.InFiles, w)

	if len(cmdSlice) == 0 {
		addOutputError(&output, `No cmd or CliCmd.  Please provide "cmd" param.`, http.StatusBadRequest)
		return output
	}

	fmt.Println(`Executing "` + configObj.CliCmd + ` ` + inpObj.Command + `".`)

	// we're calling this from inside a temporary subfolder.  If the
	// program called exists inside the initial pzsvc-exec folder, that's
	// probably where it's called from, and we need to acccess it directly.
	_, err = os.Stat(fmt.Sprintf("./%s", cmdSlice[0]))
	if err == nil || !(os.IsNotExist(err)) {
		// ie, if there's a file in the start folder named the same thing
		// as the base command
		cmdSlice[0] = ("../" + cmdSlice[0])
	}

	clc := exec.Command(cmdSlice[0], cmdSlice[1:]...)
	clc.Dir = runID

	var stdout bytes.Buffer
	var stderr bytes.Buffer
	clc.Stdout = &stdout
	clc.Stderr = &stderr

	err = clc.Run()

	if err != nil {
		pzsvc.LogSimpleErr("clc.Run error: ", err)
		addOutputError(&output, `pzsvc-exec failed on cmd "`+inpObj.Command+`".  If that was correct, check logs for further details.`, http.StatusBadRequest)
	}

	fmt.Println(`Program stdout: ` + stdout.String())
	fmt.Println(`Program stderr: ` + stderr.String())

	attMap := make(map[string]string)
	attMap["algoName"] = configObj.SvcName
	attMap["algoVersion"] = version
	attMap["algoCmd"] = configObj.CliCmd + " " + inpObj.Command
	attMap["algoProcTime"] = time.Now().UTC().Format("20060102.150405.99999")

	// this is the other spot that handleFlist gets used, and works on the
	// same principles.

	ingFunc := func(fName, dummy, fType string) (string, error) {
		return pzsvc.IngestFile(fName, runID, fType, inpObj.PzAddr, configObj.SvcName, version, inpObj.PzAuth, attMap)
	}

	handleFList(inpObj.OutTiffs, nil, ingFunc, "raster", &output, output.OutFiles, w)
	handleFList(inpObj.OutTxts, nil, ingFunc, "text", &output, output.OutFiles, w)
	handleFList(inpObj.OutGeoJs, nil, ingFunc, "geojson", &output, output.OutFiles, w)

	return output
}
<commit_msg>Improving a logging issue<commit_after>// Copyright 2016, RadiantBlue Technologies, Inc.
//
// 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 pzse

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"os/exec"
	"strconv"
	"time"

	"github.com/venicegeo/pzsvc-exec/pzsvc"
)

// ParseConfig parses the config file on starting up
func ParseConfig(configObj *ConfigType) ConfigParseOut {

	canReg := CheckConfig(configObj)
	canPzFile := configObj.CanUpload || configObj.CanDownlPz

	var authKey string
	if configObj.AuthEnVar != "" && (canReg || canPzFile) {
		authKey = os.Getenv(configObj.AuthEnVar)
		if authKey == "" {
			errStr := "Error: no auth key at AuthEnVar."
			if canReg {
				errStr += "  Registration disabled."
			}
			if canPzFile {
				errStr += "  Client will have to provide authKey for Pz file interactions."
			}
			fmt.Println(errStr)
			canReg = false
		}
	}

	if configObj.Port <= 0 {
		configObj.Port = 8080
	}
	portStr := ":" + strconv.Itoa(configObj.Port)

	version := GetVersion(configObj)

	if canReg {
		fmt.Println("About to manage registration.")
		err := pzsvc.ManageRegistration(configObj.SvcName,
			configObj.Description,
			configObj.URL+"/execute",
			configObj.PzAddr,
			version,
			authKey,
			configObj.Attributes)
		if err != nil {
			fmt.Println("pzsvc-exec error in managing registration: ", err.Error())
		}
		fmt.Println("Registration managed.")
	}

	var procPool = pzsvc.Semaphore(nil)
	if configObj.NumProcs > 0 {
		procPool = make(pzsvc.Semaphore, configObj.NumProcs)
	}

	return ConfigParseOut{authKey, portStr, version, procPool}
}

// Execute does the primary work for pzsvc-exec.  Given a request and various
// blocks of config data, it creates a temporary folder to work in, downloads
// any files indicated in the request (if the configs support it), executes
// the command indicated by the combination of request and configs, uploads
// any files indicated by the request (if the configs support it) and cleans
// up after itself
func Execute(w http.ResponseWriter, r *http.Request, configObj ConfigType, pzConfigAuth, version string, procPool pzsvc.Semaphore) OutStruct {

	// Makes sure that you only have a certain number of execution tasks firing at once.
	// pzsvc-exec calls can get pretty resource-intensive, and this keeps them from
	// trampling each other into messy deadlock
	procPool.Lock()
	defer procPool.Unlock()

	var (
		output OutStruct
		inpObj InpStruct
		byts   []byte
		err    error
		pErr   *pzsvc.Error
	)
	output.InFiles = make(map[string]string)
	output.OutFiles = make(map[string]string)
	output.HTTPStatus = http.StatusOK

	if r.Method != "POST" {
		addOutputError(&output, r.Method+" not supported.  Please us POST.", http.StatusMethodNotAllowed)
		return output
	}

	if byts, pErr = pzsvc.ReadBodyJSON(&inpObj, r.Body); err != nil {
		pErr.Log("Could not read request body.  Attempting to fall back to form fields.  Initial error:")
		inpObj.Command = r.FormValue("cmd")
		inpObj.InPzFiles = splitOrNil(r.FormValue("inFiles"), ",")
		inpObj.InExtFiles = splitOrNil(r.FormValue("inFileURLs"), ",")
		inpObj.InPzNames = splitOrNil(r.FormValue("inPzFileNames"), ",")
		inpObj.InExtNames = splitOrNil(r.FormValue("inExtFileNames"), ",")
		inpObj.OutTiffs = splitOrNil(r.FormValue("outTiffs"), ",")
		inpObj.OutTxts = splitOrNil(r.FormValue("outTxts"), ",")
		inpObj.OutGeoJs = splitOrNil(r.FormValue("outGeoJson"), ",")
		inpObj.ExtAuth = r.FormValue("inUrlAuthKey")
		inpObj.PzAuth = r.FormValue("authKey")
		inpObj.PzAddr = r.FormValue("pzAddr")
		byts, _ = json.Marshal(inpObj)
	}
	fmt.Println(`pzsvc-exec called.  Input: ` + string(byts))

	cmdParamSlice := splitOrNil(inpObj.Command, " ")
	cmdConfigSlice := splitOrNil(configObj.CliCmd, " ")
	cmdSlice := append(cmdConfigSlice, cmdParamSlice...)

	if inpObj.PzAuth == "" {
		inpObj.PzAuth = pzConfigAuth
	}
	if inpObj.PzAddr == "" {
		inpObj.PzAddr = configObj.PzAddr
	}

	if inpObj.PzAddr == "" && (len(inpObj.InPzFiles)+len(inpObj.OutTiffs)+len(inpObj.OutTxts)+len(inpObj.OutGeoJs) != 0) {
		addOutputError(&output, "Cannot complete.  No Piazza address provided for file upload/download.", http.StatusForbidden)
		return output
	}

	if inpObj.PzAuth == "" && (len(inpObj.InPzFiles)+len(inpObj.OutTiffs)+len(inpObj.OutTxts)+len(inpObj.OutGeoJs) != 0) {
		addOutputError(&output, "Cannot complete.  Auth Key not available.", http.StatusForbidden)
		return output
	}

	if !configObj.CanDownlExt && (len(inpObj.InExtFiles) != 0) {
		addOutputError(&output, "Cannot complete.  Configuration does not allow external file download.", http.StatusForbidden)
		return output
	}
	if !configObj.CanDownlPz && (len(inpObj.InPzFiles) != 0) {
		addOutputError(&output, "Cannot complete.  Configuration does not allow Piazza file download.", http.StatusForbidden)
		return output
	}
	if !configObj.CanUpload && (len(inpObj.OutTiffs)+len(inpObj.OutTxts)+len(inpObj.OutGeoJs) != 0) {
		addOutputError(&output, "Cannot complete.  Configuration does not allow file upload.", http.StatusForbidden)
		return output
	}

	runID, err := pzsvc.PsuUUID()
	if err != nil {
		pzsvc.LogSimpleErr("psuUUID error: ", err)
		addOutputError(&output, "pzsvc-exec internal error.  Check logs for further information.", http.StatusInternalServerError)
	}
	err = os.Mkdir("./"+runID, 0777)
	if err != nil {
		pzsvc.LogSimpleErr("os.Mkdir error: ", err)
		addOutputError(&output, "pzsvc-exec internal error.  Check logs for further information.", http.StatusInternalServerError)
	}
	defer os.RemoveAll("./" + runID)

	err = os.Chmod("./"+runID, 0777)
	if err != nil {
		pzsvc.LogSimpleErr("os.Chmod error: ", err)
		addOutputError(&output, "pzsvc-exec internal error.  Check logs for further information.", http.StatusInternalServerError)
	}

	// this is done to enable use of handleFList, which lets us
	// reduce a fair bit of code duplication in plowing through
	// our upload/download lists.  handleFList gets used a fair
	// bit more after the execute call.
	pzDownlFunc := func(dataID, fname, fType string) (string, error) {
		return pzsvc.DownloadByID(dataID, fname, runID, inpObj.PzAddr, inpObj.PzAuth)
	}
	handleFList(inpObj.InPzFiles, inpObj.InPzNames, pzDownlFunc, "", &output, output.InFiles, w)

	extDownlFunc := func(url, fname, fType string) (string, error) {
		return pzsvc.DownloadByURL(url, fname, runID, inpObj.ExtAuth)
	}
	handleFList(inpObj.InExtFiles, inpObj.InExtNames, extDownlFunc, "", &output, output.InFiles, w)

	if len(cmdSlice) == 0 {
		addOutputError(&output, `No cmd or CliCmd.  Please provide "cmd" param.`, http.StatusBadRequest)
		return output
	}

	fmt.Println(`Executing "` + configObj.CliCmd + ` ` + inpObj.Command + `".`)

	// we're calling this from inside a temporary subfolder.  If the
	// program called exists inside the initial pzsvc-exec folder, that's
	// probably where it's called from, and we need to acccess it directly.
	_, err = os.Stat(fmt.Sprintf("./%s", cmdSlice[0]))
	if err == nil || !(os.IsNotExist(err)) {
		// ie, if there's a file in the start folder named the same thing
		// as the base command
		cmdSlice[0] = ("../" + cmdSlice[0])
	}

	clc := exec.Command(cmdSlice[0], cmdSlice[1:]...)
	clc.Dir = runID

	var stdout bytes.Buffer
	var stderr bytes.Buffer
	clc.Stdout = &stdout
	clc.Stderr = &stderr

	err = clc.Run()

	if err != nil {
		pzsvc.LogSimpleErr("clc.Run error: ", err)
		addOutputError(&output, `pzsvc-exec failed on cmd "`+inpObj.Command+`".  If that was correct, check logs for further details.`, http.StatusBadRequest)
	}

	fmt.Println(`Program stdout: ` + stdout.String())
	fmt.Println(`Program stderr: ` + stderr.String())

	attMap := make(map[string]string)
	attMap["algoName"] = configObj.SvcName
	attMap["algoVersion"] = version
	attMap["algoCmd"] = configObj.CliCmd + " " + inpObj.Command
	attMap["algoProcTime"] = time.Now().UTC().Format("20060102.150405.99999")

	// this is the other spot that handleFlist gets used, and works on the
	// same principles.

	ingFunc := func(fName, dummy, fType string) (string, error) {
		return pzsvc.IngestFile(fName, runID, fType, inpObj.PzAddr, configObj.SvcName, version, inpObj.PzAuth, attMap)
	}

	handleFList(inpObj.OutTiffs, nil, ingFunc, "raster", &output, output.OutFiles, w)
	handleFList(inpObj.OutTxts, nil, ingFunc, "text", &output, output.OutFiles, w)
	handleFList(inpObj.OutGeoJs, nil, ingFunc, "geojson", &output, output.OutFiles, w)

	return output
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package alitasks

import (
	"fmt"

	"github.com/denverdino/aliyungo/ram"

	"k8s.io/klog"
	"k8s.io/kops/upup/pkg/fi"
	"k8s.io/kops/upup/pkg/fi/cloudup/aliup"
	"k8s.io/kops/upup/pkg/fi/cloudup/terraform"
)

//go:generate fitask -type=RAMRole

type RAMRole struct {
	Lifecycle                *fi.Lifecycle
	Name                     *string
	AssumeRolePolicyDocument *string
	RAMRoleId                *string
}

var _ fi.CompareWithID = &RAMRole{}

func (r *RAMRole) CompareWithID() *string {
	return r.Name
}

func (r *RAMRole) Find(c *fi.Context) (*RAMRole, error) {
	cloud := c.Cloud.(aliup.ALICloud)

	roleList, err := cloud.RamClient().ListRoles()
	if err != nil {
		return nil, fmt.Errorf("error listing RamRoles: %v", err)
	}

	// Don't exist RAMrole with specified User.
	if len(roleList.Roles.Role) == 0 {
		return nil, nil
	}

	// The same user's RAM resource name can not be repeated
	for _, role := range roleList.Roles.Role {
		if role.RoleName == fi.StringValue(r.Name) {

			klog.V(2).Infof("found matching RamRole with name: %q", *r.Name)
			actual := &RAMRole{}
			actual.Name = fi.String(role.RoleName)
			actual.RAMRoleId = fi.String(role.RoleId)
			actual.AssumeRolePolicyDocument = fi.String(role.AssumeRolePolicyDocument)

			// Ignore "system" fields
			actual.Lifecycle = r.Lifecycle
			r.RAMRoleId = actual.RAMRoleId
			return actual, nil
		}
	}

	return nil, nil
}

func (r *RAMRole) Run(c *fi.Context) error {
	return fi.DefaultDeltaRunMethod(r, c)
}

func (_ *RAMRole) CheckChanges(a, e, changes *RAMRole) error {
	if a == nil {
		if e.AssumeRolePolicyDocument == nil {
			return fi.RequiredField("AssumeRolePolicyDocument")
		}
		if e.Name == nil {
			return fi.RequiredField("Name")
		}
	}
	return nil
}

func (_ *RAMRole) RenderALI(t *aliup.ALIAPITarget, a, e, changes *RAMRole) error {
	if a == nil {
		klog.V(2).Infof("Creating RAMRole with Name:%q", fi.StringValue(e.Name))

		roleRequest := ram.RoleRequest{
			RoleName:                 fi.StringValue(e.Name),
			AssumeRolePolicyDocument: fi.StringValue(e.AssumeRolePolicyDocument),
		}

		roleResponse, err := t.Cloud.RamClient().CreateRole(roleRequest)
		if err != nil {
			return fmt.Errorf("error creating RAMRole: %v", err)
		}

		e.RAMRoleId = fi.String(roleResponse.Role.RoleId)
	}

	return nil
}

type terraformRAMRole struct {
	Name     *string `json:"name,omitempty"`
	Document *string `json:"document,omitempty"`
}

func (_ *RAMRole) RenderTerraform(t *terraform.TerraformTarget, a, e, changes *RAMRole) error {
	tf := &terraformRAMRole{
		Name:     e.Name,
		Document: e.AssumeRolePolicyDocument,
	}
	return t.RenderResource("alicloud_ram_role", *e.Name, tf)
}

func (s *RAMRole) TerraformLink() *terraform.Literal {
	return terraform.LiteralProperty("alicloud_ram_role", *s.Name, "name")
}
<commit_msg>Alicloud: fix comparison failures for RamRole<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 alitasks

import (
	"fmt"
	"strings"

	"github.com/denverdino/aliyungo/common"
	"github.com/denverdino/aliyungo/ram"

	"k8s.io/klog"
	"k8s.io/kops/upup/pkg/fi"
	"k8s.io/kops/upup/pkg/fi/cloudup/aliup"
	"k8s.io/kops/upup/pkg/fi/cloudup/terraform"
)

//go:generate fitask -type=RAMRole

type RAMRole struct {
	Lifecycle                *fi.Lifecycle
	Name                     *string
	AssumeRolePolicyDocument *string
	RAMRoleId                *string
}

var _ fi.CompareWithID = &RAMRole{}

func (r *RAMRole) CompareWithID() *string {
	return r.Name
}

func compactPolicy(s string) string {
	removedStrings := []string{"\n", "<br>", " ", "\r\n"}
	for _, each := range removedStrings {
		s = strings.Replace(s, each, "", -1)
	}
	return s
}

func (r *RAMRole) Find(c *fi.Context) (*RAMRole, error) {
	cloud := c.Cloud.(aliup.ALICloud)

	request := ram.RoleQueryRequest{
		RoleName: fi.StringValue(r.Name),
	}

	roleResp, err := cloud.RamClient().GetRole(request)
	if err != nil {
		if e, ok := err.(*common.Error); ok && e.StatusCode == 404 {
			klog.V(2).Infof("no RamRole with name: %q", *r.Name)
			return nil, nil
		}
		return nil, fmt.Errorf("error get RamRole %q: %v", *r.Name, err)
	}

	role := roleResp.Role
	if role.RoleId == "" {
		klog.V(2).Infof("no RamRole with name: %q", *r.Name)
		return nil, nil
	}

	klog.V(2).Infof("found matching RamRole with name: %q", *r.Name)
	actual := &RAMRole{
		Name:                     fi.String(role.RoleName),
		RAMRoleId:                fi.String(role.RoleId),
		AssumeRolePolicyDocument: fi.String(compactPolicy(role.AssumeRolePolicyDocument)),
	}

	// Ignore "system" fields
	actual.Lifecycle = r.Lifecycle
	r.RAMRoleId = actual.RAMRoleId

	return actual, nil
}

func (r *RAMRole) Run(c *fi.Context) error {
	return fi.DefaultDeltaRunMethod(r, c)
}

func (_ *RAMRole) CheckChanges(a, e, changes *RAMRole) error {
	if a == nil {
		if e.AssumeRolePolicyDocument == nil {
			return fi.RequiredField("AssumeRolePolicyDocument")
		}
		if e.Name == nil {
			return fi.RequiredField("Name")
		}
	}
	return nil
}

func (_ *RAMRole) RenderALI(t *aliup.ALIAPITarget, a, e, changes *RAMRole) error {
	if a == nil {
		klog.V(2).Infof("Creating RAMRole with Name:%q", fi.StringValue(e.Name))

		roleRequest := ram.RoleRequest{
			RoleName:                 fi.StringValue(e.Name),
			AssumeRolePolicyDocument: fi.StringValue(e.AssumeRolePolicyDocument),
		}

		roleResponse, err := t.Cloud.RamClient().CreateRole(roleRequest)
		if err != nil {
			return fmt.Errorf("error creating RAMRole: %v", err)
		}

		e.RAMRoleId = fi.String(roleResponse.Role.RoleId)
	}

	return nil
}

type terraformRAMRole struct {
	Name     *string `json:"name,omitempty"`
	Document *string `json:"document,omitempty"`
}

func (_ *RAMRole) RenderTerraform(t *terraform.TerraformTarget, a, e, changes *RAMRole) error {
	tf := &terraformRAMRole{
		Name:     e.Name,
		Document: e.AssumeRolePolicyDocument,
	}
	return t.RenderResource("alicloud_ram_role", *e.Name, tf)
}

func (s *RAMRole) TerraformLink() *terraform.Literal {
	return terraform.LiteralProperty("alicloud_ram_role", *s.Name, "name")
}
<|endoftext|>


<commit_before>package nuimo

import (
	"log"
	"fmt"
	"strings"
	"github.com/currantlabs/ble"
	"github.com/currantlabs/ble/examples/lib/gatt"
	"github.com/currantlabs/ble/linux/hci"
	"github.com/currantlabs/ble/linux/hci/cmd"
	"encoding/binary"
)

const SERVICE_BATTERY_STATUS = "0000180F00001000800000805F9B34FB"
const SERVICE_DEVICE_INFO = "0000180A00001000800000805F9B34FB"
const SERVICE_LED_MATRIX = "F29B1523CB1940F3BE5C7241ECB82FD1"
const SERVICE_USER_INPUT = "F29B1525CB1940F3BE5C7241ECB82FD2"

const CHAR_BATTERY_LEVEL = "00002A1900001000800000805F9B34FB"
const CHAR_DEVICE_INFO = "00002A2900001000800000805F9B34FB"
const CHAR_LED_MATRIX = "F29B1524CB1940F3BE5C7241ECB82FD1"
const CHAR_INPUT_FLY = "F29B1526CB1940F3BE5C7241ECB82FD2"
const CHAR_INPUT_SWIPE = "F29B1527CB1940F3BE5C7241ECB82FD2"
const CHAR_INPUT_ROTATE = "F29B1528CB1940F3BE5C7241ECB82FD2"
const CHAR_INPUT_CLICK = "F29B1529CB1940F3BE5C7241ECB82FD2"

const DIR_LEFT = 0
const DIR_RIGHT = 1
const DIR_UP = 2
const DIR_BACKWARDS = 2
const DIR_DOWN = 3
const DIR_TOWARDS = 3
const DIR_UPDOWN = 4

const CLICK_DOWN = 1
const CLICK_UP = 0

type Nuimo struct {
	client ble.Client
	events chan Event
	led    *ble.Characteristic
}

type Event struct {
	Key   string
	Value int64
	Raw   []byte
}

func Connect() (*Nuimo, error) {
	filter := func(a ble.Advertisement) bool {
		return strings.ToUpper(a.LocalName()) == "NUIMO"
	}

	// Set connection parameters. Only supported on Linux platform.
	d := gatt.DefaultDevice()
	if h, ok := d.(*hci.HCI); ok {
		if err := h.Option(hci.OptConnParams(
			cmd.LECreateConnection{
				LEScanInterval:        0x0004, // 0x0004 - 0x4000; N * 0.625 msec
				LEScanWindow:          0x0004, // 0x0004 - 0x4000; N * 0.625 msec
				InitiatorFilterPolicy: 0x00, // White list is not used
				PeerAddressType:       0x00, // Public Device Address
				PeerAddress:           [6]byte{}, //
				OwnAddressType:        0x00, // Public Device Address
				ConnIntervalMin:       0x0006, // 0x0006 - 0x0C80; N * 1.25 msec
				ConnIntervalMax:       0x0006, // 0x0006 - 0x0C80; N * 1.25 msec
				ConnLatency:           0x0000, // 0x0000 - 0x01F3; N * 1.25 msec
				SupervisionTimeout:    0x0048, // 0x000A - 0x0C80; N * 10 msec
				MinimumCELength:       0x0000, // 0x0000 - 0xFFFF; N * 0.625 msec
				MaximumCELength:       0x0000, // 0x0000 - 0xFFFF; N * 0.625 msec
			})); err != nil {
			log.Fatalf("can't set advertising param: %s", err)
		}
	}

	client, err := gatt.Discover(gatt.FilterFunc(filter))
	if err != nil {
		return nil, err
	}

	ch := make(chan Event)
	n := &Nuimo{client: client, events: ch}
	err = n.DiscoverServices()
	return n, err

}

func (n *Nuimo) Events() <-chan Event {
	return n.events
}

func (n *Nuimo) Display(matrix []byte, brightness uint8, timeout uint8) {

	displayMatrix := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}

	for c, dots := range matrix {
		if c > 10 {
			break;
		}
		displayMatrix[c] = dots
	}

	displayMatrix[11] = brightness
	displayMatrix[12] = timeout

	n.client.WriteCharacteristic(n.led, displayMatrix, true)
}

func DisplayMatrix(dots ...byte) []byte {
	bytes := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
	var b uint8
	var i uint8
	dotCount := uint8(len(dots))

	for b = 0; b < 11; b++ {
		for i = 0; i < 8; i++ {
			dot := (b * 8) + i
			//log.Printf("%d %d %d (%t) %d dot", b, i, dot, dots[dot] > 0, byte(1)<<i)
			if dot < dotCount && dots[dot] > 0 {
				bytes[b] |= byte(1)<<i
			}
		}

	}

	return bytes
}

func (n *Nuimo) DiscoverServices() error {
	p, err := n.client.DiscoverProfile(true)
	if err != nil {
		return fmt.Errorf("can't discover services: %s\n", err)
	}

	for _, s := range p.Services {

		if s.UUID.Equal(ble.MustParse(SERVICE_BATTERY_STATUS)) {
			for _, c := range s.Characteristics {
				if (c.UUID.Equal(ble.MustParse(CHAR_BATTERY_LEVEL))) {
					n.client.Subscribe(c, false, n.battery)
				}
			}
		}

		if s.UUID.Equal(ble.MustParse(SERVICE_USER_INPUT)) {
			for _, c := range s.Characteristics {
				if (c.UUID.Equal(ble.MustParse(CHAR_INPUT_CLICK))) {
					n.client.Subscribe(c, false, n.click)
				}

				if (c.UUID.Equal(ble.MustParse(CHAR_INPUT_ROTATE))) {
					n.client.Subscribe(c, false, n.rotate)
				}

				if (c.UUID.Equal(ble.MustParse(CHAR_INPUT_SWIPE))) {
					n.client.Subscribe(c, false, n.swipe)
				}
				if (c.UUID.Equal(ble.MustParse(CHAR_INPUT_FLY))) {
					n.client.Subscribe(c, false, n.fly)
				}
			}
		}

		if s.UUID.Equal(ble.MustParse(SERVICE_LED_MATRIX)) {
			for _, c := range s.Characteristics {
				n.led = c
			}
		}

		//fmt.Printf("Service: %s %s, Handle (0x%02X)\n", s.UUID.String(), ble.Name(s.UUID), s.Handle)
	}
	return nil
}

func (n *Nuimo) Disconnect() error {
	close(n.events)
	return n.client.CancelConnection()
}

func (n *Nuimo) battery(req []byte) {
	uval, _ := binary.Uvarint(req)
	level := int64(uval)
	n.events <- Event{Key:"battery", Raw: req, Value: level}
}

func (n *Nuimo) click(req []byte) {
	uval, _ := binary.Uvarint(req)
	dir := int64(uval)
	switch dir {
	case CLICK_DOWN:
		n.events <- Event{Key:"press", Raw: req}
	case CLICK_UP:
		n.events <- Event{Key:"release", Raw: req}
	}
}

func (n *Nuimo) rotate(req []byte) {
	uval := binary.LittleEndian.Uint16(req)
	val := int64(int16(uval))
	n.events <- Event{Key:"rotate", Raw: req, Value: val}
}
func (n *Nuimo) swipe(req []byte) {
	uval, _ := binary.Uvarint(req)
	dir := int64(uval)
	n.events <- Event{Key:"swipe", Raw: req, Value: dir}

	switch dir {
	case DIR_LEFT:
		n.events <- Event{Key:"swipe_left", Raw: req}
	case DIR_RIGHT:
		n.events <- Event{Key:"swipe_right", Raw: req}
	case DIR_UP:
		n.events <- Event{Key:"swipe_up", Raw: req}
	case DIR_DOWN:
		n.events <- Event{Key:"swipe_down", Raw: req}
	}
}
func (n *Nuimo) fly(req []byte) {
	uval, _ := binary.Uvarint(req[0:1])
	dir := int(uval)
	uval, _ = binary.Uvarint(req[2:])
	distance := int64(uval)

	switch dir {
	case DIR_LEFT:
		n.events <- Event{Key:"fly_left", Raw: req, Value: distance}
	case DIR_RIGHT:
		n.events <- Event{Key:"fly_right", Raw: req, Value: distance}
	case DIR_BACKWARDS:
		n.events <- Event{Key:"fly_backwards", Raw: req, Value: distance}
	case DIR_TOWARDS:
		n.events <- Event{Key:"fly_towards", Raw: req, Value: distance}
	case DIR_UPDOWN:
		n.events <- Event{Key:"fly_updown", Raw: req, Value: distance}
	}
}
<commit_msg>Remove unused dev code<commit_after>package nuimo

import (
	"log"
	"fmt"
	"strings"
	"github.com/currantlabs/ble"
	"github.com/currantlabs/ble/examples/lib/gatt"
	"github.com/currantlabs/ble/linux/hci"
	"github.com/currantlabs/ble/linux/hci/cmd"
	"encoding/binary"
)

const SERVICE_BATTERY_STATUS = "0000180F00001000800000805F9B34FB"
const SERVICE_DEVICE_INFO = "0000180A00001000800000805F9B34FB"
const SERVICE_LED_MATRIX = "F29B1523CB1940F3BE5C7241ECB82FD1"
const SERVICE_USER_INPUT = "F29B1525CB1940F3BE5C7241ECB82FD2"

const CHAR_BATTERY_LEVEL = "00002A1900001000800000805F9B34FB"
const CHAR_DEVICE_INFO = "00002A2900001000800000805F9B34FB"
const CHAR_LED_MATRIX = "F29B1524CB1940F3BE5C7241ECB82FD1"
const CHAR_INPUT_FLY = "F29B1526CB1940F3BE5C7241ECB82FD2"
const CHAR_INPUT_SWIPE = "F29B1527CB1940F3BE5C7241ECB82FD2"
const CHAR_INPUT_ROTATE = "F29B1528CB1940F3BE5C7241ECB82FD2"
const CHAR_INPUT_CLICK = "F29B1529CB1940F3BE5C7241ECB82FD2"

const DIR_LEFT = 0
const DIR_RIGHT = 1
const DIR_UP = 2
const DIR_BACKWARDS = 2
const DIR_DOWN = 3
const DIR_TOWARDS = 3
const DIR_UPDOWN = 4

const CLICK_DOWN = 1
const CLICK_UP = 0

type Nuimo struct {
	client ble.Client
	events chan Event
	led    *ble.Characteristic
}

type Event struct {
	Key   string
	Value int64
	Raw   []byte
}

func Connect() (*Nuimo, error) {
	filter := func(a ble.Advertisement) bool {
		return strings.ToUpper(a.LocalName()) == "NUIMO"
	}

	// Set connection parameters. Only supported on Linux platform.
	d := gatt.DefaultDevice()
	if h, ok := d.(*hci.HCI); ok {
		if err := h.Option(hci.OptConnParams(
			cmd.LECreateConnection{
				LEScanInterval:        0x0004, // 0x0004 - 0x4000; N * 0.625 msec
				LEScanWindow:          0x0004, // 0x0004 - 0x4000; N * 0.625 msec
				InitiatorFilterPolicy: 0x00, // White list is not used
				PeerAddressType:       0x00, // Public Device Address
				PeerAddress:           [6]byte{}, //
				OwnAddressType:        0x00, // Public Device Address
				ConnIntervalMin:       0x0006, // 0x0006 - 0x0C80; N * 1.25 msec
				ConnIntervalMax:       0x0006, // 0x0006 - 0x0C80; N * 1.25 msec
				ConnLatency:           0x0000, // 0x0000 - 0x01F3; N * 1.25 msec
				SupervisionTimeout:    0x0048, // 0x000A - 0x0C80; N * 10 msec
				MinimumCELength:       0x0000, // 0x0000 - 0xFFFF; N * 0.625 msec
				MaximumCELength:       0x0000, // 0x0000 - 0xFFFF; N * 0.625 msec
			})); err != nil {
			log.Fatalf("can't set advertising param: %s", err)
		}
	}

	client, err := gatt.Discover(gatt.FilterFunc(filter))
	if err != nil {
		return nil, err
	}

	ch := make(chan Event)
	n := &Nuimo{client: client, events: ch}
	err = n.DiscoverServices()
	return n, err

}

func (n *Nuimo) Events() <-chan Event {
	return n.events
}

func (n *Nuimo) Display(matrix []byte, brightness uint8, timeout uint8) {

	displayMatrix := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}

	for c, dots := range matrix {
		if c > 10 {
			break;
		}
		displayMatrix[c] = dots
	}

	displayMatrix[11] = brightness
	displayMatrix[12] = timeout

	n.client.WriteCharacteristic(n.led, displayMatrix, true)
}

func DisplayMatrix(dots ...byte) []byte {
	bytes := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
	var b uint8
	var i uint8
	dotCount := uint8(len(dots))

	for b = 0; b < 11; b++ {
		for i = 0; i < 8; i++ {
			dot := (b * 8) + i
			if dot < dotCount && dots[dot] > 0 {
				bytes[b] |= byte(1)<<i
			}
		}

	}

	return bytes
}

func (n *Nuimo) DiscoverServices() error {
	p, err := n.client.DiscoverProfile(true)
	if err != nil {
		return fmt.Errorf("can't discover services: %s\n", err)
	}

	for _, s := range p.Services {

		if s.UUID.Equal(ble.MustParse(SERVICE_BATTERY_STATUS)) {
			for _, c := range s.Characteristics {
				if (c.UUID.Equal(ble.MustParse(CHAR_BATTERY_LEVEL))) {
					n.client.Subscribe(c, false, n.battery)
				}
			}
		}

		if s.UUID.Equal(ble.MustParse(SERVICE_USER_INPUT)) {
			for _, c := range s.Characteristics {
				if (c.UUID.Equal(ble.MustParse(CHAR_INPUT_CLICK))) {
					n.client.Subscribe(c, false, n.click)
				}

				if (c.UUID.Equal(ble.MustParse(CHAR_INPUT_ROTATE))) {
					n.client.Subscribe(c, false, n.rotate)
				}

				if (c.UUID.Equal(ble.MustParse(CHAR_INPUT_SWIPE))) {
					n.client.Subscribe(c, false, n.swipe)
				}
				if (c.UUID.Equal(ble.MustParse(CHAR_INPUT_FLY))) {
					n.client.Subscribe(c, false, n.fly)
				}
			}
		}

		if s.UUID.Equal(ble.MustParse(SERVICE_LED_MATRIX)) {
			for _, c := range s.Characteristics {
				n.led = c
			}
		}

		//fmt.Printf("Service: %s %s, Handle (0x%02X)\n", s.UUID.String(), ble.Name(s.UUID), s.Handle)
	}
	return nil
}

func (n *Nuimo) Disconnect() error {
	close(n.events)
	return n.client.CancelConnection()
}

func (n *Nuimo) battery(req []byte) {
	uval, _ := binary.Uvarint(req)
	level := int64(uval)
	n.events <- Event{Key:"battery", Raw: req, Value: level}
}

func (n *Nuimo) click(req []byte) {
	uval, _ := binary.Uvarint(req)
	dir := int64(uval)
	switch dir {
	case CLICK_DOWN:
		n.events <- Event{Key:"press", Raw: req}
	case CLICK_UP:
		n.events <- Event{Key:"release", Raw: req}
	}
}

func (n *Nuimo) rotate(req []byte) {
	uval := binary.LittleEndian.Uint16(req)
	val := int64(int16(uval))
	n.events <- Event{Key:"rotate", Raw: req, Value: val}
}
func (n *Nuimo) swipe(req []byte) {
	uval, _ := binary.Uvarint(req)
	dir := int64(uval)
	n.events <- Event{Key:"swipe", Raw: req, Value: dir}

	switch dir {
	case DIR_LEFT:
		n.events <- Event{Key:"swipe_left", Raw: req}
	case DIR_RIGHT:
		n.events <- Event{Key:"swipe_right", Raw: req}
	case DIR_UP:
		n.events <- Event{Key:"swipe_up", Raw: req}
	case DIR_DOWN:
		n.events <- Event{Key:"swipe_down", Raw: req}
	}
}
func (n *Nuimo) fly(req []byte) {
	uval, _ := binary.Uvarint(req[0:1])
	dir := int(uval)
	uval, _ = binary.Uvarint(req[2:])
	distance := int64(uval)

	switch dir {
	case DIR_LEFT:
		n.events <- Event{Key:"fly_left", Raw: req, Value: distance}
	case DIR_RIGHT:
		n.events <- Event{Key:"fly_right", Raw: req, Value: distance}
	case DIR_BACKWARDS:
		n.events <- Event{Key:"fly_backwards", Raw: req, Value: distance}
	case DIR_TOWARDS:
		n.events <- Event{Key:"fly_towards", Raw: req, Value: distance}
	case DIR_UPDOWN:
		n.events <- Event{Key:"fly_updown", Raw: req, Value: distance}
	}
}
<|endoftext|>


<commit_before>package cache

import (
	"fmt"
	"go/build"
	goimporter "go/importer"
	"go/token"
	"go/types"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"golang.org/x/tools/go/gcexportdata"
)

// We need to mangle go/build.Default to make gcimporter work as
// intended, so use a lock to protect against concurrent accesses.
var buildDefaultLock sync.Mutex

// Mu must be held while using the cache importer.
var Mu sync.Mutex

var importCache = importerCache{
	fset:    token.NewFileSet(),
	imports: make(map[string]importCacheEntry),
}

func NewImporter(ctx *PackedContext, filename string, fallbackToSource bool) types.ImporterFrom {
	importCache.clean()

	imp := &importer{
		ctx:              ctx,
		importerCache:    &importCache,
		fallbackToSource: fallbackToSource,
	}

	slashed := filepath.ToSlash(filename)
	i := strings.LastIndex(slashed, "/vendor/src/")
	if i < 0 {
		i = strings.LastIndex(slashed, "/src/")
	}
	if i > 0 {
		paths := filepath.SplitList(imp.ctx.GOPATH)

		gbroot := filepath.FromSlash(slashed[:i])
		gbvendor := filepath.Join(gbroot, "vendor")
		if SamePath(gbroot, imp.ctx.GOROOT) {
			goto Found
		}
		for _, path := range paths {
			if SamePath(path, gbroot) || SamePath(path, gbvendor) {
				goto Found
			}
		}

		imp.gbroot = gbroot
		imp.gbvendor = gbvendor
	Found:
	}

	return imp
}

type importer struct {
	*importerCache
	gbroot, gbvendor string
	ctx              *PackedContext
	fallbackToSource bool
}

type importerCache struct {
	fset    *token.FileSet
	imports map[string]importCacheEntry
}

type importCacheEntry struct {
	pkg   *types.Package
	mtime time.Time
}

func (i *importer) Import(importPath string) (*types.Package, error) {
	return i.ImportFrom(importPath, "", 0)
}

func (i *importer) ImportFrom(importPath, srcDir string, mode types.ImportMode) (*types.Package, error) {
	buildDefaultLock.Lock()
	defer buildDefaultLock.Unlock()

	origDef := build.Default
	defer func() { build.Default = origDef }()

	def := &build.Default
	// The gb root of a project can be used as a $GOPATH because it contains pkg/.
	def.GOPATH = i.ctx.GOPATH
	if i.gbroot != "" {
		def.GOPATH = i.gbroot
	}
	def.GOARCH = i.ctx.GOARCH
	def.GOOS = i.ctx.GOOS
	def.GOROOT = i.ctx.GOROOT
	def.CgoEnabled = i.ctx.CgoEnabled
	def.UseAllFiles = i.ctx.UseAllFiles
	def.Compiler = i.ctx.Compiler
	def.BuildTags = i.ctx.BuildTags
	def.ReleaseTags = i.ctx.ReleaseTags
	def.InstallSuffix = i.ctx.InstallSuffix
	def.SplitPathList = i.splitPathList
	def.JoinPath = i.joinPath

	filename, path := gcexportdata.Find(importPath, srcDir)
	entry, ok := i.imports[path]
	if filename == "" {
		// If there is no export data, check the cache.
		// TODO(rstambler): Develop a better heuristic for entry eviction.
		if ok && time.Since(entry.mtime) <= time.Minute*20 {
			return entry.pkg, nil
		}
		// If there is no cache entry and the user has configured the correct
		// setting, import and cache using the source importer.
		if i.fallbackToSource {
			pkg, err := goimporter.For("source", nil).Import(path)
			if pkg == nil {
				return nil, err
			}
			entry = importCacheEntry{pkg, time.Now()}
			i.imports[path] = entry
			return entry.pkg, nil
		}
	}

	// If there is export data for the package.
	fi, err := os.Stat(filename)
	if err != nil {
		return nil, err
	}
	if entry.mtime != fi.ModTime() {
		f, err := os.Open(filename)
		if err != nil {
			return nil, err
		}
		in, err := gcexportdata.NewReader(f)
		if err != nil {
			return nil, err
		}
		pkg, err := gcexportdata.Read(in, i.fset, make(map[string]*types.Package), path)
		if err != nil {
			return nil, err
		}
		entry = importCacheEntry{pkg, fi.ModTime()}
		i.imports[path] = entry
	}

	return entry.pkg, nil
}

// Delete random files to keep the cache at most 100 entries.
// Only call while holding the importer's mutex.
func (i *importerCache) clean() {
	for k := range i.imports {
		if len(i.imports) <= 100 {
			break
		}
		delete(i.imports, k)
	}
}

func (i *importer) splitPathList(list string) []string {
	res := filepath.SplitList(list)
	if i.gbroot != "" {
		res = append(res, i.gbroot, i.gbvendor)
	}
	return res
}

func (i *importer) joinPath(elem ...string) string {
	res := filepath.Join(elem...)

	if i.gbroot != "" {
		// Want to rewrite "$GBROOT/(vendor/)?pkg/$GOOS_$GOARCH(_)?"
		// into "$GBROOT/pkg/$GOOS-$GOARCH(-)?".
		// Note: gb doesn't use vendor/pkg.
		if gbrel, err := filepath.Rel(i.gbroot, res); err == nil {
			gbrel = filepath.ToSlash(gbrel)
			gbrel, _ = match(gbrel, "vendor/")
			if gbrel, ok := match(gbrel, fmt.Sprintf("pkg/%s_%s", i.ctx.GOOS, i.ctx.GOARCH)); ok {
				gbrel, hasSuffix := match(gbrel, "_")

				// Reassemble into result.
				if hasSuffix {
					gbrel = "-" + gbrel
				}
				gbrel = fmt.Sprintf("pkg/%s-%s/", i.ctx.GOOS, i.ctx.GOARCH) + gbrel
				gbrel = filepath.FromSlash(gbrel)
				res = filepath.Join(i.gbroot, gbrel)
			}
		}
	}
	return res
}

func match(s, prefix string) (string, bool) {
	rest := strings.TrimPrefix(s, prefix)
	return rest, len(rest) < len(s)
}
<commit_msg>internal/cache: return in importer if no export data found<commit_after>package cache

import (
	"fmt"
	"go/build"
	goimporter "go/importer"
	"go/token"
	"go/types"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"golang.org/x/tools/go/gcexportdata"
)

// We need to mangle go/build.Default to make gcimporter work as
// intended, so use a lock to protect against concurrent accesses.
var buildDefaultLock sync.Mutex

// Mu must be held while using the cache importer.
var Mu sync.Mutex

var importCache = importerCache{
	fset:    token.NewFileSet(),
	imports: make(map[string]importCacheEntry),
}

func NewImporter(ctx *PackedContext, filename string, fallbackToSource bool) types.ImporterFrom {
	importCache.clean()

	imp := &importer{
		ctx:              ctx,
		importerCache:    &importCache,
		fallbackToSource: fallbackToSource,
	}

	slashed := filepath.ToSlash(filename)
	i := strings.LastIndex(slashed, "/vendor/src/")
	if i < 0 {
		i = strings.LastIndex(slashed, "/src/")
	}
	if i > 0 {
		paths := filepath.SplitList(imp.ctx.GOPATH)

		gbroot := filepath.FromSlash(slashed[:i])
		gbvendor := filepath.Join(gbroot, "vendor")
		if SamePath(gbroot, imp.ctx.GOROOT) {
			goto Found
		}
		for _, path := range paths {
			if SamePath(path, gbroot) || SamePath(path, gbvendor) {
				goto Found
			}
		}

		imp.gbroot = gbroot
		imp.gbvendor = gbvendor
	Found:
	}

	return imp
}

type importer struct {
	*importerCache
	gbroot, gbvendor string
	ctx              *PackedContext
	fallbackToSource bool
}

type importerCache struct {
	fset    *token.FileSet
	imports map[string]importCacheEntry
}

type importCacheEntry struct {
	pkg   *types.Package
	mtime time.Time
}

func (i *importer) Import(importPath string) (*types.Package, error) {
	return i.ImportFrom(importPath, "", 0)
}

func (i *importer) ImportFrom(importPath, srcDir string, mode types.ImportMode) (*types.Package, error) {
	buildDefaultLock.Lock()
	defer buildDefaultLock.Unlock()

	origDef := build.Default
	defer func() { build.Default = origDef }()

	def := &build.Default
	// The gb root of a project can be used as a $GOPATH because it contains pkg/.
	def.GOPATH = i.ctx.GOPATH
	if i.gbroot != "" {
		def.GOPATH = i.gbroot
	}
	def.GOARCH = i.ctx.GOARCH
	def.GOOS = i.ctx.GOOS
	def.GOROOT = i.ctx.GOROOT
	def.CgoEnabled = i.ctx.CgoEnabled
	def.UseAllFiles = i.ctx.UseAllFiles
	def.Compiler = i.ctx.Compiler
	def.BuildTags = i.ctx.BuildTags
	def.ReleaseTags = i.ctx.ReleaseTags
	def.InstallSuffix = i.ctx.InstallSuffix
	def.SplitPathList = i.splitPathList
	def.JoinPath = i.joinPath

	filename, path := gcexportdata.Find(importPath, srcDir)
	entry, ok := i.imports[path]
	if filename == "" {
		// If there is no export data, check the cache.
		// TODO(rstambler): Develop a better heuristic for entry eviction.
		if ok && time.Since(entry.mtime) <= time.Minute*20 {
			return entry.pkg, nil
		}
		// If there is no cache entry and the user has configured the correct
		// setting, import and cache using the source importer.
		if i.fallbackToSource {
			pkg, err := goimporter.For("source", nil).Import(path)
			if pkg == nil {
				return nil, err
			}
			entry = importCacheEntry{pkg, time.Now()}
			i.imports[path] = entry
			return entry.pkg, nil
		}
		return nil, fmt.Errorf("no export data for %s", path)
	}

	// If there is export data for the package.
	fi, err := os.Stat(filename)
	if err != nil {
		return nil, err
	}
	if entry.mtime != fi.ModTime() {
		f, err := os.Open(filename)
		if err != nil {
			return nil, err
		}
		in, err := gcexportdata.NewReader(f)
		if err != nil {
			return nil, err
		}
		pkg, err := gcexportdata.Read(in, i.fset, make(map[string]*types.Package), path)
		if err != nil {
			return nil, err
		}
		entry = importCacheEntry{pkg, fi.ModTime()}
		i.imports[path] = entry
	}

	return entry.pkg, nil
}

// Delete random files to keep the cache at most 100 entries.
// Only call while holding the importer's mutex.
func (i *importerCache) clean() {
	for k := range i.imports {
		if len(i.imports) <= 100 {
			break
		}
		delete(i.imports, k)
	}
}

func (i *importer) splitPathList(list string) []string {
	res := filepath.SplitList(list)
	if i.gbroot != "" {
		res = append(res, i.gbroot, i.gbvendor)
	}
	return res
}

func (i *importer) joinPath(elem ...string) string {
	res := filepath.Join(elem...)

	if i.gbroot != "" {
		// Want to rewrite "$GBROOT/(vendor/)?pkg/$GOOS_$GOARCH(_)?"
		// into "$GBROOT/pkg/$GOOS-$GOARCH(-)?".
		// Note: gb doesn't use vendor/pkg.
		if gbrel, err := filepath.Rel(i.gbroot, res); err == nil {
			gbrel = filepath.ToSlash(gbrel)
			gbrel, _ = match(gbrel, "vendor/")
			if gbrel, ok := match(gbrel, fmt.Sprintf("pkg/%s_%s", i.ctx.GOOS, i.ctx.GOARCH)); ok {
				gbrel, hasSuffix := match(gbrel, "_")

				// Reassemble into result.
				if hasSuffix {
					gbrel = "-" + gbrel
				}
				gbrel = fmt.Sprintf("pkg/%s-%s/", i.ctx.GOOS, i.ctx.GOARCH) + gbrel
				gbrel = filepath.FromSlash(gbrel)
				res = filepath.Join(i.gbroot, gbrel)
			}
		}
	}
	return res
}

func match(s, prefix string) (string, bool) {
	rest := strings.TrimPrefix(s, prefix)
	return rest, len(rest) < len(s)
}
<|endoftext|>