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

package hbook // import "go-hep.org/x/hep/hbook"

import (
	"bufio"
	"bytes"
	"encoding/gob"
	"fmt"
	"io"
	"math"
	"sort"
	"strings"
)

//go:generate go get github.com/campoy/embedmd
//go:generate embedmd -w README.md

//go:generate brio-gen -p go-hep.org/x/hep/hbook -t Dist0D,Dist1D,Dist2D -o dist_brio.go
//go:generate brio-gen -p go-hep.org/x/hep/hbook -t Range,Binning1D,BinningP1D,Bin1D,BinP1D,Binning2D,Bin2D -o binning_brio.go
//go:generate brio-gen -p go-hep.org/x/hep/hbook -t Point2D -o points_brio.go
//go:generate brio-gen -p go-hep.org/x/hep/hbook -t H1D,H2D,P1D,S2D -o hbook_brio.go

// Bin models 1D, 2D, ... bins.
type Bin interface {
	Rank() int           // Number of dimensions of the bin
	Entries() int64      // Number of entries in the bin
	EffEntries() float64 // Effective number of entries in the bin
	SumW() float64       // sum of weights
	SumW2() float64      // sum of squared weights
}

// Range is a 1-dim interval [Min, Max].
type Range struct {
	Min float64
	Max float64
}

// Width returns the size of the range.
func (r Range) Width() float64 {
	return math.Abs(r.Max - r.Min)
}

// Annotation is a bag of attributes that are attached to a histogram.
type Annotation map[string]interface{}

// Histogram is an n-dim histogram (with weighted entries)
type Histogram interface {
	// Annotation returns the annotations attached to the
	// histogram. (e.g. name, title, ...)
	Annotation() Annotation

	// Name returns the name of this histogram
	Name() string

	// Rank returns the number of dimensions of this histogram.
	Rank() int

	// Entries returns the number of entries of this histogram.
	Entries() int64
}

// MarshalYODA implements the YODAMarshaler interface.
func (ann Annotation) MarshalYODA() ([]byte, error) {
	keys := make([]string, 0, len(ann))
	for k := range ann {
		if k == "" {
			continue
		}
		keys = append(keys, k)
	}
	sort.Strings(keys)
	buf := new(bytes.Buffer)
	for _, k := range keys {
		fmt.Fprintf(buf, "%s=%v\n", k, ann[k])
	}
	return buf.Bytes(), nil
}

// UnmarshalYODA implements the YODAUnmarshaler interface.
func (ann *Annotation) UnmarshalYODA(data []byte) error {
	var err error
	s := bufio.NewScanner(bytes.NewReader(data))
	for s.Scan() {
		txt := s.Text()
		i := strings.Index(txt, "=")
		k := txt[:i]
		v := txt[i+1:]
		(*ann)[k] = v
	}
	err = s.Err()
	if err == io.EOF {
		err = nil
	}
	return err
}

// MarshalBinary implements encoding.BinaryMarshaler
func (ann *Annotation) MarshalBinary() ([]byte, error) {
	var v map[string]interface{} = *ann
	buf := new(bytes.Buffer)
	err := gob.NewEncoder(buf).Encode(v)
	return buf.Bytes(), err
}

// UnmarshalBinary implements encoding.BinaryUnmarshaler
func (ann *Annotation) UnmarshalBinary(data []byte) error {
	var v = make(map[string]interface{})
	buf := bytes.NewReader(data)
	err := gob.NewDecoder(buf).Decode(&v)
	if err != nil {
		return err
	}
	*ann = Annotation(v)
	return nil
}
<commit_msg>hbook: fix generate stanza for binningP1D<commit_after>// Copyright 2016 The go-hep Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package hbook // import "go-hep.org/x/hep/hbook"

import (
	"bufio"
	"bytes"
	"encoding/gob"
	"fmt"
	"io"
	"math"
	"sort"
	"strings"
)

//go:generate go get github.com/campoy/embedmd
//go:generate embedmd -w README.md

//go:generate brio-gen -p go-hep.org/x/hep/hbook -t Dist0D,Dist1D,Dist2D -o dist_brio.go
//go:generate brio-gen -p go-hep.org/x/hep/hbook -t Range,Binning1D,binningP1D,Bin1D,BinP1D,Binning2D,Bin2D -o binning_brio.go
//go:generate brio-gen -p go-hep.org/x/hep/hbook -t Point2D -o points_brio.go
//go:generate brio-gen -p go-hep.org/x/hep/hbook -t H1D,H2D,P1D,S2D -o hbook_brio.go

// Bin models 1D, 2D, ... bins.
type Bin interface {
	Rank() int           // Number of dimensions of the bin
	Entries() int64      // Number of entries in the bin
	EffEntries() float64 // Effective number of entries in the bin
	SumW() float64       // sum of weights
	SumW2() float64      // sum of squared weights
}

// Range is a 1-dim interval [Min, Max].
type Range struct {
	Min float64
	Max float64
}

// Width returns the size of the range.
func (r Range) Width() float64 {
	return math.Abs(r.Max - r.Min)
}

// Annotation is a bag of attributes that are attached to a histogram.
type Annotation map[string]interface{}

// Histogram is an n-dim histogram (with weighted entries)
type Histogram interface {
	// Annotation returns the annotations attached to the
	// histogram. (e.g. name, title, ...)
	Annotation() Annotation

	// Name returns the name of this histogram
	Name() string

	// Rank returns the number of dimensions of this histogram.
	Rank() int

	// Entries returns the number of entries of this histogram.
	Entries() int64
}

// MarshalYODA implements the YODAMarshaler interface.
func (ann Annotation) MarshalYODA() ([]byte, error) {
	keys := make([]string, 0, len(ann))
	for k := range ann {
		if k == "" {
			continue
		}
		keys = append(keys, k)
	}
	sort.Strings(keys)
	buf := new(bytes.Buffer)
	for _, k := range keys {
		fmt.Fprintf(buf, "%s=%v\n", k, ann[k])
	}
	return buf.Bytes(), nil
}

// UnmarshalYODA implements the YODAUnmarshaler interface.
func (ann *Annotation) UnmarshalYODA(data []byte) error {
	var err error
	s := bufio.NewScanner(bytes.NewReader(data))
	for s.Scan() {
		txt := s.Text()
		i := strings.Index(txt, "=")
		k := txt[:i]
		v := txt[i+1:]
		(*ann)[k] = v
	}
	err = s.Err()
	if err == io.EOF {
		err = nil
	}
	return err
}

// MarshalBinary implements encoding.BinaryMarshaler
func (ann *Annotation) MarshalBinary() ([]byte, error) {
	var v map[string]interface{} = *ann
	buf := new(bytes.Buffer)
	err := gob.NewEncoder(buf).Encode(v)
	return buf.Bytes(), err
}

// UnmarshalBinary implements encoding.BinaryUnmarshaler
func (ann *Annotation) UnmarshalBinary(data []byte) error {
	var v = make(map[string]interface{})
	buf := bytes.NewReader(data)
	err := gob.NewDecoder(buf).Decode(&v)
	if err != nil {
		return err
	}
	*ann = Annotation(v)
	return nil
}
<|endoftext|>


<commit_before>package helper

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"os"

	"github.com/SYNQfm/SYNQ-Golang/synq"
	"github.com/SYNQfm/helpers/common"
)

func LoadFromCache(name string, c common.Cacheable, obj interface{}) bool {
	cacheFile := c.GetCacheFile(name)
	if cacheFile != "" {
		if _, e := os.Stat(cacheFile); e == nil {
			log.Printf("loading from cached file %s\n", cacheFile)
			bytes, _ := ioutil.ReadFile(cacheFile)
			json.Unmarshal(bytes, obj)
			return true
		}
	}
	return false
}

func SaveToCache(name string, c common.Cacheable, obj interface{}) bool {
	cacheFile := c.GetCacheFile(name)
	if cacheFile != "" {
		data, _ := json.Marshal(obj)
		ioutil.WriteFile(cacheFile, data, 0755)
		return true
	}
	return false
}

func LoadVideosByQuery(query, name string, c common.Cacheable, api synq.Api) (videos []synq.Video, err error) {
	ok := LoadFromCache(name, c, &videos)
	if ok {
		return videos, nil
	}
	log.Printf("querying '%s'\n", query)
	videos, err = api.Query(query)
	if err != nil {
		return videos, err
	}
	SaveToCache(name, c, videos)
	return videos, err
}

// fow now, the query will be the account id
func LoadVideosByQueryV2(query, name string, c common.Cacheable, api synq.ApiV2) (videos []synq.VideoV2, err error) {
	ok := LoadFromCache(name, c, &videos)
	if ok {
		return videos, nil
	}
	log.Printf("get all videos (filter by account '%s')\n", query)
	videos, err = api.GetVideos(query)
	if err != nil {
		return videos, err
	}
	SaveToCache(name, c, videos)
	return videos, err
}

func LoadVideo(id string, c common.Cacheable, api synq.Api) (video synq.Video, err error) {
	ok := LoadFromCache(id, c, &video)
	if ok {
		video.Api = &api
		return video, nil
	}
	// need to use the v1 api to get the raw video data
	log.Printf("Getting video %s", id)
	video, e := api.GetVideo(id)
	if e != nil {
		return video, e
	}
	SaveToCache(id, c, &video)
	return video, nil
}

func LoadVideoV2(id string, c common.Cacheable, api synq.ApiV2) (video synq.VideoV2, err error) {
	ok := LoadFromCache(id, c, &video)
	if ok {
		video.Api = &api
		return video, nil
	}
	log.Printf("Getting video %s\n", id)
	video, err = api.GetVideo(id)
	if err != nil {
		return video, err
	}
	SaveToCache(id, c, &video)
	video.Api = &api
	return video, nil
}

func LoadUploadParameters(id string, req synq.UnicornParam, c common.Cacheable, api synq.ApiV2) (up synq.UploadParameters, err error) {
	lookId := id
	if req.AssetId != "" {
		lookId = req.AssetId
	}
	ok := LoadFromCache(lookId+"_up", c, &up)
	if ok {
		return up, nil
	}
	log.Printf("Getting upload parameters for %s\n", id)
	up, err = api.GetUploadParams(id, req)
	if err != nil {
		return up, err
	}
	SaveToCache(lookId+"_up", c, &up)
	return up, nil
}

func LoadAsset(id string, c common.Cacheable, api synq.ApiV2) (asset synq.Asset, err error) {
	ok := LoadFromCache(id, c, &asset)
	if !ok {
		log.Printf("Getting asset %s\n", id)
		asset, err = api.GetAsset(id)
		if err != nil {
			return asset, err
		}
	}
	asset.Api = api
	video, e2 := LoadVideoV2(asset.VideoId, c, api)
	if e2 != nil {
		return asset, e2
	}
	asset.Video = video
	SaveToCache(id, c, &asset)
	return asset, nil
}
<commit_msg>swap params<commit_after>package helper

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"os"

	"github.com/SYNQfm/SYNQ-Golang/synq"
	"github.com/SYNQfm/SYNQ-Golang/upload"
	"github.com/SYNQfm/helpers/common"
)

func LoadFromCache(name string, c common.Cacheable, obj interface{}) bool {
	cacheFile := c.GetCacheFile(name)
	if cacheFile != "" {
		if _, e := os.Stat(cacheFile); e == nil {
			log.Printf("loading from cached file %s\n", cacheFile)
			bytes, _ := ioutil.ReadFile(cacheFile)
			json.Unmarshal(bytes, obj)
			return true
		}
	}
	return false
}

func SaveToCache(name string, c common.Cacheable, obj interface{}) bool {
	cacheFile := c.GetCacheFile(name)
	if cacheFile != "" {
		data, _ := json.Marshal(obj)
		ioutil.WriteFile(cacheFile, data, 0755)
		return true
	}
	return false
}

func LoadVideosByQuery(query, name string, c common.Cacheable, api synq.Api) (videos []synq.Video, err error) {
	ok := LoadFromCache(name, c, &videos)
	if ok {
		return videos, nil
	}
	log.Printf("querying '%s'\n", query)
	videos, err = api.Query(query)
	if err != nil {
		return videos, err
	}
	SaveToCache(name, c, videos)
	return videos, err
}

// fow now, the query will be the account id
func LoadVideosByQueryV2(query, name string, c common.Cacheable, api synq.ApiV2) (videos []synq.VideoV2, err error) {
	ok := LoadFromCache(name, c, &videos)
	if ok {
		return videos, nil
	}
	log.Printf("get all videos (filter by account '%s')\n", query)
	videos, err = api.GetVideos(query)
	if err != nil {
		return videos, err
	}
	SaveToCache(name, c, videos)
	return videos, err
}

func LoadVideo(id string, c common.Cacheable, api synq.Api) (video synq.Video, err error) {
	ok := LoadFromCache(id, c, &video)
	if ok {
		video.Api = &api
		return video, nil
	}
	// need to use the v1 api to get the raw video data
	log.Printf("Getting video %s", id)
	video, e := api.GetVideo(id)
	if e != nil {
		return video, e
	}
	SaveToCache(id, c, &video)
	return video, nil
}

func LoadVideoV2(id string, c common.Cacheable, api synq.ApiV2) (video synq.VideoV2, err error) {
	ok := LoadFromCache(id, c, &video)
	if ok {
		video.Api = &api
		return video, nil
	}
	log.Printf("Getting video %s\n", id)
	video, err = api.GetVideo(id)
	if err != nil {
		return video, err
	}
	SaveToCache(id, c, &video)
	video.Api = &api
	return video, nil
}

func LoadUploadParameters(id string, req synq.UnicornParam, c common.Cacheable, api synq.ApiV2) (up upload.UploadParameters, err error) {
	lookId := id
	if req.AssetId != "" {
		lookId = req.AssetId
	}
	ok := LoadFromCache(lookId+"_up", c, &up)
	if ok {
		return up, nil
	}
	log.Printf("Getting upload parameters for %s\n", id)
	up, err = api.GetUploadParams(id, req)
	if err != nil {
		return up, err
	}
	SaveToCache(lookId+"_up", c, &up)
	return up, nil
}

func LoadAsset(id string, c common.Cacheable, api synq.ApiV2) (asset synq.Asset, err error) {
	ok := LoadFromCache(id, c, &asset)
	if !ok {
		log.Printf("Getting asset %s\n", id)
		asset, err = api.GetAsset(id)
		if err != nil {
			return asset, err
		}
	}
	asset.Api = api
	video, e2 := LoadVideoV2(asset.VideoId, c, api)
	if e2 != nil {
		return asset, e2
	}
	asset.Video = video
	SaveToCache(id, c, &asset)
	return asset, nil
}
<|endoftext|>


<commit_before>// Copyright (C) 2017 Google 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 vulkan

import (
	"fmt"

	"github.com/google/gapid/gapis/api"
)

func (st *State) getSubmitAttachmentInfo(attachment api.FramebufferAttachment) (w, h uint32, f VkFormat, attachmentIndex uint32, canResize bool, err error) {
	returnError := func(format_str string, e ...interface{}) (w, h uint32, f VkFormat, attachmentIndex uint32, canResize bool, err error) {
		return 0, 0, VkFormat_VK_FORMAT_UNDEFINED, 0, true, fmt.Errorf(format_str, e...)
	}

	lastQueue := st.LastBoundQueue()
	if lastQueue.IsNil() {
		return returnError("No previous queue submission")
	}

	lastDrawInfo, ok := st.LastDrawInfos().Lookup(lastQueue.VulkanHandle())
	if !ok {
		return returnError("There have been no previous draws")
	}

	if lastDrawInfo.Framebuffer().IsNil() || !st.Framebuffers().Contains(lastDrawInfo.Framebuffer().VulkanHandle()) {
		return returnError("%s is not bound", attachment)
	}

	if lastDrawInfo.Framebuffer().RenderPass().IsNil() {
		return returnError("%s is not bound to any renderpass", attachment)
	}

	lastSubpass := lastDrawInfo.LastSubpass()

	subpassDesc := lastDrawInfo.Framebuffer().RenderPass().SubpassDescriptions().Get(lastSubpass)
	switch attachment {
	case api.FramebufferAttachment_Color0,
		api.FramebufferAttachment_Color1,
		api.FramebufferAttachment_Color2,
		api.FramebufferAttachment_Color3:
		attachmentIndex := uint32(attachment - api.FramebufferAttachment_Color0)
		if attRef, ok := subpassDesc.ColorAttachments().Lookup(attachmentIndex); ok {
			if ca, ok := lastDrawInfo.Framebuffer().ImageAttachments().Lookup(attRef.Attachment()); ok {
				return ca.Image().Info().Extent().Width(),
					ca.Image().Info().Extent().Height(),
					ca.Image().Info().Fmt(),
					attRef.Attachment(), true, nil
			}

		}
	case api.FramebufferAttachment_Depth:
		if !subpassDesc.DepthStencilAttachment().IsNil() && !lastDrawInfo.Framebuffer().IsNil() {
			attRef := subpassDesc.DepthStencilAttachment()
			if attachment, ok := lastDrawInfo.Framebuffer().ImageAttachments().Lookup(attRef.Attachment()); ok {
				depthImg := attachment.Image()
				return depthImg.Info().Extent().Width(), depthImg.Info().Extent().Height(), depthImg.Info().Fmt(), attRef.Attachment(), true, nil
			}
		}
	case api.FramebufferAttachment_Stencil:
		fallthrough
	default:
		return returnError("Framebuffer attachment %v currently unsupported", attachment)
	}

	return returnError("%s is not bound", attachment)
}

func (st *State) getPresentAttachmentInfo(attachment api.FramebufferAttachment) (w, h uint32, f VkFormat, attachmentIndex uint32, canResize bool, err error) {
	returnError := func(format_str string, e ...interface{}) (w, h uint32, f VkFormat, attachmentIndex uint32, canResize bool, err error) {
		return 0, 0, VkFormat_VK_FORMAT_UNDEFINED, 0, false, fmt.Errorf(format_str, e...)
	}

	switch attachment {
	case api.FramebufferAttachment_Color0,
		api.FramebufferAttachment_Color1,
		api.FramebufferAttachment_Color2,
		api.FramebufferAttachment_Color3:
		imageIdx := uint32(attachment - api.FramebufferAttachment_Color0)
		if st.LastPresentInfo().PresentImageCount() <= imageIdx {
			return returnError("Swapchain does not contain image %v", attachment)
		}
		colorImg := st.LastPresentInfo().PresentImages().Get(imageIdx)
		if !colorImg.IsNil() {
			queue := st.Queues().Get(st.LastPresentInfo().Queue())
			vkDevice := queue.Device()
			device := st.Devices().Get(vkDevice)
			vkPhysicalDevice := device.PhysicalDevice()
			physicalDevice := st.PhysicalDevices().Get(vkPhysicalDevice)
			if properties, ok := physicalDevice.QueueFamilyProperties().Lookup(queue.Family()); ok {
				if properties.QueueFlags()&VkQueueFlags(VkQueueFlagBits_VK_QUEUE_GRAPHICS_BIT) != 0 {
					return colorImg.Info().Extent().Width(), colorImg.Info().Extent().Height(), colorImg.Info().Fmt(), imageIdx, true, nil
				}
				return colorImg.Info().Extent().Width(), colorImg.Info().Extent().Height(), colorImg.Info().Fmt(), imageIdx, false, nil
			}

			return returnError("Last present queue does not exist", attachment)
		}
	case api.FramebufferAttachment_Depth:
		fallthrough
	case api.FramebufferAttachment_Stencil:
		fallthrough
	default:
		return returnError("Swapchain attachment %v does not exist", attachment)
	}
	return returnError("Swapchain attachment %v does not exist", attachment)
}

func (st *State) getFramebufferAttachmentInfo(attachment api.FramebufferAttachment) (uint32, uint32, VkFormat, uint32, bool, error) {
	if st.LastSubmission() == LastSubmissionType_SUBMIT {
		return st.getSubmitAttachmentInfo(attachment)
	}
	return st.getPresentAttachmentInfo(attachment)
}
<commit_msg>Handle the case where we destroy an ImageView attached to a framebuffer.<commit_after>// Copyright (C) 2017 Google 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 vulkan

import (
	"fmt"

	"github.com/google/gapid/gapis/api"
)

func (st *State) getSubmitAttachmentInfo(attachment api.FramebufferAttachment) (w, h uint32, f VkFormat, attachmentIndex uint32, canResize bool, err error) {
	returnError := func(format_str string, e ...interface{}) (w, h uint32, f VkFormat, attachmentIndex uint32, canResize bool, err error) {
		return 0, 0, VkFormat_VK_FORMAT_UNDEFINED, 0, true, fmt.Errorf(format_str, e...)
	}

	lastQueue := st.LastBoundQueue()
	if lastQueue.IsNil() {
		return returnError("No previous queue submission")
	}

	lastDrawInfo, ok := st.LastDrawInfos().Lookup(lastQueue.VulkanHandle())
	if !ok {
		return returnError("There have been no previous draws")
	}

	if lastDrawInfo.Framebuffer().IsNil() || !st.Framebuffers().Contains(lastDrawInfo.Framebuffer().VulkanHandle()) {
		return returnError("%s is not bound", attachment)
	}

	if lastDrawInfo.Framebuffer().RenderPass().IsNil() {
		return returnError("%s is not bound to any renderpass", attachment)
	}

	lastSubpass := lastDrawInfo.LastSubpass()

	subpassDesc := lastDrawInfo.Framebuffer().RenderPass().SubpassDescriptions().Get(lastSubpass)
	switch attachment {
	case api.FramebufferAttachment_Color0,
		api.FramebufferAttachment_Color1,
		api.FramebufferAttachment_Color2,
		api.FramebufferAttachment_Color3:
		attachmentIndex := uint32(attachment - api.FramebufferAttachment_Color0)
		if attRef, ok := subpassDesc.ColorAttachments().Lookup(attachmentIndex); ok {
			if ca, ok := lastDrawInfo.Framebuffer().ImageAttachments().Lookup(attRef.Attachment()); ok {
				// This can occur if we destroy the image-view, we remove it from the framebuffer,
				// but may not unbind the framebuffer.
				if !ca.Image().IsNil() {
					return ca.Image().Info().Extent().Width(),
						ca.Image().Info().Extent().Height(),
						ca.Image().Info().Fmt(),
						attRef.Attachment(), true, nil
				}
			}
		}
	case api.FramebufferAttachment_Depth:
		if !subpassDesc.DepthStencilAttachment().IsNil() && !lastDrawInfo.Framebuffer().IsNil() {
			attRef := subpassDesc.DepthStencilAttachment()
			if attachment, ok := lastDrawInfo.Framebuffer().ImageAttachments().Lookup(attRef.Attachment()); ok {
				depthImg := attachment.Image()
				// This can occur if we destroy the image-view, we remove it from the framebuffer,
				// but may not unbind the framebuffer.
				if !depthImg.IsNil() {
					return depthImg.Info().Extent().Width(), depthImg.Info().Extent().Height(), depthImg.Info().Fmt(), attRef.Attachment(), true, nil
				}
			}
		}
	case api.FramebufferAttachment_Stencil:
		fallthrough
	default:
		return returnError("Framebuffer attachment %v currently unsupported", attachment)
	}

	return returnError("%s is not bound", attachment)
}

func (st *State) getPresentAttachmentInfo(attachment api.FramebufferAttachment) (w, h uint32, f VkFormat, attachmentIndex uint32, canResize bool, err error) {
	returnError := func(format_str string, e ...interface{}) (w, h uint32, f VkFormat, attachmentIndex uint32, canResize bool, err error) {
		return 0, 0, VkFormat_VK_FORMAT_UNDEFINED, 0, false, fmt.Errorf(format_str, e...)
	}

	switch attachment {
	case api.FramebufferAttachment_Color0,
		api.FramebufferAttachment_Color1,
		api.FramebufferAttachment_Color2,
		api.FramebufferAttachment_Color3:
		imageIdx := uint32(attachment - api.FramebufferAttachment_Color0)
		if st.LastPresentInfo().PresentImageCount() <= imageIdx {
			return returnError("Swapchain does not contain image %v", attachment)
		}
		colorImg := st.LastPresentInfo().PresentImages().Get(imageIdx)
		if !colorImg.IsNil() {
			queue := st.Queues().Get(st.LastPresentInfo().Queue())
			vkDevice := queue.Device()
			device := st.Devices().Get(vkDevice)
			vkPhysicalDevice := device.PhysicalDevice()
			physicalDevice := st.PhysicalDevices().Get(vkPhysicalDevice)
			if properties, ok := physicalDevice.QueueFamilyProperties().Lookup(queue.Family()); ok {
				if properties.QueueFlags()&VkQueueFlags(VkQueueFlagBits_VK_QUEUE_GRAPHICS_BIT) != 0 {
					return colorImg.Info().Extent().Width(), colorImg.Info().Extent().Height(), colorImg.Info().Fmt(), imageIdx, true, nil
				}
				return colorImg.Info().Extent().Width(), colorImg.Info().Extent().Height(), colorImg.Info().Fmt(), imageIdx, false, nil
			}

			return returnError("Last present queue does not exist", attachment)
		}
	case api.FramebufferAttachment_Depth:
		fallthrough
	case api.FramebufferAttachment_Stencil:
		fallthrough
	default:
		return returnError("Swapchain attachment %v does not exist", attachment)
	}
	return returnError("Swapchain attachment %v does not exist", attachment)
}

func (st *State) getFramebufferAttachmentInfo(attachment api.FramebufferAttachment) (uint32, uint32, VkFormat, uint32, bool, error) {
	if st.LastSubmission() == LastSubmissionType_SUBMIT {
		return st.getSubmitAttachmentInfo(attachment)
	}
	return st.getPresentAttachmentInfo(attachment)
}
<|endoftext|>


<commit_before>package mysql

import (
	"database/sql"
	"fmt"

	"gorm.io/gorm"
	"gorm.io/gorm/clause"
	"gorm.io/gorm/migrator"
	"gorm.io/gorm/schema"
)

type Migrator struct {
	migrator.Migrator
	Dialector
}

type Column struct {
	name              string
	nullable          sql.NullString
	datatype          string
	maxLen            sql.NullInt64
	precision         sql.NullInt64
	scale             sql.NullInt64
	datetimePrecision sql.NullInt64
}

func (c Column) Name() string {
	return c.name
}

func (c Column) DatabaseTypeName() string {
	return c.datatype
}

func (c Column) Length() (int64, bool) {
	if c.maxLen.Valid {
		return c.maxLen.Int64, c.maxLen.Valid
	}

	return 0, false
}

func (c Column) Nullable() (bool, bool) {
	if c.nullable.Valid {
		return c.nullable.String == "YES", true
	}

	return false, false
}

// DecimalSize return precision int64, scale int64, ok bool
func (c Column) DecimalSize() (int64, int64, bool) {
	if c.precision.Valid {
		if c.scale.Valid {
			return c.precision.Int64, c.scale.Int64, true
		}

		return c.precision.Int64, 0, true
	}

	if c.datetimePrecision.Valid {
		return c.datetimePrecision.Int64, 0, true
	}

	return 0, 0, false
}

func (m Migrator) FullDataTypeOf(field *schema.Field) clause.Expr {
	expr := m.Migrator.FullDataTypeOf(field)

	if value, ok := field.TagSettings["COMMENT"]; ok {
		expr.SQL += " COMMENT " + m.Dialector.Explain("?", value)
	}

	return expr
}

func (m Migrator) AlterColumn(value interface{}, field string) error {
	return m.RunWithValue(value, func(stmt *gorm.Statement) error {
		if field := stmt.Schema.LookUpField(field); field != nil {
			return m.DB.Exec(
				"ALTER TABLE ? MODIFY COLUMN ? ?",
				clause.Table{Name: stmt.Table}, clause.Column{Name: field.DBName}, m.FullDataTypeOf(field),
			).Error
		}
		return fmt.Errorf("failed to look up field with name: %s", field)
	})
}

func (m Migrator) RenameColumn(value interface{}, oldName, newName string) error {
	return m.RunWithValue(value, func(stmt *gorm.Statement) error {
		if !m.Dialector.DontSupportRenameColumn {
			return m.Migrator.RenameColumn(value, oldName, newName)
		}

		var field *schema.Field
		if f := stmt.Schema.LookUpField(oldName); f != nil {
			oldName = f.DBName
			field = f
		}

		if f := stmt.Schema.LookUpField(newName); f != nil {
			newName = f.DBName
			field = f
		}

		if field != nil {
			return m.DB.Exec(
				"ALTER TABLE ? CHANGE ? ? ?",
				clause.Table{Name: stmt.Table}, clause.Column{Name: oldName},
				clause.Column{Name: newName}, m.FullDataTypeOf(field),
			).Error
		}

		return fmt.Errorf("failed to look up field with name: %s", newName)
	})
}

func (m Migrator) RenameIndex(value interface{}, oldName, newName string) error {
	if !m.Dialector.DontSupportRenameIndex {
		return m.RunWithValue(value, func(stmt *gorm.Statement) error {
			return m.DB.Exec(
				"ALTER TABLE ? RENAME INDEX ? TO ?",
				clause.Table{Name: stmt.Table}, clause.Column{Name: oldName}, clause.Column{Name: newName},
			).Error
		})
	}

	return m.RunWithValue(value, func(stmt *gorm.Statement) error {
		err := m.DropIndex(value, oldName)
		if err != nil {
			return err
		}

		if idx := stmt.Schema.LookIndex(newName); idx == nil {
			if idx = stmt.Schema.LookIndex(oldName); idx != nil {
				opts := m.BuildIndexOptions(idx.Fields, stmt)
				values := []interface{}{clause.Column{Name: newName}, clause.Table{Name: stmt.Table}, opts}

				createIndexSQL := "CREATE "
				if idx.Class != "" {
					createIndexSQL += idx.Class + " "
				}
				createIndexSQL += "INDEX ? ON ??"

				if idx.Type != "" {
					createIndexSQL += " USING " + idx.Type
				}

				return m.DB.Exec(createIndexSQL, values...).Error
			}
		}

		return m.CreateIndex(value, newName)
	})

}

func (m Migrator) DropTable(values ...interface{}) error {
	values = m.ReorderModels(values, false)
	tx := m.DB.Session(&gorm.Session{})
	tx.Exec("SET FOREIGN_KEY_CHECKS = 0;")
	for i := len(values) - 1; i >= 0; i-- {
		if err := m.RunWithValue(values[i], func(stmt *gorm.Statement) error {
			return tx.Exec("DROP TABLE IF EXISTS ? CASCADE", clause.Table{Name: stmt.Table}).Error
		}); err != nil {
			return err
		}
	}
	tx.Exec("SET FOREIGN_KEY_CHECKS = 1;")
	return nil
}

func (m Migrator) DropConstraint(value interface{}, name string) error {
	return m.RunWithValue(value, func(stmt *gorm.Statement) error {
		constraint, chk, table := m.GuessConstraintAndTable(stmt, name)
		if chk != nil {
			return m.DB.Exec("ALTER TABLE ? DROP CHECK ?", clause.Table{Name: stmt.Table}, clause.Column{Name: chk.Name}).Error
		}
		if constraint != nil {
			name = constraint.Name
		}

		return m.DB.Exec(
			"ALTER TABLE ? DROP FOREIGN KEY ?", clause.Table{Name: table}, clause.Column{Name: name},
		).Error
	})
}

// ColumnTypes column types return columnTypes,error
func (m Migrator) ColumnTypes(value interface{}) ([]gorm.ColumnType, error) {
	columnTypes := make([]gorm.ColumnType, 0)
	err := m.RunWithValue(value, func(stmt *gorm.Statement) error {
		var (
			currentDatabase = m.DB.Migrator().CurrentDatabase()
			columnTypeSQL   = "SELECT column_name, is_nullable, data_type, character_maximum_length, numeric_precision, numeric_scale "
		)

		if !m.DisableDatetimePrecision {
			columnTypeSQL += ", datetime_precision "
		}
		columnTypeSQL += "FROM information_schema.columns WHERE table_schema = ? AND table_name = ?"

		columns, rowErr := m.DB.Raw(columnTypeSQL, currentDatabase, stmt.Table).Rows()
		if rowErr != nil {
			return rowErr
		}

		defer columns.Close()

		for columns.Next() {
			var column Column
			var values = []interface{}{&column.name, &column.nullable, &column.datatype,
				&column.maxLen, &column.precision, &column.scale}

			if !m.DisableDatetimePrecision {
				values = append(values, &column.datetimePrecision)
			}

			if scanErr := columns.Scan(values...); scanErr != nil {
				return scanErr
			}
			columnTypes = append(columnTypes, column)
		}

		return nil
	})

	return columnTypes, err
}
<commit_msg>feat: implement CurrentDatabase for mysql (#56)<commit_after>package mysql

import (
	"database/sql"
	"fmt"

	"gorm.io/gorm"
	"gorm.io/gorm/clause"
	"gorm.io/gorm/migrator"
	"gorm.io/gorm/schema"
)

type Migrator struct {
	migrator.Migrator
	Dialector
}

type Column struct {
	name              string
	nullable          sql.NullString
	datatype          string
	maxLen            sql.NullInt64
	precision         sql.NullInt64
	scale             sql.NullInt64
	datetimePrecision sql.NullInt64
}

func (c Column) Name() string {
	return c.name
}

func (c Column) DatabaseTypeName() string {
	return c.datatype
}

func (c Column) Length() (int64, bool) {
	if c.maxLen.Valid {
		return c.maxLen.Int64, c.maxLen.Valid
	}

	return 0, false
}

func (c Column) Nullable() (bool, bool) {
	if c.nullable.Valid {
		return c.nullable.String == "YES", true
	}

	return false, false
}

// DecimalSize return precision int64, scale int64, ok bool
func (c Column) DecimalSize() (int64, int64, bool) {
	if c.precision.Valid {
		if c.scale.Valid {
			return c.precision.Int64, c.scale.Int64, true
		}

		return c.precision.Int64, 0, true
	}

	if c.datetimePrecision.Valid {
		return c.datetimePrecision.Int64, 0, true
	}

	return 0, 0, false
}

func (m Migrator) FullDataTypeOf(field *schema.Field) clause.Expr {
	expr := m.Migrator.FullDataTypeOf(field)

	if value, ok := field.TagSettings["COMMENT"]; ok {
		expr.SQL += " COMMENT " + m.Dialector.Explain("?", value)
	}

	return expr
}

func (m Migrator) AlterColumn(value interface{}, field string) error {
	return m.RunWithValue(value, func(stmt *gorm.Statement) error {
		if field := stmt.Schema.LookUpField(field); field != nil {
			return m.DB.Exec(
				"ALTER TABLE ? MODIFY COLUMN ? ?",
				clause.Table{Name: stmt.Table}, clause.Column{Name: field.DBName}, m.FullDataTypeOf(field),
			).Error
		}
		return fmt.Errorf("failed to look up field with name: %s", field)
	})
}

func (m Migrator) RenameColumn(value interface{}, oldName, newName string) error {
	return m.RunWithValue(value, func(stmt *gorm.Statement) error {
		if !m.Dialector.DontSupportRenameColumn {
			return m.Migrator.RenameColumn(value, oldName, newName)
		}

		var field *schema.Field
		if f := stmt.Schema.LookUpField(oldName); f != nil {
			oldName = f.DBName
			field = f
		}

		if f := stmt.Schema.LookUpField(newName); f != nil {
			newName = f.DBName
			field = f
		}

		if field != nil {
			return m.DB.Exec(
				"ALTER TABLE ? CHANGE ? ? ?",
				clause.Table{Name: stmt.Table}, clause.Column{Name: oldName},
				clause.Column{Name: newName}, m.FullDataTypeOf(field),
			).Error
		}

		return fmt.Errorf("failed to look up field with name: %s", newName)
	})
}

func (m Migrator) RenameIndex(value interface{}, oldName, newName string) error {
	if !m.Dialector.DontSupportRenameIndex {
		return m.RunWithValue(value, func(stmt *gorm.Statement) error {
			return m.DB.Exec(
				"ALTER TABLE ? RENAME INDEX ? TO ?",
				clause.Table{Name: stmt.Table}, clause.Column{Name: oldName}, clause.Column{Name: newName},
			).Error
		})
	}

	return m.RunWithValue(value, func(stmt *gorm.Statement) error {
		err := m.DropIndex(value, oldName)
		if err != nil {
			return err
		}

		if idx := stmt.Schema.LookIndex(newName); idx == nil {
			if idx = stmt.Schema.LookIndex(oldName); idx != nil {
				opts := m.BuildIndexOptions(idx.Fields, stmt)
				values := []interface{}{clause.Column{Name: newName}, clause.Table{Name: stmt.Table}, opts}

				createIndexSQL := "CREATE "
				if idx.Class != "" {
					createIndexSQL += idx.Class + " "
				}
				createIndexSQL += "INDEX ? ON ??"

				if idx.Type != "" {
					createIndexSQL += " USING " + idx.Type
				}

				return m.DB.Exec(createIndexSQL, values...).Error
			}
		}

		return m.CreateIndex(value, newName)
	})

}

func (m Migrator) DropTable(values ...interface{}) error {
	values = m.ReorderModels(values, false)
	tx := m.DB.Session(&gorm.Session{})
	tx.Exec("SET FOREIGN_KEY_CHECKS = 0;")
	for i := len(values) - 1; i >= 0; i-- {
		if err := m.RunWithValue(values[i], func(stmt *gorm.Statement) error {
			return tx.Exec("DROP TABLE IF EXISTS ? CASCADE", clause.Table{Name: stmt.Table}).Error
		}); err != nil {
			return err
		}
	}
	tx.Exec("SET FOREIGN_KEY_CHECKS = 1;")
	return nil
}

func (m Migrator) DropConstraint(value interface{}, name string) error {
	return m.RunWithValue(value, func(stmt *gorm.Statement) error {
		constraint, chk, table := m.GuessConstraintAndTable(stmt, name)
		if chk != nil {
			return m.DB.Exec("ALTER TABLE ? DROP CHECK ?", clause.Table{Name: stmt.Table}, clause.Column{Name: chk.Name}).Error
		}
		if constraint != nil {
			name = constraint.Name
		}

		return m.DB.Exec(
			"ALTER TABLE ? DROP FOREIGN KEY ?", clause.Table{Name: table}, clause.Column{Name: name},
		).Error
	})
}

// ColumnTypes column types return columnTypes,error
func (m Migrator) ColumnTypes(value interface{}) ([]gorm.ColumnType, error) {
	columnTypes := make([]gorm.ColumnType, 0)
	err := m.RunWithValue(value, func(stmt *gorm.Statement) error {
		var (
			currentDatabase = m.DB.Migrator().CurrentDatabase()
			columnTypeSQL   = "SELECT column_name, is_nullable, data_type, character_maximum_length, numeric_precision, numeric_scale "
		)

		if !m.DisableDatetimePrecision {
			columnTypeSQL += ", datetime_precision "
		}
		columnTypeSQL += "FROM information_schema.columns WHERE table_schema = ? AND table_name = ?"

		columns, rowErr := m.DB.Raw(columnTypeSQL, currentDatabase, stmt.Table).Rows()
		if rowErr != nil {
			return rowErr
		}

		defer columns.Close()

		for columns.Next() {
			var column Column
			var values = []interface{}{&column.name, &column.nullable, &column.datatype,
				&column.maxLen, &column.precision, &column.scale}

			if !m.DisableDatetimePrecision {
				values = append(values, &column.datetimePrecision)
			}

			if scanErr := columns.Scan(values...); scanErr != nil {
				return scanErr
			}
			columnTypes = append(columnTypes, column)
		}

		return nil
	})

	return columnTypes, err
}

func (m Migrator) CurrentDatabase() (name string) {
	baseName := m.Migrator.CurrentDatabase()
	m.DB.Raw(
		"SELECT SCHEMA_NAME from Information_schema.SCHEMATA where SCHEMA_NAME LIKE ? ORDER BY SCHEMA_NAME=? DESC limit 1",
		baseName+"%", baseName).Scan(&name)
	return
}
<|endoftext|>


<commit_before>package oak

import (
	"image"
	"image/draw"

	"github.com/oakmound/oak/v2/dlog"
	"github.com/oakmound/oak/v2/render"
	"github.com/oakmound/oak/v2/timing"
	"github.com/oakmound/shiny/screen"
)

var (
	// Background is the uniform color drawn to the screen in between draw frames
	Background = image.Black
	// DrawTicker is the parallel to LogicTicker to set the draw framerate
	DrawTicker *timing.DynamicTicker
)

// DrawLoop
// Unless told to stop, the draw channel will repeatedly
// 1. draw the background color to a temporary buffer
// 2. draw all visible rendered elements onto the temporary buffer.
// 3. draw the buffer's data at the viewport's position to the screen.
// 4. publish the screen to display in window.
func drawLoop() {
	<-drawCh

	tx, err := screenControl.NewTexture(winBuffer.Bounds().Max)
	if err != nil {
		panic(err)
	}

	draw.Draw(winBuffer.RGBA(), winBuffer.Bounds(), Background, zeroPoint, draw.Src)
	drawLoopPublish(tx)

	DrawTicker = timing.NewDynamicTicker()
	DrawTicker.SetTick(timing.FPSToDuration(DrawFrameRate))

	dlog.Verb("Draw Loop Start")
	for {
	drawSelect:
		select {
		case <-windowUpdateCh:
			<-windowUpdateCh
		case <-drawCh:
			dlog.Verb("Got something from draw channel")
			<-drawCh
			dlog.Verb("Starting loading")
			for {
				<-DrawTicker.C
				draw.Draw(winBuffer.RGBA(), winBuffer.Bounds(), Background, zeroPoint, draw.Src)
				if LoadingR != nil {
					LoadingR.Draw(winBuffer.RGBA())
				}
				drawLoopPublish(tx)

				select {
				case <-drawCh:
					break drawSelect
				case viewPoint := <-viewportCh:
					dlog.Verb("Got something from viewport channel (waiting on draw)")
					updateScreen(viewPoint[0], viewPoint[1])
				case viewPoint := <-viewportShiftCh:
					dlog.Verb("Got something from viewport shfit channel (waiting on draw)")
					shiftViewPort(viewPoint[0], viewPoint[1])
				default:
				}
			}
		case viewPoint := <-viewportCh:
			dlog.Verb("Got something from viewport channel")
			updateScreen(viewPoint[0], viewPoint[1])
		case viewPoint := <-viewportShiftCh:
			dlog.Verb("Got something from viewport shift channel")
			shiftViewPort(viewPoint[0], viewPoint[1])
		case <-DrawTicker.C:
			draw.Draw(winBuffer.RGBA(), winBuffer.Bounds(), Background, zeroPoint, draw.Src)
			render.PreDraw()
			render.GlobalDrawStack.Draw(winBuffer.RGBA(), ViewPos, ScreenWidth, ScreenHeight)
			drawLoopPublish(tx)
		}
	}
}

var (
	drawLoopPublishDef = func(tx screen.Texture) {
		tx.Upload(zeroPoint, winBuffer, winBuffer.Bounds())
		windowControl.Scale(windowRect, tx, tx.Bounds(), draw.Src)
		windowControl.Publish()
	}
	drawLoopPublish = drawLoopPublishDef
)
<commit_msg>Update drawLoop.go<commit_after>package oak

import (
	"image"
	"image/draw"

	"github.com/oakmound/oak/v2/dlog"
	"github.com/oakmound/oak/v2/render"
	"github.com/oakmound/oak/v2/timing"
	"github.com/oakmound/shiny/screen"
)

var (
	// Background is the uniform color drawn to the screen in between draw frames
	Background = image.Black
	// DrawTicker is the parallel to LogicTicker to set the draw framerate
	DrawTicker *timing.DynamicTicker
)

// DrawLoop
// Unless told to stop, the draw channel will repeatedly
// 1. draw the background color to a temporary buffer
// 2. draw all visible rendered elements onto the temporary buffer.
// 3. draw the buffer's data at the viewport's position to the screen.
// 4. publish the screen to display in window.
func drawLoop() {
	<-drawCh

	tx, err := screenControl.NewTexture(winBuffer.Bounds().Max)
	if err != nil {
		panic(err)
	}

	draw.Draw(winBuffer.RGBA(), winBuffer.Bounds(), Background, zeroPoint, draw.Src)
	drawLoopPublish(tx)

	DrawTicker = timing.NewDynamicTicker()
	DrawTicker.SetTick(timing.FPSToDuration(DrawFrameRate))

	dlog.Verb("Draw Loop Start")
	for {
	drawSelect:
		select {
		case <-windowUpdateCh:
			<-windowUpdateCh
		case <-drawCh:
			dlog.Verb("Got something from draw channel")
			<-drawCh
			dlog.Verb("Starting loading")
			for {
				<-DrawTicker.C
				draw.Draw(winBuffer.RGBA(), winBuffer.Bounds(), Background, zeroPoint, draw.Src)
				if LoadingR != nil {
					LoadingR.Draw(winBuffer.RGBA())
				}
				drawLoopPublish(tx)

				select {
				case <-drawCh:
					break drawSelect
				case viewPoint := <-viewportCh:
					dlog.Verb("Got something from viewport channel (waiting on draw)")
					updateScreen(viewPoint[0], viewPoint[1])
				case viewPoint := <-viewportShiftCh:
					dlog.Verb("Got something from viewport shift channel (waiting on draw)")
					shiftViewPort(viewPoint[0], viewPoint[1])
				default:
				}
			}
		case viewPoint := <-viewportCh:
			dlog.Verb("Got something from viewport channel")
			updateScreen(viewPoint[0], viewPoint[1])
		case viewPoint := <-viewportShiftCh:
			dlog.Verb("Got something from viewport shift channel")
			shiftViewPort(viewPoint[0], viewPoint[1])
		case <-DrawTicker.C:
			draw.Draw(winBuffer.RGBA(), winBuffer.Bounds(), Background, zeroPoint, draw.Src)
			render.PreDraw()
			render.GlobalDrawStack.Draw(winBuffer.RGBA(), ViewPos, ScreenWidth, ScreenHeight)
			drawLoopPublish(tx)
		}
	}
}

var (
	drawLoopPublishDef = func(tx screen.Texture) {
		tx.Upload(zeroPoint, winBuffer, winBuffer.Bounds())
		windowControl.Scale(windowRect, tx, tx.Bounds(), draw.Src)
		windowControl.Publish()
	}
	drawLoopPublish = drawLoopPublishDef
)
<|endoftext|>


<commit_before>package tview

import (
	"strings"

	"github.com/gdamore/tcell"
	runewidth "github.com/mattn/go-runewidth"
)

// dropDownOption is one option that can be selected in a drop-down primitive.
type dropDownOption struct {
	Text     string // The text to be displayed in the drop-down.
	Selected func() // The (optional) callback for when this option was selected.
}

// DropDown implements a selection widget whose options become visible in a
// drop-down list when activated.
//
// See https://github.com/rivo/tview/wiki/DropDown for an example.
type DropDown struct {
	*Box

	// The options from which the user can choose.
	options []*dropDownOption

	// The index of the currently selected option. Negative if no option is
	// currently selected.
	currentOption int

	// Set to true if the options are visible and selectable.
	open bool

	// The runes typed so far to directly access one of the list items.
	prefix string

	// The list element for the options.
	list *List

	// The text to be displayed before the input area.
	label string

	// The label color.
	labelColor tcell.Color

	// The background color of the input area.
	fieldBackgroundColor tcell.Color

	// The text color of the input area.
	fieldTextColor tcell.Color

	// The color for prefixes.
	prefixTextColor tcell.Color

	// The screen width of the label area. A value of 0 means use the width of
	// the label text.
	labelWidth int

	// The screen width of the input area. A value of 0 means extend as much as
	// possible.
	fieldWidth int

	// An optional function which is called when the user indicated that they
	// are done selecting options. The key which was pressed is provided (tab,
	// shift-tab, or escape).
	done func(tcell.Key)

	// A callback function set by the Form class and called when the user leaves
	// this form item.
	finished func(tcell.Key)
}

// NewDropDown returns a new drop-down.
func NewDropDown() *DropDown {
	list := NewList().ShowSecondaryText(false)
	list.SetMainTextColor(Styles.PrimitiveBackgroundColor).
		SetSelectedTextColor(Styles.PrimitiveBackgroundColor).
		SetSelectedBackgroundColor(Styles.PrimaryTextColor).
		SetBackgroundColor(Styles.MoreContrastBackgroundColor)

	d := &DropDown{
		Box:                  NewBox(),
		currentOption:        -1,
		list:                 list,
		labelColor:           Styles.SecondaryTextColor,
		fieldBackgroundColor: Styles.ContrastBackgroundColor,
		fieldTextColor:       Styles.PrimaryTextColor,
		prefixTextColor:      Styles.ContrastSecondaryTextColor,
	}

	d.focus = d

	return d
}

// SetCurrentOption sets the index of the currently selected option. This may
// be a negative value to indicate that no option is currently selected.
func (d *DropDown) SetCurrentOption(index int) *DropDown {
	d.currentOption = index
	d.list.SetCurrentItem(index)
	return d
}

// GetCurrentOption returns the index of the currently selected option as well
// as its text. If no option was selected, -1 and an empty string is returned.
func (d *DropDown) GetCurrentOption() (int, string) {
	var text string
	if d.currentOption >= 0 && d.currentOption < len(d.options) {
		text = d.options[d.currentOption].Text
	}
	return d.currentOption, text
}

// SetLabel sets the text to be displayed before the input area.
func (d *DropDown) SetLabel(label string) *DropDown {
	d.label = label
	return d
}

// GetLabel returns the text to be displayed before the input area.
func (d *DropDown) GetLabel() string {
	return d.label
}

// SetLabelWidth sets the screen width of the label. A value of 0 will cause the
// primitive to use the width of the label string.
func (d *DropDown) SetLabelWidth(width int) *DropDown {
	d.labelWidth = width
	return d
}

// SetLabelColor sets the color of the label.
func (d *DropDown) SetLabelColor(color tcell.Color) *DropDown {
	d.labelColor = color
	return d
}

// SetFieldBackgroundColor sets the background color of the options area.
func (d *DropDown) SetFieldBackgroundColor(color tcell.Color) *DropDown {
	d.fieldBackgroundColor = color
	return d
}

// SetFieldTextColor sets the text color of the options area.
func (d *DropDown) SetFieldTextColor(color tcell.Color) *DropDown {
	d.fieldTextColor = color
	return d
}

// SetPrefixTextColor sets the color of the prefix string. The prefix string is
// shown when the user starts typing text, which directly selects the first
// option that starts with the typed string.
func (d *DropDown) SetPrefixTextColor(color tcell.Color) *DropDown {
	d.prefixTextColor = color
	return d
}

// SetFormAttributes sets attributes shared by all form items.
func (d *DropDown) SetFormAttributes(labelWidth int, labelColor, bgColor, fieldTextColor, fieldBgColor tcell.Color) FormItem {
	d.labelWidth = labelWidth
	d.labelColor = labelColor
	d.backgroundColor = bgColor
	d.fieldTextColor = fieldTextColor
	d.fieldBackgroundColor = fieldBgColor
	return d
}

// SetFieldWidth sets the screen width of the options area. A value of 0 means
// extend to as long as the longest option text.
func (d *DropDown) SetFieldWidth(width int) *DropDown {
	d.fieldWidth = width
	return d
}

// GetFieldWidth returns this primitive's field screen width.
func (d *DropDown) GetFieldWidth() int {
	if d.fieldWidth > 0 {
		return d.fieldWidth
	}
	fieldWidth := 0
	for _, option := range d.options {
		width := StringWidth(option.Text)
		if width > fieldWidth {
			fieldWidth = width
		}
	}
	return fieldWidth
}

// AddOption adds a new selectable option to this drop-down. The "selected"
// callback is called when this option was selected. It may be nil.
func (d *DropDown) AddOption(text string, selected func()) *DropDown {
	d.options = append(d.options, &dropDownOption{Text: text, Selected: selected})
	d.list.AddItem(text, "", 0, nil)
	return d
}

// SetOptions replaces all current options with the ones provided and installs
// one callback function which is called when one of the options is selected.
// It will be called with the option's text and its index into the options
// slice. The "selected" parameter may be nil.
func (d *DropDown) SetOptions(texts []string, selected func(text string, index int)) *DropDown {
	d.list.Clear()
	d.options = nil
	for index, text := range texts {
		func(t string, i int) {
			d.AddOption(text, func() {
				if selected != nil {
					selected(t, i)
				}
			})
		}(text, index)
	}
	return d
}

// SetDoneFunc sets a handler which is called when the user is done selecting
// options. The callback function is provided with the key that was pressed,
// which is one of the following:
//
//   - KeyEscape: Abort selection.
//   - KeyTab: Move to the next field.
//   - KeyBacktab: Move to the previous field.
func (d *DropDown) SetDoneFunc(handler func(key tcell.Key)) *DropDown {
	d.done = handler
	return d
}

// SetFinishedFunc sets a callback invoked when the user leaves this form item.
func (d *DropDown) SetFinishedFunc(handler func(key tcell.Key)) FormItem {
	d.finished = handler
	return d
}

// Draw draws this primitive onto the screen.
func (d *DropDown) Draw(screen tcell.Screen) {
	d.Box.Draw(screen)

	// Prepare.
	x, y, width, height := d.GetInnerRect()
	rightLimit := x + width
	if height < 1 || rightLimit <= x {
		return
	}

	// Draw label.
	if d.labelWidth > 0 {
		labelWidth := d.labelWidth
		if labelWidth > rightLimit-x {
			labelWidth = rightLimit - x
		}
		Print(screen, d.label, x, y, labelWidth, AlignLeft, d.labelColor)
		x += labelWidth
	} else {
		_, drawnWidth := Print(screen, d.label, x, y, rightLimit-x, AlignLeft, d.labelColor)
		x += drawnWidth
	}

	// What's the longest option text?
	maxWidth := 0
	for _, option := range d.options {
		strWidth := StringWidth(option.Text)
		if strWidth > maxWidth {
			maxWidth = strWidth
		}
	}

	// Draw selection area.
	fieldWidth := d.fieldWidth
	if fieldWidth == 0 {
		fieldWidth = maxWidth
	}
	if rightLimit-x < fieldWidth {
		fieldWidth = rightLimit - x
	}
	fieldStyle := tcell.StyleDefault.Background(d.fieldBackgroundColor)
	if d.GetFocusable().HasFocus() && !d.open {
		fieldStyle = fieldStyle.Background(d.fieldTextColor)
	}
	for index := 0; index < fieldWidth; index++ {
		screen.SetContent(x+index, y, ' ', nil, fieldStyle)
	}

	// Draw selected text.
	if d.open && len(d.prefix) > 0 {
		// Show the prefix.
		Print(screen, d.prefix, x, y, fieldWidth, AlignLeft, d.prefixTextColor)
		prefixWidth := runewidth.StringWidth(d.prefix)
		listItemText := d.options[d.list.GetCurrentItem()].Text
		if prefixWidth < fieldWidth && len(d.prefix) < len(listItemText) {
			Print(screen, listItemText[len(d.prefix):], x+prefixWidth, y, fieldWidth-prefixWidth, AlignLeft, d.fieldTextColor)
		}
	} else {
		if d.currentOption >= 0 && d.currentOption < len(d.options) {
			color := d.fieldTextColor
			// Just show the current selection.
			if d.GetFocusable().HasFocus() && !d.open {
				color = d.fieldBackgroundColor
			}
			Print(screen, d.options[d.currentOption].Text, x, y, fieldWidth, AlignLeft, color)
		}
	}

	// Draw options list.
	if d.HasFocus() && d.open {
		// We prefer to drop down but if there is no space, maybe drop up?
		lx := x
		ly := y + 1
		lwidth := maxWidth
		lheight := len(d.options)
		_, sheight := screen.Size()
		if ly+lheight >= sheight && ly-2 > lheight-ly {
			ly = y - lheight
			if ly < 0 {
				ly = 0
			}
		}
		if ly+lheight >= sheight {
			lheight = sheight - ly
		}
		d.list.SetRect(lx, ly, lwidth, lheight)
		d.list.Draw(screen)
	}
}

// InputHandler returns the handler for this primitive.
func (d *DropDown) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
	return d.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) {
		// A helper function which selects an item in the drop-down list based on
		// the current prefix.
		evalPrefix := func() {
			if len(d.prefix) > 0 {
				for index, option := range d.options {
					if strings.HasPrefix(strings.ToLower(option.Text), d.prefix) {
						d.list.SetCurrentItem(index)
						return
					}
				}
				// Prefix does not match any item. Remove last rune.
				r := []rune(d.prefix)
				d.prefix = string(r[:len(r)-1])
			}
		}

		// Process key event.
		switch key := event.Key(); key {
		case tcell.KeyEnter, tcell.KeyRune, tcell.KeyDown:
			d.prefix = ""

			// If the first key was a letter already, it becomes part of the prefix.
			if r := event.Rune(); key == tcell.KeyRune && r != ' ' {
				d.prefix += string(r)
				evalPrefix()
			}

			// Hand control over to the list.
			d.open = true
			d.list.SetSelectedFunc(func(index int, mainText, secondaryText string, shortcut rune) {
				// An option was selected. Close the list again.
				d.open = false
				setFocus(d)
				d.currentOption = index

				// Trigger "selected" event.
				if d.options[d.currentOption].Selected != nil {
					d.options[d.currentOption].Selected()
				}
			}).SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
				if event.Key() == tcell.KeyRune {
					d.prefix += string(event.Rune())
					evalPrefix()
				} else if event.Key() == tcell.KeyBackspace || event.Key() == tcell.KeyBackspace2 {
					if len(d.prefix) > 0 {
						r := []rune(d.prefix)
						d.prefix = string(r[:len(r)-1])
					}
					evalPrefix()
				} else {
					d.prefix = ""
				}
				return event
			})
			setFocus(d.list)
		case tcell.KeyEscape, tcell.KeyTab, tcell.KeyBacktab:
			if d.done != nil {
				d.done(key)
			}
			if d.finished != nil {
				d.finished(key)
			}
		}
	})
}

// Focus is called by the application when the primitive receives focus.
func (d *DropDown) Focus(delegate func(p Primitive)) {
	d.Box.Focus(delegate)
	if d.open {
		delegate(d.list)
	}
}

// HasFocus returns whether or not this primitive has focus.
func (d *DropDown) HasFocus() bool {
	if d.open {
		return d.list.HasFocus()
	}
	return d.hasFocus
}
<commit_msg>Hitting Escape on a drop-down selection resets it.<commit_after>package tview

import (
	"strings"

	"github.com/gdamore/tcell"
	runewidth "github.com/mattn/go-runewidth"
)

// dropDownOption is one option that can be selected in a drop-down primitive.
type dropDownOption struct {
	Text     string // The text to be displayed in the drop-down.
	Selected func() // The (optional) callback for when this option was selected.
}

// DropDown implements a selection widget whose options become visible in a
// drop-down list when activated.
//
// See https://github.com/rivo/tview/wiki/DropDown for an example.
type DropDown struct {
	*Box

	// The options from which the user can choose.
	options []*dropDownOption

	// The index of the currently selected option. Negative if no option is
	// currently selected.
	currentOption int

	// Set to true if the options are visible and selectable.
	open bool

	// The runes typed so far to directly access one of the list items.
	prefix string

	// The list element for the options.
	list *List

	// The text to be displayed before the input area.
	label string

	// The label color.
	labelColor tcell.Color

	// The background color of the input area.
	fieldBackgroundColor tcell.Color

	// The text color of the input area.
	fieldTextColor tcell.Color

	// The color for prefixes.
	prefixTextColor tcell.Color

	// The screen width of the label area. A value of 0 means use the width of
	// the label text.
	labelWidth int

	// The screen width of the input area. A value of 0 means extend as much as
	// possible.
	fieldWidth int

	// An optional function which is called when the user indicated that they
	// are done selecting options. The key which was pressed is provided (tab,
	// shift-tab, or escape).
	done func(tcell.Key)

	// A callback function set by the Form class and called when the user leaves
	// this form item.
	finished func(tcell.Key)
}

// NewDropDown returns a new drop-down.
func NewDropDown() *DropDown {
	list := NewList().ShowSecondaryText(false)
	list.SetMainTextColor(Styles.PrimitiveBackgroundColor).
		SetSelectedTextColor(Styles.PrimitiveBackgroundColor).
		SetSelectedBackgroundColor(Styles.PrimaryTextColor).
		SetBackgroundColor(Styles.MoreContrastBackgroundColor)

	d := &DropDown{
		Box:                  NewBox(),
		currentOption:        -1,
		list:                 list,
		labelColor:           Styles.SecondaryTextColor,
		fieldBackgroundColor: Styles.ContrastBackgroundColor,
		fieldTextColor:       Styles.PrimaryTextColor,
		prefixTextColor:      Styles.ContrastSecondaryTextColor,
	}

	d.focus = d

	return d
}

// SetCurrentOption sets the index of the currently selected option. This may
// be a negative value to indicate that no option is currently selected.
func (d *DropDown) SetCurrentOption(index int) *DropDown {
	d.currentOption = index
	d.list.SetCurrentItem(index)
	return d
}

// GetCurrentOption returns the index of the currently selected option as well
// as its text. If no option was selected, -1 and an empty string is returned.
func (d *DropDown) GetCurrentOption() (int, string) {
	var text string
	if d.currentOption >= 0 && d.currentOption < len(d.options) {
		text = d.options[d.currentOption].Text
	}
	return d.currentOption, text
}

// SetLabel sets the text to be displayed before the input area.
func (d *DropDown) SetLabel(label string) *DropDown {
	d.label = label
	return d
}

// GetLabel returns the text to be displayed before the input area.
func (d *DropDown) GetLabel() string {
	return d.label
}

// SetLabelWidth sets the screen width of the label. A value of 0 will cause the
// primitive to use the width of the label string.
func (d *DropDown) SetLabelWidth(width int) *DropDown {
	d.labelWidth = width
	return d
}

// SetLabelColor sets the color of the label.
func (d *DropDown) SetLabelColor(color tcell.Color) *DropDown {
	d.labelColor = color
	return d
}

// SetFieldBackgroundColor sets the background color of the options area.
func (d *DropDown) SetFieldBackgroundColor(color tcell.Color) *DropDown {
	d.fieldBackgroundColor = color
	return d
}

// SetFieldTextColor sets the text color of the options area.
func (d *DropDown) SetFieldTextColor(color tcell.Color) *DropDown {
	d.fieldTextColor = color
	return d
}

// SetPrefixTextColor sets the color of the prefix string. The prefix string is
// shown when the user starts typing text, which directly selects the first
// option that starts with the typed string.
func (d *DropDown) SetPrefixTextColor(color tcell.Color) *DropDown {
	d.prefixTextColor = color
	return d
}

// SetFormAttributes sets attributes shared by all form items.
func (d *DropDown) SetFormAttributes(labelWidth int, labelColor, bgColor, fieldTextColor, fieldBgColor tcell.Color) FormItem {
	d.labelWidth = labelWidth
	d.labelColor = labelColor
	d.backgroundColor = bgColor
	d.fieldTextColor = fieldTextColor
	d.fieldBackgroundColor = fieldBgColor
	return d
}

// SetFieldWidth sets the screen width of the options area. A value of 0 means
// extend to as long as the longest option text.
func (d *DropDown) SetFieldWidth(width int) *DropDown {
	d.fieldWidth = width
	return d
}

// GetFieldWidth returns this primitive's field screen width.
func (d *DropDown) GetFieldWidth() int {
	if d.fieldWidth > 0 {
		return d.fieldWidth
	}
	fieldWidth := 0
	for _, option := range d.options {
		width := StringWidth(option.Text)
		if width > fieldWidth {
			fieldWidth = width
		}
	}
	return fieldWidth
}

// AddOption adds a new selectable option to this drop-down. The "selected"
// callback is called when this option was selected. It may be nil.
func (d *DropDown) AddOption(text string, selected func()) *DropDown {
	d.options = append(d.options, &dropDownOption{Text: text, Selected: selected})
	d.list.AddItem(text, "", 0, nil)
	return d
}

// SetOptions replaces all current options with the ones provided and installs
// one callback function which is called when one of the options is selected.
// It will be called with the option's text and its index into the options
// slice. The "selected" parameter may be nil.
func (d *DropDown) SetOptions(texts []string, selected func(text string, index int)) *DropDown {
	d.list.Clear()
	d.options = nil
	for index, text := range texts {
		func(t string, i int) {
			d.AddOption(text, func() {
				if selected != nil {
					selected(t, i)
				}
			})
		}(text, index)
	}
	return d
}

// SetDoneFunc sets a handler which is called when the user is done selecting
// options. The callback function is provided with the key that was pressed,
// which is one of the following:
//
//   - KeyEscape: Abort selection.
//   - KeyTab: Move to the next field.
//   - KeyBacktab: Move to the previous field.
func (d *DropDown) SetDoneFunc(handler func(key tcell.Key)) *DropDown {
	d.done = handler
	return d
}

// SetFinishedFunc sets a callback invoked when the user leaves this form item.
func (d *DropDown) SetFinishedFunc(handler func(key tcell.Key)) FormItem {
	d.finished = handler
	return d
}

// Draw draws this primitive onto the screen.
func (d *DropDown) Draw(screen tcell.Screen) {
	d.Box.Draw(screen)

	// Prepare.
	x, y, width, height := d.GetInnerRect()
	rightLimit := x + width
	if height < 1 || rightLimit <= x {
		return
	}

	// Draw label.
	if d.labelWidth > 0 {
		labelWidth := d.labelWidth
		if labelWidth > rightLimit-x {
			labelWidth = rightLimit - x
		}
		Print(screen, d.label, x, y, labelWidth, AlignLeft, d.labelColor)
		x += labelWidth
	} else {
		_, drawnWidth := Print(screen, d.label, x, y, rightLimit-x, AlignLeft, d.labelColor)
		x += drawnWidth
	}

	// What's the longest option text?
	maxWidth := 0
	for _, option := range d.options {
		strWidth := StringWidth(option.Text)
		if strWidth > maxWidth {
			maxWidth = strWidth
		}
	}

	// Draw selection area.
	fieldWidth := d.fieldWidth
	if fieldWidth == 0 {
		fieldWidth = maxWidth
	}
	if rightLimit-x < fieldWidth {
		fieldWidth = rightLimit - x
	}
	fieldStyle := tcell.StyleDefault.Background(d.fieldBackgroundColor)
	if d.GetFocusable().HasFocus() && !d.open {
		fieldStyle = fieldStyle.Background(d.fieldTextColor)
	}
	for index := 0; index < fieldWidth; index++ {
		screen.SetContent(x+index, y, ' ', nil, fieldStyle)
	}

	// Draw selected text.
	if d.open && len(d.prefix) > 0 {
		// Show the prefix.
		Print(screen, d.prefix, x, y, fieldWidth, AlignLeft, d.prefixTextColor)
		prefixWidth := runewidth.StringWidth(d.prefix)
		listItemText := d.options[d.list.GetCurrentItem()].Text
		if prefixWidth < fieldWidth && len(d.prefix) < len(listItemText) {
			Print(screen, listItemText[len(d.prefix):], x+prefixWidth, y, fieldWidth-prefixWidth, AlignLeft, d.fieldTextColor)
		}
	} else {
		if d.currentOption >= 0 && d.currentOption < len(d.options) {
			color := d.fieldTextColor
			// Just show the current selection.
			if d.GetFocusable().HasFocus() && !d.open {
				color = d.fieldBackgroundColor
			}
			Print(screen, d.options[d.currentOption].Text, x, y, fieldWidth, AlignLeft, color)
		}
	}

	// Draw options list.
	if d.HasFocus() && d.open {
		// We prefer to drop down but if there is no space, maybe drop up?
		lx := x
		ly := y + 1
		lwidth := maxWidth
		lheight := len(d.options)
		_, sheight := screen.Size()
		if ly+lheight >= sheight && ly-2 > lheight-ly {
			ly = y - lheight
			if ly < 0 {
				ly = 0
			}
		}
		if ly+lheight >= sheight {
			lheight = sheight - ly
		}
		d.list.SetRect(lx, ly, lwidth, lheight)
		d.list.Draw(screen)
	}
}

// InputHandler returns the handler for this primitive.
func (d *DropDown) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
	return d.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) {
		// A helper function which selects an item in the drop-down list based on
		// the current prefix.
		evalPrefix := func() {
			if len(d.prefix) > 0 {
				for index, option := range d.options {
					if strings.HasPrefix(strings.ToLower(option.Text), d.prefix) {
						d.list.SetCurrentItem(index)
						return
					}
				}
				// Prefix does not match any item. Remove last rune.
				r := []rune(d.prefix)
				d.prefix = string(r[:len(r)-1])
			}
		}

		// Process key event.
		switch key := event.Key(); key {
		case tcell.KeyEnter, tcell.KeyRune, tcell.KeyDown:
			d.prefix = ""

			// If the first key was a letter already, it becomes part of the prefix.
			if r := event.Rune(); key == tcell.KeyRune && r != ' ' {
				d.prefix += string(r)
				evalPrefix()
			}

			// Hand control over to the list.
			d.open = true
			optionBefore := d.currentOption
			d.list.SetSelectedFunc(func(index int, mainText, secondaryText string, shortcut rune) {
				// An option was selected. Close the list again.
				d.open = false
				setFocus(d)
				d.currentOption = index

				// Trigger "selected" event.
				if d.options[d.currentOption].Selected != nil {
					d.options[d.currentOption].Selected()
				}
			}).SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
				if event.Key() == tcell.KeyRune {
					d.prefix += string(event.Rune())
					evalPrefix()
				} else if event.Key() == tcell.KeyBackspace || event.Key() == tcell.KeyBackspace2 {
					if len(d.prefix) > 0 {
						r := []rune(d.prefix)
						d.prefix = string(r[:len(r)-1])
					}
					evalPrefix()
				} else if event.Key() == tcell.KeyEscape {
					d.open = false
					d.currentOption = optionBefore
					setFocus(d)
				} else {
					d.prefix = ""
				}
				return event
			})
			setFocus(d.list)
		case tcell.KeyEscape, tcell.KeyTab, tcell.KeyBacktab:
			if d.done != nil {
				d.done(key)
			}
			if d.finished != nil {
				d.finished(key)
			}
		}
	})
}

// Focus is called by the application when the primitive receives focus.
func (d *DropDown) Focus(delegate func(p Primitive)) {
	d.Box.Focus(delegate)
	if d.open {
		delegate(d.list)
	}
}

// HasFocus returns whether or not this primitive has focus.
func (d *DropDown) HasFocus() bool {
	if d.open {
		return d.list.HasFocus()
	}
	return d.hasFocus
}
<|endoftext|>


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

// Objwriter reads an object file description in an unspecified format
// and writes a Go object file. It is invoked by parts of the toolchain
// that have not yet been converted from C to Go and should not be
// used otherwise.
package main

import "cmd/internal/obj"
import (
	"cmd/internal/obj/x86"
)

// TODO(rsc): Implement.
// For now we just check that the objwriter binary is available to be run.

func main() {
	_ = obj.Exported
	_ = x86.Exported
}
<commit_msg>[dev.cc] cmd/objwriter: implement using cmd/internal/obj<commit_after>// Copyright 2015 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Objwriter reads an object file description in an unspecified format
// and writes a Go object file. It is invoked by parts of the toolchain
// that have not yet been converted from C to Go and should not be
// used otherwise.
package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"math"
	"os"
	"runtime/pprof"
	"strconv"
	"strings"

	"cmd/internal/obj"
	"cmd/internal/obj/arm"
	"cmd/internal/obj/i386"
	"cmd/internal/obj/ppc64"
	"cmd/internal/obj/x86"
)

var arch *obj.LinkArch
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to this file")
var memprofile = flag.String("memprofile", "", "write memory profile to this file")

func main() {
	log.SetPrefix("goobj: ")
	log.SetFlags(0)
	flag.Parse()

	if flag.NArg() == 1 && flag.Arg(0) == "ping" {
		// old invocation from liblink, just testing that objwriter exists
		return
	}

	if flag.NArg() != 4 {
		fmt.Fprintf(os.Stderr, "usage: goobj infile objfile offset goarch\n")
		os.Exit(2)
	}

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}
	if *memprofile != "" {
		f, err := os.Create(*memprofile)
		if err != nil {
			log.Fatal(err)
		}
		defer pprof.WriteHeapProfile(f)
	}

	switch flag.Arg(3) {
	case "amd64":
		arch = &x86.Linkamd64
	case "amd64p32":
		arch = &x86.Linkamd64p32
	case "386":
		// TODO(rsc): Move Link386 to package x86.
		arch = &i386.Link386
	case "arm":
		arch = &arm.Linkarm
	case "ppc64":
		arch = &ppc64.Linkppc64
	case "ppc64le":
		arch = &ppc64.Linkppc64le
	}

	input()
}

const (
	// must match liblink/objfilego.c
	TypeEnd = iota
	TypeCtxt
	TypePlist
	TypeSym
	TypeProg
	TypeAddr
	TypeHist
)

var (
	ctxt   *obj.Link
	plists = map[int64]*obj.Plist{}
	syms   = map[int64]*obj.LSym{}
	progs  = map[int64]*obj.Prog{}
	hists  = map[int64]*obj.Hist{}
	undef  = map[interface{}]bool{}
)

func input() {
	args := flag.Args()
	ctxt = obj.Linknew(arch)
	ctxt.Debugasm = 1
	ctxt.Bso = obj.Binitw(os.Stdout)
	defer obj.Bflush(ctxt.Bso)
	ctxt.Diag = log.Fatalf
	f, err := os.Open(args[0])
	if err != nil {
		log.Fatal(err)
	}

	b := bufio.NewReaderSize(f, 1<<20)
	if v := rdint(b); v != TypeCtxt {
		log.Fatalf("invalid input - missing ctxt - got %d", v)
	}
	name := rdstring(b)
	if name != ctxt.Arch.Name {
		log.Fatalf("bad arch %s - want %s", name, ctxt.Arch.Name)
	}

	ctxt.Goarm = int32(rdint(b))
	ctxt.Debugasm = int32(rdint(b))
	ctxt.Trimpath = rdstring(b)
	ctxt.Plist = rdplist(b)
	ctxt.Plast = rdplist(b)
	ctxt.Hist = rdhist(b)
	ctxt.Ehist = rdhist(b)
	for {
		i := rdint(b)
		if i < 0 {
			break
		}
		ctxt.Hash[i] = rdsym(b)
	}
	last := int64(TypeCtxt)

Loop:
	for {
		t := rdint(b)
		switch t {
		default:
			log.Fatalf("unexpected input after type %d: %v", last, t)
		case TypeEnd:
			break Loop
		case TypePlist:
			readplist(b, rdplist(b))
		case TypeSym:
			readsym(b, rdsym(b))
		case TypeProg:
			readprog(b, rdprog(b))
		case TypeHist:
			readhist(b, rdhist(b))
		}
		last = t
	}

	if len(undef) > 0 {
		panic("missing definitions")
	}

	var buf bytes.Buffer
	obuf := obj.Binitw(&buf)
	obj.Writeobjdirect(ctxt, obuf)
	obj.Bflush(obuf)

	data, err := ioutil.ReadFile(args[1])
	if err != nil {
		log.Fatal(err)
	}

	offset, err := strconv.Atoi(args[2])
	if err != nil {
		log.Fatalf("bad offset: %v", err)
	}
	if offset > len(data) {
		log.Fatalf("offset too large: %v > %v", offset, len(data))
	}

	old := data[offset:]
	if len(old) > 0 && !bytes.Equal(old, buf.Bytes()) {
		out := strings.TrimSuffix(args[0], ".in") + ".out"
		if err := ioutil.WriteFile(out, append(data[:offset:offset], buf.Bytes()...), 0666); err != nil {
			log.Fatal(err)
		}
		log.Fatalf("goobj produced different output:\n\toriginal: %s\n\tgoobj: %s", args[1], out)
	}

	if len(old) == 0 {
		data = append(data, buf.Bytes()...)
		if err := ioutil.WriteFile(args[1], data, 0666); err != nil {
			log.Fatal(err)
		}
	}
}

func rdstring(b *bufio.Reader) string {
	v := rdint(b)
	buf := make([]byte, v)
	io.ReadFull(b, buf)
	return string(buf)
}

func rdint(b *bufio.Reader) int64 {
	var v uint64
	shift := uint(0)
	for {
		b, err := b.ReadByte()
		if err != nil {
			log.Fatal(err)
		}
		v |= uint64(b&0x7F) << shift
		shift += 7
		if b&0x80 == 0 {
			break
		}
	}
	return int64(v>>1) ^ int64(v<<63)>>63
}

func rdplist(b *bufio.Reader) *obj.Plist {
	id := rdint(b)
	if id == 0 {
		return nil
	}
	pl := plists[id]
	if pl == nil {
		pl = new(obj.Plist)
		plists[id] = pl
		undef[pl] = true
	}
	return pl
}

func rdsym(b *bufio.Reader) *obj.LSym {
	id := rdint(b)
	if id == 0 {
		return nil
	}
	sym := syms[id]
	if sym == nil {
		sym = new(obj.LSym)
		syms[id] = sym
		undef[sym] = true
	}
	return sym
}

func rdprog(b *bufio.Reader) *obj.Prog {
	id := rdint(b)
	if id == 0 {
		return nil
	}
	prog := progs[id]
	if prog == nil {
		prog = new(obj.Prog)
		prog.Ctxt = ctxt
		progs[id] = prog
		undef[prog] = true
	}
	return prog
}

func rdhist(b *bufio.Reader) *obj.Hist {
	id := rdint(b)
	if id == 0 {
		return nil
	}
	h := hists[id]
	if h == nil {
		h = new(obj.Hist)
		hists[id] = h
		undef[h] = true
	}
	return h
}

func readplist(b *bufio.Reader, pl *obj.Plist) {
	if !undef[pl] {
		panic("double-def")
	}
	delete(undef, pl)
	pl.Recur = int(rdint(b))
	pl.Name = rdsym(b)
	pl.Firstpc = rdprog(b)
	pl.Link = rdplist(b)
}

func readsym(b *bufio.Reader, s *obj.LSym) {
	if !undef[s] {
		panic("double-def")
	}
	delete(undef, s)
	s.Name = rdstring(b)
	s.Extname = rdstring(b)
	s.Type_ = int16(rdint(b))
	s.Version = int16(rdint(b))
	s.Dupok = uint8(rdint(b))
	s.External = uint8(rdint(b))
	s.Nosplit = uint8(rdint(b))
	s.Reachable = uint8(rdint(b))
	s.Cgoexport = uint8(rdint(b))
	s.Special = uint8(rdint(b))
	s.Stkcheck = uint8(rdint(b))
	s.Hide = uint8(rdint(b))
	s.Leaf = uint8(rdint(b))
	s.Fnptr = uint8(rdint(b))
	s.Seenglobl = uint8(rdint(b))
	s.Onlist = uint8(rdint(b))
	s.Symid = int16(rdint(b))
	s.Dynid = int32(rdint(b))
	s.Sig = int32(rdint(b))
	s.Plt = int32(rdint(b))
	s.Got = int32(rdint(b))
	s.Align = int32(rdint(b))
	s.Elfsym = int32(rdint(b))
	s.Args = int32(rdint(b))
	s.Locals = int32(rdint(b))
	s.Value = rdint(b)
	s.Size = rdint(b)
	s.Hash = rdsym(b)
	s.Allsym = rdsym(b)
	s.Next = rdsym(b)
	s.Sub = rdsym(b)
	s.Outer = rdsym(b)
	s.Gotype = rdsym(b)
	s.Reachparent = rdsym(b)
	s.Queue = rdsym(b)
	s.File = rdstring(b)
	s.Dynimplib = rdstring(b)
	s.Dynimpvers = rdstring(b)
	s.Text = rdprog(b)
	s.Etext = rdprog(b)
	n := int(rdint(b))
	if n > 0 {
		s.P = make([]byte, n)
		io.ReadFull(b, s.P)
	}
	s.R = make([]obj.Reloc, int(rdint(b)))
	for i := range s.R {
		r := &s.R[i]
		r.Off = int32(rdint(b))
		r.Siz = uint8(rdint(b))
		r.Done = uint8(rdint(b))
		r.Type_ = int32(rdint(b))
		r.Add = rdint(b)
		r.Xadd = rdint(b)
		r.Sym = rdsym(b)
		r.Xsym = rdsym(b)
	}
}

func readprog(b *bufio.Reader, p *obj.Prog) {
	if !undef[p] {
		panic("double-def")
	}
	delete(undef, p)
	p.Pc = rdint(b)
	p.Lineno = int32(rdint(b))
	p.Link = rdprog(b)
	p.As = int16(rdint(b))
	p.Reg = uint8(rdint(b))
	p.Scond = uint8(rdint(b))
	p.Width = int8(rdint(b))
	readaddr(b, &p.From)
	readaddr(b, &p.From3)
	readaddr(b, &p.To)
}

func readaddr(b *bufio.Reader, a *obj.Addr) {
	if rdint(b) != TypeAddr {
		log.Fatal("out of sync")
	}
	a.Offset = rdint(b)
	a.U.Dval = rdfloat(b)
	buf := make([]byte, 8)
	io.ReadFull(b, buf)
	a.U.Sval = string(buf)
	a.U.Branch = rdprog(b)
	a.Sym = rdsym(b)
	a.Gotype = rdsym(b)
	a.Type_ = int16(rdint(b))
	a.Index = uint8(rdint(b))
	a.Scale = int8(rdint(b))
	a.Reg = int8(rdint(b))
	a.Name = int8(rdint(b))
	a.Class = int8(rdint(b))
	a.Etype = uint8(rdint(b))
	a.Offset2 = int32(rdint(b))
	a.Width = rdint(b)
}

func readhist(b *bufio.Reader, h *obj.Hist) {
	if !undef[h] {
		panic("double-def")
	}
	delete(undef, h)
	h.Link = rdhist(b)
	h.Name = rdstring(b)
	h.Line = int32(rdint(b))
	h.Offset = int32(rdint(b))
}

func rdfloat(b *bufio.Reader) float64 {
	return math.Float64frombits(uint64(rdint(b)))
}
<|endoftext|>


<commit_before>// +build !gtk_3_6,!gtk_3_8,!gtk_3_10,!gtk_3_12,!gtk_3_14,!gtk_3_16

// See: https://developer.gnome.org/gtk3/3.18/api-index-3-18.html

// For gtk_overlay_reorder_overlay():
// See: https://git.gnome.org/browse/gtk+/tree/gtk/gtkoverlay.h?h=gtk-3-18

package gtk

// #include <gtk/gtk.h>
import "C"

/*
 * GtkStack
 */

// TODO:
// gtk_stack_get_interpolate_size().
// gtk_stack_set_interpolate_size().

/*
 * GtkRadioMenuItem
 */

// TODO
// gtk_radio_menu_item_join_group().

/*
 * GtkOverlay
 */

// ReorderOverlay() is a wrapper around gtk_overlay_reorder_overlay().
func (v *Overlay) ReorderOverlay(child IWidget, position int) {
	C.gtk_overlay_reorder_overlay(v.native(), child.toWidget(), C.int(position))
}

// GetOverlayPassThrough() is a wrapper around gtk_overlay_get_overlay_pass_through().
func (v *Overlay) GetOverlayPassThrough(widget IWidget) bool {
	c := C.gtk_overlay_get_overlay_pass_through(v.native(), widget.toWidget())
	return gobool(c)
}

// SetOverlayPassThrough() is a wrapper around gtk_overlay_set_overlay_pass_through().
func (v *Overlay) SetOverlayPassThrough(widget IWidget, passThrough bool) {
	C.gtk_overlay_set_overlay_pass_through(v.native(), widget.toWidget(), gbool(passThrough))
}

/*
 * GtkPlacesSidebar
 */

// TODO:
// gtk_places_sidebar_set_show_recent().
// gtk_places_sidebar_get_show_recent().
// gtk_places_sidebar_get_show_trash().
// gtk_places_sidebar_set_show_trash().
// gtk_places_sidebar_get_show_other_locations().
// gtk_places_sidebar_set_show_other_locations().
// gtk_places_sidebar_set_drop_targets_visible().

/*
 * GtkPopover
 */

// SetDefaultWidget is a wrapper around gtk_popover_set_default_widget().
func (p *Popover) SetDefaultWidget(widget IWidget) {
	C.gtk_popover_set_default_widget(p.native(), widget.toWidget())
}

// GetDefaultWidget is a wrapper around gtk_popover_get_default_widget().
func (p *Popover) GetDefaultWidget() (IWidget, error) {
	w := C.gtk_popover_get_default_widget(p.native())
	if w == nil {
		return nil, nil
	}
	return castWidget(w)
}

/*
 * GtkTextView
 */

// SetTopMargin is a wrapper around gtk_text_view_set_top_margin().
func (v *TextView) SetTopMargin(topMargin int) {
	C.gtk_text_view_set_top_margin(v.native(), C.gint(topMargin))
}

// GetTopMargin is a wrapper around gtk_text_view_get_top_margin().
func (v *TextView) GetTopMargin() int {
	return int(C.gtk_text_view_get_top_margin(v.native()))
}

// SetBottomMargin is a wrapper around gtk_text_view_set_bottom_margin().
func (v *TextView) SetBottomMargin(bottomMargin int) {
	C.gtk_text_view_set_bottom_margin(v.native(), C.gint(bottomMargin))
}

// GetBottomMargin is a wrapper around gtk_text_view_get_bottom_margin().
func (v *TextView) GetBottomMargin() int {
	return int(C.gtk_text_view_get_bottom_margin(v.native()))
}
<commit_msg>Add binding for GtkRadioMenuItem<commit_after>// +build !gtk_3_6,!gtk_3_8,!gtk_3_10,!gtk_3_12,!gtk_3_14,!gtk_3_16

// See: https://developer.gnome.org/gtk3/3.18/api-index-3-18.html

// For gtk_overlay_reorder_overlay():
// See: https://git.gnome.org/browse/gtk+/tree/gtk/gtkoverlay.h?h=gtk-3-18

package gtk

// #include <gtk/gtk.h>
import "C"

/*
 * GtkStack
 */

// TODO:
// gtk_stack_get_interpolate_size().
// gtk_stack_set_interpolate_size().

/*
 * GtkRadioMenuItem
 */

// JoinGroup is a wrapper around gtk_radio_menu_item_join_group().
func (v *RadioMenuItem) JoinGroup(group_source *RadioMenuItem) {
	C.gtk_radio_menu_item_join_group(v.native(), group_source.native())
}

/*
 * GtkOverlay
 */

// ReorderOverlay() is a wrapper around gtk_overlay_reorder_overlay().
func (v *Overlay) ReorderOverlay(child IWidget, position int) {
	C.gtk_overlay_reorder_overlay(v.native(), child.toWidget(), C.int(position))
}

// GetOverlayPassThrough() is a wrapper around gtk_overlay_get_overlay_pass_through().
func (v *Overlay) GetOverlayPassThrough(widget IWidget) bool {
	c := C.gtk_overlay_get_overlay_pass_through(v.native(), widget.toWidget())
	return gobool(c)
}

// SetOverlayPassThrough() is a wrapper around gtk_overlay_set_overlay_pass_through().
func (v *Overlay) SetOverlayPassThrough(widget IWidget, passThrough bool) {
	C.gtk_overlay_set_overlay_pass_through(v.native(), widget.toWidget(), gbool(passThrough))
}

/*
 * GtkPlacesSidebar
 */

// TODO:
// gtk_places_sidebar_set_show_recent().
// gtk_places_sidebar_get_show_recent().
// gtk_places_sidebar_get_show_trash().
// gtk_places_sidebar_set_show_trash().
// gtk_places_sidebar_get_show_other_locations().
// gtk_places_sidebar_set_show_other_locations().
// gtk_places_sidebar_set_drop_targets_visible().

/*
 * GtkPopover
 */

// SetDefaultWidget is a wrapper around gtk_popover_set_default_widget().
func (p *Popover) SetDefaultWidget(widget IWidget) {
	C.gtk_popover_set_default_widget(p.native(), widget.toWidget())
}

// GetDefaultWidget is a wrapper around gtk_popover_get_default_widget().
func (p *Popover) GetDefaultWidget() (IWidget, error) {
	w := C.gtk_popover_get_default_widget(p.native())
	if w == nil {
		return nil, nil
	}
	return castWidget(w)
}

/*
 * GtkTextView
 */

// SetTopMargin is a wrapper around gtk_text_view_set_top_margin().
func (v *TextView) SetTopMargin(topMargin int) {
	C.gtk_text_view_set_top_margin(v.native(), C.gint(topMargin))
}

// GetTopMargin is a wrapper around gtk_text_view_get_top_margin().
func (v *TextView) GetTopMargin() int {
	return int(C.gtk_text_view_get_top_margin(v.native()))
}

// SetBottomMargin is a wrapper around gtk_text_view_set_bottom_margin().
func (v *TextView) SetBottomMargin(bottomMargin int) {
	C.gtk_text_view_set_bottom_margin(v.native(), C.gint(bottomMargin))
}

// GetBottomMargin is a wrapper around gtk_text_view_get_bottom_margin().
func (v *TextView) GetBottomMargin() int {
	return int(C.gtk_text_view_get_bottom_margin(v.native()))
}
<|endoftext|>


<commit_before>package sidekick

import (
	"bytes"
	"errors"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"io/ioutil"
	"os"
	"os/exec"
	"time"
)

func NewHaproxy(role string, properties *Config, version string, context Context) *Haproxy {
	if version == "" {
		version = "1.4.22"
	}
	return &Haproxy{
		Role:       role,
		properties: properties,
		Version:    version,
		Context:    context,
	}
}

type Haproxy struct {
	Role       string
	Version    string
	properties *Config
	State      int
	Context    Context
}

const (
	SUCCESS    int = iota
	UNCHANGED  int = iota
	ERR_SYSLOG int = iota
	ERR_CONF   int = iota
	ERR_RELOAD int = iota
)

// ApplyConfiguration write the new configuration and reload
// A rollback is called on failure
func (hap *Haproxy) ApplyConfiguration(data *EventMessage) (int, error) {
	hap.createSkeleton(data.CorrelationId)

	newConf := data.Conf
	path := hap.confPath()

	// Check conf diff
	oldConf, err := ioutil.ReadFile(path)
	if log.GetLevel() == log.DebugLevel {
		hap.dumpConfiguration(hap.NewDebugPath(), newConf, data)
	}
	if bytes.Equal(oldConf, newConf) {
		log.WithFields(hap.Context.Fields()).WithFields(
			log.Fields{"role": hap.Role}).Debug("Unchanged configuration")
		return UNCHANGED, nil
	}

	// Archive previous configuration
	archivePath := hap.confArchivePath()
	os.Rename(path, archivePath)
	log.WithFields(hap.Context.Fields()).WithFields(
		log.Fields{
			"role":        hap.Role,
			"archivePath": archivePath,
		}).Info("Old configuration saved")
	err = ioutil.WriteFile(path, newConf, 0644)
	if err != nil {
		return ERR_CONF, err
	}

	log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
		"role": hap.Role,
		"path": path,
	}).Info("New configuration written")

	// Reload haproxy
	err = hap.reload(data.CorrelationId)
	if err != nil {
		log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
			"role": hap.Role,
		}).WithError(err).Error("Reload failed")
		hap.dumpConfiguration(hap.NewErrorPath(), newConf, data)
		errRollback := hap.rollback(data.CorrelationId)
		if errRollback != nil {
			log.WithError(errRollback).Error("error in rollback in addition to error of the reload")
		} else {
			log.WithFields(hap.Context.Fields()).Debug("rollback done")
		}
		return ERR_RELOAD, err
	}
	// Write syslog fragment
	fragmentPath := hap.syslogFragmentPath()
	err = ioutil.WriteFile(fragmentPath, data.SyslogFragment, 0644)
	if err != nil {
		log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
			"role": hap.Role,
		}).WithError(err).Error("Failed to write syslog fragment")
		// TODO Should we rollback on syslog error ?
		return ERR_SYSLOG, err
	}
	log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
		"role":     hap.Role,
		"content":  string(data.SyslogFragment),
		"filename": fragmentPath,
	}).Debug("Write syslog fragment")

	return SUCCESS, nil
}

// dumpConfiguration dumps the new configuration file with context for debugging purpose
func (hap *Haproxy) dumpConfiguration(filename string, newConf []byte, data *EventMessage) {
	f, err2 := os.Create(filename)
	defer f.Close()
	if err2 == nil {
		f.WriteString("================================================================\n")
		f.WriteString(fmt.Sprintf("application: %s\n", data.Application))
		f.WriteString(fmt.Sprintf("platform: %s\n", data.Platform))
		f.WriteString(fmt.Sprintf("correlationId: %s\n", data.CorrelationId))
		f.WriteString("================================================================\n")
		f.Write(newConf)
		f.Sync()

		log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
			"role":     hap.Role,
			"filename": filename,
		}).Info("Dump configuration")
	}
}

// confPath give the path of the configuration file given an application context
// It returns the absolute path to the file
func (hap *Haproxy) confPath() string {
	baseDir := hap.properties.HapHome + "/" + hap.Context.Application + "/Config"
	return baseDir + "/hap" + hap.Context.Application + hap.Context.Platform + ".conf"
}

// confPath give the path of the archived configuration file given an application context
func (hap *Haproxy) confArchivePath() string {
	baseDir := hap.properties.HapHome + "/" + hap.Context.Application + "/version-1"
	return baseDir + "/hap" + hap.Context.Application + hap.Context.Platform + ".conf"
}

// NewErrorPath gives a unique path the error file given the hap context
// It returns the full path to the file
func (hap *Haproxy) NewErrorPath() string {
	baseDir := hap.properties.HapHome + "/" + hap.Context.Application + "/errors"
	prefix := time.Now().Format("20060102150405")
	return baseDir + "/" + prefix + "_" + hap.Context.Application + hap.Context.Platform + ".log"
}

func (hap *Haproxy) NewDebugPath() string {
	baseDir := hap.properties.HapHome + "/" + hap.Context.Application + "/dump"
	prefix := time.Now().Format("20060102150405")
	return baseDir + "/" + prefix + "_" + hap.Context.Application + hap.Context.Platform + ".log"
}

// reload calls external shell script to reload haproxy
// It returns error if the reload fails
func (hap *Haproxy) reload(correlationId string) error {
	reloadScript := hap.getReloadScript()
	output, err := exec.Command("sh", reloadScript, "reload", "-y").Output()
	if err != nil {
		log.WithFields(hap.Context.Fields()).WithError(err).Error("Error reloading")
	} else {
		log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
			"role":         hap.Role,
			"reloadScript": reloadScript,
			"cmd":          string(output[:]),
		}).Debug("Reload succeeded")
	}
	return err
}

// rollback reverts configuration files and call for reload
func (hap *Haproxy) rollback(correlationId string) error {
	lastConf := hap.confArchivePath()
	if _, err := os.Stat(lastConf); os.IsNotExist(err) {
		return errors.New("No configuration file to rollback")
	}
	// TODO remove current hap.confPath() ?
	os.Rename(lastConf, hap.confPath())
	hap.reload(correlationId)
	return nil
}

// createSkeleton creates the directory tree for a new haproxy context
func (hap *Haproxy) createSkeleton(correlationId string) error {
	baseDir := hap.properties.HapHome + "/" + hap.Context.Application

	createDirectory(hap.Context, correlationId, baseDir+"/Config")
	createDirectory(hap.Context, correlationId, baseDir+"/logs/"+hap.Context.Application+hap.Context.Platform)
	createDirectory(hap.Context, correlationId, baseDir+"/scripts")
	createDirectory(hap.Context, correlationId, baseDir+"/version-1")
	createDirectory(hap.Context, correlationId, baseDir+"/errors")
	createDirectory(hap.Context, correlationId, baseDir+"/dump")

	updateSymlink(hap.Context, correlationId, hap.getHapctlFilename(), hap.getReloadScript())
	updateSymlink(hap.Context, correlationId, hap.getHapBinary(), baseDir+"/Config/haproxy")

	return nil
}

// confPath give the path of the configuration file given an application context
// It returns the absolute path to the file
func (hap *Haproxy) syslogFragmentPath() string {
	baseDir := hap.properties.HapHome + "/SYSLOG/Config/syslog.conf.d"
	os.MkdirAll(baseDir, 0755)
	return baseDir + "/syslog" + hap.Context.Application + hap.Context.Platform + ".conf"
}

// updateSymlink create or update a symlink
func updateSymlink(context Context, correlationId, oldname, newname string) {
	newLink := true
	if _, err := os.Stat(newname); err == nil {
		os.Remove(newname)
		newLink = false
	}
	err := os.Symlink(oldname, newname)
	if err != nil {
		log.WithFields(context.Fields()).WithError(err).WithFields(log.Fields{
			"path": newname,
		}).Error("Symlink failed")
	}

	if newLink {
		log.WithFields(context.Fields()).WithFields(log.Fields{
			"path": newname,
		}).Info("Symlink created")
	}
}

// createDirectory recursively creates directory if it doesn't exists
func createDirectory(context Context, correlationId string, dir string) {
	if _, err := os.Stat(dir); os.IsNotExist(err) {
		err := os.MkdirAll(dir, 0755)
		if err != nil {
			log.WithError(err).WithFields(context.Fields()).WithFields(log.Fields{
				"dir": dir,
			}).Error("Failed to create")
		} else {
			log.WithFields(context.Fields()).WithFields(log.Fields{
				"dir": dir,
			}).Info("Directory created")
		}
	}
}

// getHapctlFilename return the path to the vsc hapctl shell script
// This script is provided
func (hap *Haproxy) getHapctlFilename() string {
	return "/HOME/uxwadm/scripts/hapctl_unif"
}

// getReloadScript calculates reload script path given the hap context
// It returns the full script path
func (hap *Haproxy) getReloadScript() string {
	return fmt.Sprintf("%s/%s/scripts/hapctl%s%s", hap.properties.HapHome, hap.Context.Application, hap.Context.Application, hap.Context.Platform)
}

// getHapBinary calculates the haproxy binary to use given the expected version
// It returns the full path to the haproxy binary
func (hap *Haproxy) getHapBinary() string {
	return fmt.Sprintf("/export/product/haproxy/product/%s/bin/haproxy", hap.Version)
}

func (hap *Haproxy) Delete() {
	baseDir := hap.properties.HapHome + "/" + hap.Context.Application
	err := os.RemoveAll(baseDir)
	if err != nil {
		log.WithError(err).WithFields(hap.Context.Fields()).WithFields(log.Fields{
			"dir": baseDir,
		}).Error("Failed to delete haproxy")
	} else {
		log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
			"dir": baseDir,
		}).Info("HAproxy deleted")
	}
}

func (hap *Haproxy) Stop() error{
	reloadScript := hap.getReloadScript()
	output, err := exec.Command("sh", reloadScript, "stop").Output()
	if err != nil {
		log.WithFields(hap.Context.Fields()).WithError(err).Error("Error stop")
	} else {
		log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
			"reloadScript": reloadScript,
			"cmd":          string(output[:]),
		}).Debug("Stop succeeded")
	}
	return err
}
<commit_msg>go fmt<commit_after>package sidekick

import (
	"bytes"
	"errors"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"io/ioutil"
	"os"
	"os/exec"
	"time"
)

func NewHaproxy(role string, properties *Config, version string, context Context) *Haproxy {
	if version == "" {
		version = "1.4.22"
	}
	return &Haproxy{
		Role:       role,
		properties: properties,
		Version:    version,
		Context:    context,
	}
}

type Haproxy struct {
	Role       string
	Version    string
	properties *Config
	State      int
	Context    Context
}

const (
	SUCCESS    int = iota
	UNCHANGED  int = iota
	ERR_SYSLOG int = iota
	ERR_CONF   int = iota
	ERR_RELOAD int = iota
)

// ApplyConfiguration write the new configuration and reload
// A rollback is called on failure
func (hap *Haproxy) ApplyConfiguration(data *EventMessage) (int, error) {
	hap.createSkeleton(data.CorrelationId)

	newConf := data.Conf
	path := hap.confPath()

	// Check conf diff
	oldConf, err := ioutil.ReadFile(path)
	if log.GetLevel() == log.DebugLevel {
		hap.dumpConfiguration(hap.NewDebugPath(), newConf, data)
	}
	if bytes.Equal(oldConf, newConf) {
		log.WithFields(hap.Context.Fields()).WithFields(
			log.Fields{"role": hap.Role}).Debug("Unchanged configuration")
		return UNCHANGED, nil
	}

	// Archive previous configuration
	archivePath := hap.confArchivePath()
	os.Rename(path, archivePath)
	log.WithFields(hap.Context.Fields()).WithFields(
		log.Fields{
			"role":        hap.Role,
			"archivePath": archivePath,
		}).Info("Old configuration saved")
	err = ioutil.WriteFile(path, newConf, 0644)
	if err != nil {
		return ERR_CONF, err
	}

	log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
		"role": hap.Role,
		"path": path,
	}).Info("New configuration written")

	// Reload haproxy
	err = hap.reload(data.CorrelationId)
	if err != nil {
		log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
			"role": hap.Role,
		}).WithError(err).Error("Reload failed")
		hap.dumpConfiguration(hap.NewErrorPath(), newConf, data)
		errRollback := hap.rollback(data.CorrelationId)
		if errRollback != nil {
			log.WithError(errRollback).Error("error in rollback in addition to error of the reload")
		} else {
			log.WithFields(hap.Context.Fields()).Debug("rollback done")
		}
		return ERR_RELOAD, err
	}
	// Write syslog fragment
	fragmentPath := hap.syslogFragmentPath()
	err = ioutil.WriteFile(fragmentPath, data.SyslogFragment, 0644)
	if err != nil {
		log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
			"role": hap.Role,
		}).WithError(err).Error("Failed to write syslog fragment")
		// TODO Should we rollback on syslog error ?
		return ERR_SYSLOG, err
	}
	log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
		"role":     hap.Role,
		"content":  string(data.SyslogFragment),
		"filename": fragmentPath,
	}).Debug("Write syslog fragment")

	return SUCCESS, nil
}

// dumpConfiguration dumps the new configuration file with context for debugging purpose
func (hap *Haproxy) dumpConfiguration(filename string, newConf []byte, data *EventMessage) {
	f, err2 := os.Create(filename)
	defer f.Close()
	if err2 == nil {
		f.WriteString("================================================================\n")
		f.WriteString(fmt.Sprintf("application: %s\n", data.Application))
		f.WriteString(fmt.Sprintf("platform: %s\n", data.Platform))
		f.WriteString(fmt.Sprintf("correlationId: %s\n", data.CorrelationId))
		f.WriteString("================================================================\n")
		f.Write(newConf)
		f.Sync()

		log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
			"role":     hap.Role,
			"filename": filename,
		}).Info("Dump configuration")
	}
}

// confPath give the path of the configuration file given an application context
// It returns the absolute path to the file
func (hap *Haproxy) confPath() string {
	baseDir := hap.properties.HapHome + "/" + hap.Context.Application + "/Config"
	return baseDir + "/hap" + hap.Context.Application + hap.Context.Platform + ".conf"
}

// confPath give the path of the archived configuration file given an application context
func (hap *Haproxy) confArchivePath() string {
	baseDir := hap.properties.HapHome + "/" + hap.Context.Application + "/version-1"
	return baseDir + "/hap" + hap.Context.Application + hap.Context.Platform + ".conf"
}

// NewErrorPath gives a unique path the error file given the hap context
// It returns the full path to the file
func (hap *Haproxy) NewErrorPath() string {
	baseDir := hap.properties.HapHome + "/" + hap.Context.Application + "/errors"
	prefix := time.Now().Format("20060102150405")
	return baseDir + "/" + prefix + "_" + hap.Context.Application + hap.Context.Platform + ".log"
}

func (hap *Haproxy) NewDebugPath() string {
	baseDir := hap.properties.HapHome + "/" + hap.Context.Application + "/dump"
	prefix := time.Now().Format("20060102150405")
	return baseDir + "/" + prefix + "_" + hap.Context.Application + hap.Context.Platform + ".log"
}

// reload calls external shell script to reload haproxy
// It returns error if the reload fails
func (hap *Haproxy) reload(correlationId string) error {
	reloadScript := hap.getReloadScript()
	output, err := exec.Command("sh", reloadScript, "reload", "-y").Output()
	if err != nil {
		log.WithFields(hap.Context.Fields()).WithError(err).Error("Error reloading")
	} else {
		log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
			"role":         hap.Role,
			"reloadScript": reloadScript,
			"cmd":          string(output[:]),
		}).Debug("Reload succeeded")
	}
	return err
}

// rollback reverts configuration files and call for reload
func (hap *Haproxy) rollback(correlationId string) error {
	lastConf := hap.confArchivePath()
	if _, err := os.Stat(lastConf); os.IsNotExist(err) {
		return errors.New("No configuration file to rollback")
	}
	// TODO remove current hap.confPath() ?
	os.Rename(lastConf, hap.confPath())
	hap.reload(correlationId)
	return nil
}

// createSkeleton creates the directory tree for a new haproxy context
func (hap *Haproxy) createSkeleton(correlationId string) error {
	baseDir := hap.properties.HapHome + "/" + hap.Context.Application

	createDirectory(hap.Context, correlationId, baseDir+"/Config")
	createDirectory(hap.Context, correlationId, baseDir+"/logs/"+hap.Context.Application+hap.Context.Platform)
	createDirectory(hap.Context, correlationId, baseDir+"/scripts")
	createDirectory(hap.Context, correlationId, baseDir+"/version-1")
	createDirectory(hap.Context, correlationId, baseDir+"/errors")
	createDirectory(hap.Context, correlationId, baseDir+"/dump")

	updateSymlink(hap.Context, correlationId, hap.getHapctlFilename(), hap.getReloadScript())
	updateSymlink(hap.Context, correlationId, hap.getHapBinary(), baseDir+"/Config/haproxy")

	return nil
}

// confPath give the path of the configuration file given an application context
// It returns the absolute path to the file
func (hap *Haproxy) syslogFragmentPath() string {
	baseDir := hap.properties.HapHome + "/SYSLOG/Config/syslog.conf.d"
	os.MkdirAll(baseDir, 0755)
	return baseDir + "/syslog" + hap.Context.Application + hap.Context.Platform + ".conf"
}

// updateSymlink create or update a symlink
func updateSymlink(context Context, correlationId, oldname, newname string) {
	newLink := true
	if _, err := os.Stat(newname); err == nil {
		os.Remove(newname)
		newLink = false
	}
	err := os.Symlink(oldname, newname)
	if err != nil {
		log.WithFields(context.Fields()).WithError(err).WithFields(log.Fields{
			"path": newname,
		}).Error("Symlink failed")
	}

	if newLink {
		log.WithFields(context.Fields()).WithFields(log.Fields{
			"path": newname,
		}).Info("Symlink created")
	}
}

// createDirectory recursively creates directory if it doesn't exists
func createDirectory(context Context, correlationId string, dir string) {
	if _, err := os.Stat(dir); os.IsNotExist(err) {
		err := os.MkdirAll(dir, 0755)
		if err != nil {
			log.WithError(err).WithFields(context.Fields()).WithFields(log.Fields{
				"dir": dir,
			}).Error("Failed to create")
		} else {
			log.WithFields(context.Fields()).WithFields(log.Fields{
				"dir": dir,
			}).Info("Directory created")
		}
	}
}

// getHapctlFilename return the path to the vsc hapctl shell script
// This script is provided
func (hap *Haproxy) getHapctlFilename() string {
	return "/HOME/uxwadm/scripts/hapctl_unif"
}

// getReloadScript calculates reload script path given the hap context
// It returns the full script path
func (hap *Haproxy) getReloadScript() string {
	return fmt.Sprintf("%s/%s/scripts/hapctl%s%s", hap.properties.HapHome, hap.Context.Application, hap.Context.Application, hap.Context.Platform)
}

// getHapBinary calculates the haproxy binary to use given the expected version
// It returns the full path to the haproxy binary
func (hap *Haproxy) getHapBinary() string {
	return fmt.Sprintf("/export/product/haproxy/product/%s/bin/haproxy", hap.Version)
}

func (hap *Haproxy) Delete() {
	baseDir := hap.properties.HapHome + "/" + hap.Context.Application
	err := os.RemoveAll(baseDir)
	if err != nil {
		log.WithError(err).WithFields(hap.Context.Fields()).WithFields(log.Fields{
			"dir": baseDir,
		}).Error("Failed to delete haproxy")
	} else {
		log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
			"dir": baseDir,
		}).Info("HAproxy deleted")
	}
}

func (hap *Haproxy) Stop() error {
	reloadScript := hap.getReloadScript()
	output, err := exec.Command("sh", reloadScript, "stop").Output()
	if err != nil {
		log.WithFields(hap.Context.Fields()).WithError(err).Error("Error stop")
	} else {
		log.WithFields(hap.Context.Fields()).WithFields(log.Fields{
			"reloadScript": reloadScript,
			"cmd":          string(output[:]),
		}).Debug("Stop succeeded")
	}
	return err
}
<|endoftext|>