<commit_before>package google

import (
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
	compute "google.golang.org/api/compute/v1"
)

func resourceComputeAttachedDisk() *schema.Resource {
	return &schema.Resource{
		Create: resourceAttachedDiskCreate,
		Read:   resourceAttachedDiskRead,
		Delete: resourceAttachedDiskDelete,

		Importer: &schema.ResourceImporter{
			State: resourceAttachedDiskImport,
		},

		Timeouts: &schema.ResourceTimeout{
			Create: schema.DefaultTimeout(300 * time.Second),
			Delete: schema.DefaultTimeout(300 * time.Second),
		},

		Schema: map[string]*schema.Schema{
			"disk": {
				Type:             schema.TypeString,
				Required:         true,
				ForceNew:         true,
				DiffSuppressFunc: compareSelfLinkOrResourceName,
			},
			"instance": {
				Type:             schema.TypeString,
				Required:         true,
				ForceNew:         true,
				DiffSuppressFunc: compareSelfLinkOrResourceName,
			},
			"project": {
				Type:     schema.TypeString,
				ForceNew: true,
				Computed: true,
				Optional: true,
			},
			"zone": {
				Type:     schema.TypeString,
				ForceNew: true,
				Computed: true,
				Optional: true,
			},
			"device_name": {
				Type:     schema.TypeString,
				ForceNew: true,
				Optional: true,
				Computed: true,
			},
			"mode": {
				Type:         schema.TypeString,
				ForceNew:     true,
				Optional:     true,
				Default:      "READ_WRITE",
				ValidateFunc: validation.StringInSlice([]string{"READ_ONLY", "READ_WRITE"}, false),
			},
		},
	}
}

func resourceAttachedDiskCreate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	zv, err := parseZonalFieldValue("instances", d.Get("instance").(string), "project", "zone", d, config, false)
	if err != nil {
		return err
	}

	disk := d.Get("disk").(string)
	diskName := GetResourceNameFromSelfLink(disk)
	diskSrc := fmt.Sprintf("projects/%s/zones/%s/disks/%s", zv.Project, zv.Zone, diskName)

	// Check if the disk is a regional disk
	if strings.Contains(disk, "regions") {
		rv, err := ParseRegionDiskFieldValue(disk, d, config)
		if err != nil {
			return err
		}
		diskSrc = rv.RelativeLink()
	}

	attachedDisk := compute.AttachedDisk{
		Source:     diskSrc,
		Mode:       d.Get("mode").(string),
		DeviceName: d.Get("device_name").(string),
	}

	op, err := config.clientCompute.Instances.AttachDisk(zv.Project, zv.Zone, zv.Name, &attachedDisk).Do()
	if err != nil {
		return err
	}

	d.SetId(fmt.Sprintf("projects/%s/zones/%s/instances/%s/%s", zv.Project, zv.Zone, zv.Name, diskName))

	waitErr := computeOperationWaitTime(config, op, zv.Project,
		"disk to attach", d.Timeout(schema.TimeoutCreate))
	if waitErr != nil {
		d.SetId("")
		return waitErr
	}

	return resourceAttachedDiskRead(d, meta)
}

func resourceAttachedDiskRead(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	zv, err := parseZonalFieldValue("instances", d.Get("instance").(string), "project", "zone", d, config, false)
	if err != nil {
		return err
	}
	d.Set("project", zv.Project)
	d.Set("zone", zv.Zone)

	diskName := GetResourceNameFromSelfLink(d.Get("disk").(string))

	instance, err := config.clientCompute.Instances.Get(zv.Project, zv.Zone, zv.Name).Do()
	if err != nil {
		return handleNotFoundError(err, d, fmt.Sprintf("AttachedDisk %q", d.Id()))
	}

	// Iterate through the instance's attached disks as this is the only way to
	// confirm the disk is actually attached
	ad := findDiskByName(instance.Disks, diskName)
	if ad == nil {
		log.Printf("[WARN] Referenced disk wasn't found attached to this compute instance. Removing from state.")
		d.SetId("")
		return nil
	}

	d.Set("device_name", ad.DeviceName)
	d.Set("mode", ad.Mode)

	// Force the referenced resources to a self-link in state because it's more specific then name.
	instancePath, err := getRelativePath(instance.SelfLink)
	if err != nil {
		return err
	}
	d.Set("instance", instancePath)
	diskPath, err := getRelativePath(ad.Source)
	if err != nil {
		return err
	}
	d.Set("disk", diskPath)

	return nil
}

func resourceAttachedDiskDelete(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	zv, err := parseZonalFieldValue("instances", d.Get("instance").(string), "project", "zone", d, config, false)
	if err != nil {
		return err
	}

	diskName := GetResourceNameFromSelfLink(d.Get("disk").(string))

	instance, err := config.clientCompute.Instances.Get(zv.Project, zv.Zone, zv.Name).Do()
	if err != nil {
		return err
	}

	// Confirm the disk is still attached before making the call to detach it. If the disk isn't listed as an attached
	// disk on the compute instance then return as though the delete call succeed since this is the desired state.
	ad := findDiskByName(instance.Disks, diskName)
	if ad == nil {
		return nil
	}

	op, err := config.clientCompute.Instances.DetachDisk(zv.Project, zv.Zone, zv.Name, ad.DeviceName).Do()
	if err != nil {
		return err
	}

	waitErr := computeOperationWaitTime(config, op, zv.Project,
		fmt.Sprintf("Detaching disk from %s", zv.Name), d.Timeout(schema.TimeoutDelete))
	if waitErr != nil {
		return waitErr
	}

	return nil
}

func resourceAttachedDiskImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
	config := meta.(*Config)

	err := parseImportId(
		[]string{"projects/(?P<project>[^/]+)/zones/(?P<zone>[^/]+)/instances/(?P<instance>[^/]+)/(?P<disk>[^/]+)",
			"(?P<project>[^/]+)/(?P<zone>[^/]+)/(?P<instance>[^/]+)/(?P<disk>[^/]+)"}, d, config)
	if err != nil {
		return nil, err
	}

	id, err := replaceVars(d, config, "projects/{{project}}/zones/{{zone}}/instances/{{instance}}/{{disk}}")
	if err != nil {
		return nil, err
	}
	d.SetId(id)

	return []*schema.ResourceData{d}, nil
}

func findDiskByName(disks []*compute.AttachedDisk, id string) *compute.AttachedDisk {
	for _, disk := range disks {
		if compareSelfLinkOrResourceName("", disk.Source, id, nil) {
			return disk
		}
	}

	return nil
}
<commit_msg>add desc to schema for google_compute_attached_disk (#3679)<commit_after>package google

import (
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
	compute "google.golang.org/api/compute/v1"
)

func resourceComputeAttachedDisk() *schema.Resource {
	return &schema.Resource{
		Create: resourceAttachedDiskCreate,
		Read:   resourceAttachedDiskRead,
		Delete: resourceAttachedDiskDelete,

		Importer: &schema.ResourceImporter{
			State: resourceAttachedDiskImport,
		},

		Timeouts: &schema.ResourceTimeout{
			Create: schema.DefaultTimeout(300 * time.Second),
			Delete: schema.DefaultTimeout(300 * time.Second),
		},

		Schema: map[string]*schema.Schema{
			"disk": {
				Type:             schema.TypeString,
				Required:         true,
				ForceNew:         true,
				Description:      `name or self_link of the disk that will be attached.`,
				DiffSuppressFunc: compareSelfLinkOrResourceName,
			},
			"instance": {
				Type:             schema.TypeString,
				Required:         true,
				ForceNew:         true,
				Description:      `name or self_link of the compute instance that the disk will be attached to. If the self_link is provided then zone and project are extracted from the self link. If only the name is used then zone and project must be defined as properties on the resource or provider.`,
				DiffSuppressFunc: compareSelfLinkOrResourceName,
			},
			"project": {
				Type:        schema.TypeString,
				ForceNew:    true,
				Computed:    true,
				Optional:    true,
				Description: `The project that the referenced compute instance is a part of. If instance is referenced by its self_link the project defined in the link will take precedence.`,
			},
			"zone": {
				Type:        schema.TypeString,
				ForceNew:    true,
				Computed:    true,
				Optional:    true,
				Description: `The zone that the referenced compute instance is located within. If instance is referenced by its self_link the zone defined in the link will take precedence.`,
			},
			"device_name": {
				Type:        schema.TypeString,
				ForceNew:    true,
				Optional:    true,
				Computed:    true,
				Description: `Specifies a unique device name of your choice that is reflected into the /dev/disk/by-id/google-* tree of a Linux operating system running within the instance. This name can be used to reference the device for mounting, resizing, and so on, from within the instance. If not specified, the server chooses a default device name to apply to this disk, in the form persistent-disks-x, where x is a number assigned by Google Compute Engine.`,
			},
			"mode": {
				Type:         schema.TypeString,
				ForceNew:     true,
				Optional:     true,
				Default:      "READ_WRITE",
				Description:  `The mode in which to attach this disk, either READ_WRITE or READ_ONLY. If not specified, the default is to attach the disk in READ_WRITE mode.`,
				ValidateFunc: validation.StringInSlice([]string{"READ_ONLY", "READ_WRITE"}, false),
			},
		},
	}
}

func resourceAttachedDiskCreate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	zv, err := parseZonalFieldValue("instances", d.Get("instance").(string), "project", "zone", d, config, false)
	if err != nil {
		return err
	}

	disk := d.Get("disk").(string)
	diskName := GetResourceNameFromSelfLink(disk)
	diskSrc := fmt.Sprintf("projects/%s/zones/%s/disks/%s", zv.Project, zv.Zone, diskName)

	// Check if the disk is a regional disk
	if strings.Contains(disk, "regions") {
		rv, err := ParseRegionDiskFieldValue(disk, d, config)
		if err != nil {
			return err
		}
		diskSrc = rv.RelativeLink()
	}

	attachedDisk := compute.AttachedDisk{
		Source:     diskSrc,
		Mode:       d.Get("mode").(string),
		DeviceName: d.Get("device_name").(string),
	}

	op, err := config.clientCompute.Instances.AttachDisk(zv.Project, zv.Zone, zv.Name, &attachedDisk).Do()
	if err != nil {
		return err
	}

	d.SetId(fmt.Sprintf("projects/%s/zones/%s/instances/%s/%s", zv.Project, zv.Zone, zv.Name, diskName))

	waitErr := computeOperationWaitTime(config, op, zv.Project,
		"disk to attach", d.Timeout(schema.TimeoutCreate))
	if waitErr != nil {
		d.SetId("")
		return waitErr
	}

	return resourceAttachedDiskRead(d, meta)
}

func resourceAttachedDiskRead(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	zv, err := parseZonalFieldValue("instances", d.Get("instance").(string), "project", "zone", d, config, false)
	if err != nil {
		return err
	}
	d.Set("project", zv.Project)
	d.Set("zone", zv.Zone)

	diskName := GetResourceNameFromSelfLink(d.Get("disk").(string))

	instance, err := config.clientCompute.Instances.Get(zv.Project, zv.Zone, zv.Name).Do()
	if err != nil {
		return handleNotFoundError(err, d, fmt.Sprintf("AttachedDisk %q", d.Id()))
	}

	// Iterate through the instance's attached disks as this is the only way to
	// confirm the disk is actually attached
	ad := findDiskByName(instance.Disks, diskName)
	if ad == nil {
		log.Printf("[WARN] Referenced disk wasn't found attached to this compute instance. Removing from state.")
		d.SetId("")
		return nil
	}

	d.Set("device_name", ad.DeviceName)
	d.Set("mode", ad.Mode)

	// Force the referenced resources to a self-link in state because it's more specific then name.
	instancePath, err := getRelativePath(instance.SelfLink)
	if err != nil {
		return err
	}
	d.Set("instance", instancePath)
	diskPath, err := getRelativePath(ad.Source)
	if err != nil {
		return err
	}
	d.Set("disk", diskPath)

	return nil
}

func resourceAttachedDiskDelete(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	zv, err := parseZonalFieldValue("instances", d.Get("instance").(string), "project", "zone", d, config, false)
	if err != nil {
		return err
	}

	diskName := GetResourceNameFromSelfLink(d.Get("disk").(string))

	instance, err := config.clientCompute.Instances.Get(zv.Project, zv.Zone, zv.Name).Do()
	if err != nil {
		return err
	}

	// Confirm the disk is still attached before making the call to detach it. If the disk isn't listed as an attached
	// disk on the compute instance then return as though the delete call succeed since this is the desired state.
	ad := findDiskByName(instance.Disks, diskName)
	if ad == nil {
		return nil
	}

	op, err := config.clientCompute.Instances.DetachDisk(zv.Project, zv.Zone, zv.Name, ad.DeviceName).Do()
	if err != nil {
		return err
	}

	waitErr := computeOperationWaitTime(config, op, zv.Project,
		fmt.Sprintf("Detaching disk from %s", zv.Name), d.Timeout(schema.TimeoutDelete))
	if waitErr != nil {
		return waitErr
	}

	return nil
}

func resourceAttachedDiskImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
	config := meta.(*Config)

	err := parseImportId(
		[]string{"projects/(?P<project>[^/]+)/zones/(?P<zone>[^/]+)/instances/(?P<instance>[^/]+)/(?P<disk>[^/]+)",
			"(?P<project>[^/]+)/(?P<zone>[^/]+)/(?P<instance>[^/]+)/(?P<disk>[^/]+)"}, d, config)
	if err != nil {
		return nil, err
	}

	id, err := replaceVars(d, config, "projects/{{project}}/zones/{{zone}}/instances/{{instance}}/{{disk}}")
	if err != nil {
		return nil, err
	}
	d.SetId(id)

	return []*schema.ResourceData{d}, nil
}

func findDiskByName(disks []*compute.AttachedDisk, id string) *compute.AttachedDisk {
	for _, disk := range disks {
		if compareSelfLinkOrResourceName("", disk.Source, id, nil) {
			return disk
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"syscall"

	"bufio"
	"github.com/rgbkrk/libvirt-go"
	"html"
	"strings"
)

func main() {
	xmlPath := flag.String("domain-path", "/var/run/virt-launcher/dom.xml", "Where to look for the domain xml.")
	downwardAPIPath := flag.String("downward-api-path", "", "Load domain from this downward API file")
	conUri := flag.String("libvirt-uri", "qemu:///system", "Libvirt connection string.")
	user := flag.String("user", "vdsm@ovirt", "Libvirt user")
	pass := flag.String("pass", "shibboleth", "Libvirt password")
	flag.Parse()

	xml := readDomainXML(*xmlPath, *downwardAPIPath)
	if xml == "" {
		log.Fatal("Could not load domain XML. The resulting XML is empty")
	}
	log.Print("Domain description loaded.")

	conn := buildLocalConnection(*conUri, *user, *pass)
	log.Print("Libvirt connection established.")

	defer func() {
		if res, _ := conn.CloseConnection(); res != 0 {
			log.Fatalf("CloseConnection() == %d, expected 0", res)
		}
	}()

	// Launch VM
	dom, createErr := conn.DomainCreateXML(xml, 0)
	if createErr != nil {
		log.Fatal(createErr)
	}
	log.Print("Domain started.")

	// Wait for termination
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt,
		syscall.SIGHUP,
		syscall.SIGINT,
		syscall.SIGTERM,
		syscall.SIGQUIT,
	)

	log.Print("Waiting forever ...")
	s := <-c
	log.Print("Got signal:", s)

	destroyErr := dom.Destroy()
	if destroyErr != nil {
		log.Fatal(destroyErr)
	}
	log.Print("Domain destroyed.")
}

func readDomainXML(xmlPath string, downwardAPIPath string) string {
	var xml string

	if downwardAPIPath == "" {
		log.Print("Loading Domain from XML file.")
		rawXML, err := ioutil.ReadFile(xmlPath)
		if err != nil {
			log.Fatal(err)
		}
		xml = string(rawXML)
	} else {
		log.Print("Loading Domain from downward API file.")
		f, err := os.Open(downwardAPIPath)
		if err != nil {
			log.Fatal(err)
		}
		defer f.Close()
		scanner := bufio.NewScanner(f)
		for scanner.Scan() {
			line := scanner.Text()
			if strings.HasPrefix(line, `domainXML="`) {
				xml = DecodeDomainXML(strings.Trim(strings.TrimPrefix(line, "domainXML="), `"`))
			}
		}

	}

	return xml
}

func buildLocalConnection(uri string, user string, pass string) libvirt.VirConnection {
	conn, err := libvirt.NewVirConnectionWithAuth(uri, user, pass)
	if err != nil {
		panic(err)
	}
	return conn
}

func DecodeDomainXML(domainXML string) string {
	decodedXML := html.UnescapeString(string(domainXML))
	decodedXML = strings.Replace(decodedXML, "\\\\", "\\", -1)
	decodedXML = strings.Replace(decodedXML, "\\n", "\n", -1)
	return decodedXML
}
<commit_msg>virt-launcher: reorganize the flow<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"syscall"

	"bufio"
	"github.com/rgbkrk/libvirt-go"
	"html"
	"strings"
)

type virtlauncher struct {
	domainXML  string
	domainUUID string
	connURI    string
	user       string
	pass       string
}

func main() {
	xmlPath := flag.String("domain-path", "/var/run/virt-launcher/dom.xml", "Where to look for the domain xml.")
	downwardAPIPath := flag.String("downward-api-path", "", "Load domain from this downward API file")
	conUri := flag.String("libvirt-uri", "qemu:///system", "Libvirt connection string.")
	user := flag.String("user", "vdsm@ovirt", "Libvirt user")
	pass := flag.String("pass", "shibboleth", "Libvirt password")
	flag.Parse()

	launcher := virtlauncher{
		connURI: *conUri,
		user:    *user,
		pass:    *pass,
	}

	launcher.ReadDomainXML(*xmlPath, *downwardAPIPath)
	launcher.CreateDomain()
	waitUntilSignal()
	launcher.DestroyDomain()
}

func (vl *virtlauncher) CreateDomain() {
	conn, err := libvirt.NewVirConnectionWithAuth(vl.connURI, vl.user, vl.pass)
	if err != nil {
		panic(fmt.Sprintf("Could not connect to libvirt using %s: %s", vl.connURI, err))
	}
	defer func() {
		if _, closeErr := conn.CloseConnection(); closeErr != nil {
			log.Fatalf("CloseConnection() failed: %s", closeErr)
		}
		log.Print("Connection closed")
	}()

	log.Print("Libvirt connection established")

	// Launch VM
	dom, err := conn.DomainCreateXML(vl.domainXML, 0)
	if err != nil {
		panic(fmt.Sprintf("Could not create the libvirt domain: %s", err))
	}

	vl.domainUUID, err = dom.GetUUIDString()
	if err != nil {
		panic(fmt.Sprintf("Could not get the domain UUID (as string): %s", err))
	}

	log.Print("Domain started")
}

func (vl *virtlauncher) DestroyDomain() {
	conn, err := libvirt.NewVirConnectionWithAuth(vl.connURI, vl.user, vl.pass)
	if err != nil {
		panic(fmt.Sprintf("Could not connect to libvirt using %s: %s", vl.connURI, err))
	}
	defer func() {
		if closeRes, _ := conn.CloseConnection(); closeRes != 0 {
			log.Fatalf("CloseConnection() == %d, expected 0", closeRes)
		}
		log.Print("Connection closed")
	}()

	log.Print("Libvirt connection established")

	dom, err := conn.LookupByUUIDString(vl.domainUUID)
	if err != nil {
		panic(fmt.Sprintf("Could not find domain %s: %s", vl.domainUUID, err))
	}

	err = dom.Destroy()
	if err != nil {
		panic(fmt.Sprintf("Domain destroy failed: %s", err))
	}

	log.Print("Domain destroyed")

}

func waitUntilSignal() {
	// Wait for termination
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt,
		syscall.SIGHUP,
		syscall.SIGINT,
		syscall.SIGTERM,
		syscall.SIGQUIT,
	)

	log.Printf("Waiting forever...")
	s := <-c
	log.Print("Got signal: ", s)
}

func (vl *virtlauncher) ReadDomainXML(xmlPath string, downwardAPIPath string) {
	if downwardAPIPath == "" {
		log.Print("Loading Domain from XML file")
		rawXML, err := ioutil.ReadFile(xmlPath)
		if err != nil {
			log.Fatal(err)
		}
		vl.domainXML = string(rawXML)
	} else {
		log.Print("Loading Domain from downward API file")
		f, err := os.Open(downwardAPIPath)
		if err != nil {
			log.Fatal(err)
		}
		defer f.Close()
		scanner := bufio.NewScanner(f)
		for scanner.Scan() {
			line := scanner.Text()
			if strings.HasPrefix(line, `domainXML="`) {
				vl.domainXML = DecodeDomainXML(strings.Trim(strings.TrimPrefix(line, "domainXML="), `"`))
			}
		}

	}

	if vl.domainXML == "" {
		panic("Could not load domain XML. The resulting XML is empty")
	}
	log.Print("Domain description loaded.")
}

func DecodeDomainXML(domainXML string) string {
	decodedXML := html.UnescapeString(string(domainXML))
	decodedXML = strings.Replace(decodedXML, "\\\\", "\\", -1)
	decodedXML = strings.Replace(decodedXML, "\\n", "\n", -1)
	return decodedXML
}
<|endoftext|>


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

package ebiten

import (
	"github.com/hajimehoshi/ebiten/internal/clock"
	"github.com/hajimehoshi/ebiten/internal/hooks"
	"github.com/hajimehoshi/ebiten/internal/restorable"
	"github.com/hajimehoshi/ebiten/internal/ui"
	"github.com/hajimehoshi/ebiten/internal/web"
)

func newGraphicsContext(f func(*Image) error) *graphicsContext {
	return &graphicsContext{
		f: f,
	}
}

type graphicsContext struct {
	f           func(*Image) error
	offscreen   *Image
	screen      *Image
	initialized bool
	invalidated bool // browser only
	offsetX     float64
	offsetY     float64
}

func (c *graphicsContext) Invalidate() {
	// Note that this is called only on browsers so far.
	// TODO: On mobiles, this function is not called and instead IsTexture is called
	// to detect if the context is lost. This is simple but might not work on some platforms.
	// Should Invalidate be called explicitly?
	c.invalidated = true
}

func (c *graphicsContext) SetSize(screenWidth, screenHeight int, screenScale float64) {
	if c.screen != nil {
		_ = c.screen.Dispose()
	}
	if c.offscreen != nil {
		_ = c.offscreen.Dispose()
	}
	offscreen := newVolatileImage(screenWidth, screenHeight, FilterDefault)

	w := int(float64(screenWidth) * screenScale)
	h := int(float64(screenHeight) * screenScale)
	px0, py0, _, _ := ui.ScreenPadding()
	c.screen = newImageWithScreenFramebuffer(w, h)
	_ = c.screen.Clear()

	c.offscreen = offscreen

	c.offsetX = px0
	c.offsetY = py0
}

func (c *graphicsContext) initializeIfNeeded() error {
	if !c.initialized {
		if err := restorable.InitializeGLState(); err != nil {
			return err
		}
		c.initialized = true
	}
	if err := c.restoreIfNeeded(); err != nil {
		return err
	}
	return nil
}

func (c *graphicsContext) Update(afterFrameUpdate func()) error {
	updateCount := clock.Update()

	if err := c.initializeIfNeeded(); err != nil {
		return err
	}
	for i := 0; i < updateCount; i++ {
		restorable.ClearVolatileImages()
		setRunningSlowly(i < updateCount-1)
		if err := hooks.Run(); err != nil {
			return err
		}
		if err := c.f(c.offscreen); err != nil {
			return err
		}
		afterFrameUpdate()
	}
	if 0 < updateCount {
		// Call ClearFramebuffer instead of c.screen.Clear()
		// to clear the whole region including fullscreen's padding.
		c.screen.restorable.ClearFramebuffer()

		dw, dh := c.screen.Size()
		sw, _ := c.offscreen.Size()
		scale := float64(dw) / float64(sw)

		op := &DrawImageOptions{}

		// c.screen is special: its Y axis is down to up,
		// and the origin point is lower left.
		op.GeoM.Scale(scale, -scale)
		op.GeoM.Translate(0, float64(dh))
		op.GeoM.Translate(c.offsetX, c.offsetY)

		op.CompositeMode = CompositeModeCopy
		op.Filter = filterScreen
		_ = c.screen.DrawImage(c.offscreen, op)
	}

	if err := restorable.ResolveStaleImages(); err != nil {
		return err
	}
	return nil
}

func (c *graphicsContext) needsRestoring() (bool, error) {
	if web.IsBrowser() {
		return c.invalidated, nil
	}
	return c.offscreen.restorable.IsInvalidated()
}

func (c *graphicsContext) restoreIfNeeded() error {
	if !restorable.IsRestoringEnabled() {
		return nil
	}
	r, err := c.needsRestoring()
	if err != nil {
		return err
	}
	if !r {
		return nil
	}
	if err := restorable.Restore(); err != nil {
		return err
	}
	c.invalidated = false
	return nil
}
<commit_msg>graphics: Bug fix: a too old frame was rendered at least on Android<commit_after>// Copyright 2014 Hajime Hoshi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package ebiten

import (
	"github.com/hajimehoshi/ebiten/internal/clock"
	"github.com/hajimehoshi/ebiten/internal/hooks"
	"github.com/hajimehoshi/ebiten/internal/restorable"
	"github.com/hajimehoshi/ebiten/internal/ui"
	"github.com/hajimehoshi/ebiten/internal/web"
)

func newGraphicsContext(f func(*Image) error) *graphicsContext {
	return &graphicsContext{
		f: f,
	}
}

type graphicsContext struct {
	f           func(*Image) error
	offscreen   *Image
	screen      *Image
	initialized bool
	invalidated bool // browser only
	offsetX     float64
	offsetY     float64
}

func (c *graphicsContext) Invalidate() {
	// Note that this is called only on browsers so far.
	// TODO: On mobiles, this function is not called and instead IsTexture is called
	// to detect if the context is lost. This is simple but might not work on some platforms.
	// Should Invalidate be called explicitly?
	c.invalidated = true
}

func (c *graphicsContext) SetSize(screenWidth, screenHeight int, screenScale float64) {
	if c.screen != nil {
		_ = c.screen.Dispose()
	}
	if c.offscreen != nil {
		_ = c.offscreen.Dispose()
	}
	offscreen := newVolatileImage(screenWidth, screenHeight, FilterDefault)

	w := int(float64(screenWidth) * screenScale)
	h := int(float64(screenHeight) * screenScale)
	px0, py0, _, _ := ui.ScreenPadding()
	c.screen = newImageWithScreenFramebuffer(w, h)
	_ = c.screen.Clear()

	c.offscreen = offscreen

	c.offsetX = px0
	c.offsetY = py0
}

func (c *graphicsContext) initializeIfNeeded() error {
	if !c.initialized {
		if err := restorable.InitializeGLState(); err != nil {
			return err
		}
		c.initialized = true
	}
	if err := c.restoreIfNeeded(); err != nil {
		return err
	}
	return nil
}

func (c *graphicsContext) Update(afterFrameUpdate func()) error {
	updateCount := clock.Update()

	if err := c.initializeIfNeeded(); err != nil {
		return err
	}
	for i := 0; i < updateCount; i++ {
		restorable.ClearVolatileImages()
		setRunningSlowly(i < updateCount-1)
		if err := hooks.Run(); err != nil {
			return err
		}
		if err := c.f(c.offscreen); err != nil {
			return err
		}
		afterFrameUpdate()
	}

	// Call ClearFramebuffer instead of c.screen.Clear()
	// to clear the whole region including fullscreen's padding.
	c.screen.restorable.ClearFramebuffer()

	dw, dh := c.screen.Size()
	sw, _ := c.offscreen.Size()
	scale := float64(dw) / float64(sw)

	op := &DrawImageOptions{}

	// c.screen is special: its Y axis is down to up,
	// and the origin point is lower left.
	op.GeoM.Scale(scale, -scale)
	op.GeoM.Translate(0, float64(dh))
	op.GeoM.Translate(c.offsetX, c.offsetY)

	op.CompositeMode = CompositeModeCopy
	op.Filter = filterScreen
	_ = c.screen.DrawImage(c.offscreen, op)

	if err := restorable.ResolveStaleImages(); err != nil {
		return err
	}
	return nil
}

func (c *graphicsContext) needsRestoring() (bool, error) {
	if web.IsBrowser() {
		return c.invalidated, nil
	}
	return c.offscreen.restorable.IsInvalidated()
}

func (c *graphicsContext) restoreIfNeeded() error {
	if !restorable.IsRestoringEnabled() {
		return nil
	}
	r, err := c.needsRestoring()
	if err != nil {
		return err
	}
	if !r {
		return nil
	}
	if err := restorable.Restore(); err != nil {
		return err
	}
	c.invalidated = false
	return nil
}
<|endoftext|>


<commit_before>package keys

const (
	Backspace = 8
	Return    = 10
	Up        = 14
	Left      = 17
	Right     = 18
	Escape    = 27
	Down      = 128

	Copy  = 61795 // cmd-c
	Save  = 61811 // cmd-s
	Paste = 61814 // cmd-v
	Cut   = 61816 // cmd-x
	Redo  = 61817 // cmd-y
	Undo  = 61818 // cmd-z
)
<commit_msg>keys: fix arrow keys on osx<commit_after>package keys

const (
	Backspace = 8
	Return    = 10
	Escape    = 27
	Down      = 128

	// TODO: is this a bug coming from plan9port, or from the plan9 Go package?
	Up    = 61454
	Left  = 61457
	Right = 61458

	Copy  = 61795 // cmd-c
	Save  = 61811 // cmd-s
	Paste = 61814 // cmd-v
	Cut   = 61816 // cmd-x
	Redo  = 61817 // cmd-y
	Undo  = 61818 // cmd-z
)
<|endoftext|>


<commit_before>package kitsu

import (
	"io/ioutil"
	"net/url"
	"testing"
)

func TestNewClient(t *testing.T) {
	c := NewClient(nil)

	if got, want := c.BaseURL.String(), defaultBaseURL; got != want {
		t.Errorf("NewClient BaseURL is %v, want %v", got, want)
	}
}

func TestClient_NewRequest(t *testing.T) {
	c := NewClient(nil)

	inURL, outURL := "/foo", defaultBaseURL+"foo"
	inBody, outBody := &struct{ Foo string }{Foo: "bar"}, `{"Foo":"bar"}`+"\n"
	req, _ := c.NewRequest("GET", inURL, inBody)

	// Test that the client's base URL is added to the endpoint.
	if got, want := req.URL.String(), outURL; got != want {
		t.Errorf("NewRequest(%q) URL is %q, want %q", inURL, got, want)
	}

	// Test that body gets encoded to JSON.
	body, _ := ioutil.ReadAll(req.Body)
	if got, want := string(body), outBody; got != want {
		t.Errorf("NewRequest(%#v) Body is \n%q, want \n%q", inBody, got, want)
	}

	// Test that the correct Content-Type gets added.
	if got, want := req.Header.Get("Content-Type"), defaultMediaType; got != want {
		t.Errorf("NewRequest() Content-Type is %q, want %q", got, want)
	}
}

func TestClient_NewRequest_badURL(t *testing.T) {
	c := NewClient(nil)
	inURL := ":"
	_, err := c.NewRequest("GET", inURL, nil)
	if err == nil {
		t.Errorf("NewRequest(%q) should return parse err", inURL)
	}
	if err, ok := err.(*url.Error); !ok || err.Op != "parse" {
		t.Errorf("Expected URL parse error, got %+v", err)
	}
}
<commit_msg>Add tests for NewRequest with bad and empty body<commit_after>package kitsu

import (
	"encoding/json"
	"io/ioutil"
	"net/url"
	"testing"
)

func TestNewClient(t *testing.T) {
	c := NewClient(nil)

	if got, want := c.BaseURL.String(), defaultBaseURL; got != want {
		t.Errorf("NewClient BaseURL is %v, want %v", got, want)
	}
}

func TestClient_NewRequest(t *testing.T) {
	c := NewClient(nil)

	inURL, outURL := "/foo", defaultBaseURL+"foo"
	inBody, outBody := &struct{ Foo string }{Foo: "bar"}, `{"Foo":"bar"}`+"\n"
	req, _ := c.NewRequest("GET", inURL, inBody)

	// Test that the client's base URL is added to the endpoint.
	if got, want := req.URL.String(), outURL; got != want {
		t.Errorf("NewRequest(%q) URL is %q, want %q", inURL, got, want)
	}

	// Test that body gets encoded to JSON.
	body, _ := ioutil.ReadAll(req.Body)
	if got, want := string(body), outBody; got != want {
		t.Errorf("NewRequest(%#v) Body is \n%q, want \n%q", inBody, got, want)
	}

	// Test that the correct Content-Type gets added.
	if got, want := req.Header.Get("Content-Type"), defaultMediaType; got != want {
		t.Errorf("NewRequest() Content-Type is %q, want %q", got, want)
	}
}

func TestClient_NewRequest_badURL(t *testing.T) {
	c := NewClient(nil)
	inURL := ":"
	_, err := c.NewRequest("GET", inURL, nil)
	if err == nil {
		t.Errorf("NewRequest(%q) should return parse err", inURL)
	}
	if err, ok := err.(*url.Error); !ok || err.Op != "parse" {
		t.Errorf("Expected URL parse error, got %+v", err)
	}
}

func TestClient_NewRequest_badBody(t *testing.T) {
	c := NewClient(nil)

	type Foo struct {
		Bar map[interface{}]interface{}
	}
	inBody := &Foo{}
	_, err := c.NewRequest("GET", "/", inBody)

	if err == nil {
		t.Errorf("NewRequest(%#v) should return err", inBody)
	}
	if err, ok := err.(*json.UnsupportedTypeError); !ok {
		t.Errorf("Expected JSON Unsupported type error, got %#v.", err)
	}
}

func TestClient_NewRequest_emptyBody(t *testing.T) {
	c := NewClient(nil)
	req, err := c.NewRequest("GET", "/", nil)
	if err != nil {
		t.Fatalf("NewRequest with empty body returned error: %v", err)
	}
	if req.Body != nil {
		t.Fatalf("NewRequest with empty body should construct request with nil Body")
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package discovery

import (
	"fmt"
	"sync"

	"k8s.io/kubernetes/pkg/api/errors"
	"k8s.io/kubernetes/pkg/api/meta"
	"k8s.io/kubernetes/pkg/api/unversioned"

	"github.com/golang/glog"
)

// APIGroupResources is an API group with a mapping of versions to
// resources.
type APIGroupResources struct {
	Group unversioned.APIGroup
	// A mapping of version string to a slice of APIResources for
	// that version.
	VersionedResources map[string][]unversioned.APIResource
}

// NewRESTMapper returns a PriorityRESTMapper based on the discovered
// groups and resources passed in.
func NewRESTMapper(groupResources []*APIGroupResources, versionInterfaces meta.VersionInterfacesFunc) meta.RESTMapper {
	unionMapper := meta.MultiRESTMapper{}

	var groupPriority []string
	var resourcePriority []unversioned.GroupVersionResource
	var kindPriority []unversioned.GroupVersionKind

	for _, group := range groupResources {
		groupPriority = append(groupPriority, group.Group.Name)

		if len(group.Group.PreferredVersion.Version) != 0 {
			preferred := group.Group.PreferredVersion.Version
			if _, ok := group.VersionedResources[preferred]; ok {
				resourcePriority = append(resourcePriority, unversioned.GroupVersionResource{
					Group:    group.Group.Name,
					Version:  group.Group.PreferredVersion.Version,
					Resource: meta.AnyResource,
				})

				kindPriority = append(kindPriority, unversioned.GroupVersionKind{
					Group:   group.Group.Name,
					Version: group.Group.PreferredVersion.Version,
					Kind:    meta.AnyKind,
				})
			}
		}

		for _, discoveryVersion := range group.Group.Versions {
			resources, ok := group.VersionedResources[discoveryVersion.Version]
			if !ok {
				continue
			}

			gv := unversioned.GroupVersion{Group: group.Group.Name, Version: discoveryVersion.Version}
			versionMapper := meta.NewDefaultRESTMapper([]unversioned.GroupVersion{gv}, versionInterfaces)

			for _, resource := range resources {
				scope := meta.RESTScopeNamespace
				if !resource.Namespaced {
					scope = meta.RESTScopeRoot
				}
				versionMapper.Add(gv.WithKind(resource.Kind), scope)
				// TODO only do this if it supports listing
				versionMapper.Add(gv.WithKind(resource.Kind+"List"), scope)
			}
			// TODO why is this type not in discovery (at least for "v1")
			versionMapper.Add(gv.WithKind("List"), meta.RESTScopeRoot)
			unionMapper = append(unionMapper, versionMapper)
		}
	}

	for _, group := range groupPriority {
		resourcePriority = append(resourcePriority, unversioned.GroupVersionResource{
			Group:    group,
			Version:  meta.AnyVersion,
			Resource: meta.AnyResource,
		})
		kindPriority = append(kindPriority, unversioned.GroupVersionKind{
			Group:   group,
			Version: meta.AnyVersion,
			Kind:    meta.AnyKind,
		})
	}

	return meta.PriorityRESTMapper{
		Delegate:         unionMapper,
		ResourcePriority: resourcePriority,
		KindPriority:     kindPriority,
	}
}

// GetAPIGroupResources uses the provided discovery client to gather
// discovery information and populate a slice of APIGroupResources.
func GetAPIGroupResources(cl DiscoveryInterface) ([]*APIGroupResources, error) {
	apiGroups, err := cl.ServerGroups()
	if err != nil {
		return nil, err
	}
	var result []*APIGroupResources
	for _, group := range apiGroups.Groups {
		groupResources := &APIGroupResources{
			Group:              group,
			VersionedResources: make(map[string][]unversioned.APIResource),
		}
		for _, version := range group.Versions {
			resources, err := cl.ServerResourcesForGroupVersion(version.GroupVersion)
			if err != nil {
				if errors.IsNotFound(err) {
					continue // ignore as this can race with deletion of 3rd party APIs
				}
				return nil, err
			}
			groupResources.VersionedResources[version.Version] = resources.APIResources
		}
		result = append(result, groupResources)
	}
	return result, nil
}

// DeferredDiscoveryRESTMapper is a RESTMapper that will defer
// initialization of the RESTMapper until the first mapping is
// requested.
type DeferredDiscoveryRESTMapper struct {
	initMu           sync.Mutex
	delegate         meta.RESTMapper
	cl               CachedDiscoveryInterface
	versionInterface meta.VersionInterfacesFunc
}

// NewDeferredDiscoveryRESTMapper returns a
// DeferredDiscoveryRESTMapper that will lazily query the provided
// client for discovery information to do REST mappings.
func NewDeferredDiscoveryRESTMapper(cl CachedDiscoveryInterface, versionInterface meta.VersionInterfacesFunc) *DeferredDiscoveryRESTMapper {
	return &DeferredDiscoveryRESTMapper{
		cl:               cl,
		versionInterface: versionInterface,
	}
}

func (d *DeferredDiscoveryRESTMapper) getDelegate() (meta.RESTMapper, error) {
	d.initMu.Lock()
	defer d.initMu.Unlock()

	if d.delegate != nil {
		return d.delegate, nil
	}

	groupResources, err := GetAPIGroupResources(d.cl)
	if err != nil {
		return nil, err
	}

	d.delegate = NewRESTMapper(groupResources, d.versionInterface)
	return d.delegate, err
}

// Reset resets the internally cached Discovery information and will
// cause the next mapping request to re-discover.
func (d *DeferredDiscoveryRESTMapper) Reset() {
	glog.V(5).Info("Invalidating discovery information")

	d.initMu.Lock()
	defer d.initMu.Unlock()

	d.cl.Invalidate()
	d.delegate = nil
}

// KindFor takes a partial resource and returns back the single match.
// It returns an error if there are multiple matches.
func (d *DeferredDiscoveryRESTMapper) KindFor(resource unversioned.GroupVersionResource) (gvk unversioned.GroupVersionKind, err error) {
	del, err := d.getDelegate()
	if err != nil {
		return unversioned.GroupVersionKind{}, err
	}
	gvk, err = del.KindFor(resource)
	if err != nil && !d.cl.Fresh() {
		d.Reset()
		gvk, err = d.KindFor(resource)
	}
	return
}

// KindsFor takes a partial resource and returns back the list of
// potential kinds in priority order.
func (d *DeferredDiscoveryRESTMapper) KindsFor(resource unversioned.GroupVersionResource) (gvks []unversioned.GroupVersionKind, err error) {
	del, err := d.getDelegate()
	if err != nil {
		return nil, err
	}
	gvks, err = del.KindsFor(resource)
	if len(gvks) == 0 && !d.cl.Fresh() {
		d.Reset()
		gvks, err = d.KindsFor(resource)
	}
	return
}

// ResourceFor takes a partial resource and returns back the single
// match. It returns an error if there are multiple matches.
func (d *DeferredDiscoveryRESTMapper) ResourceFor(input unversioned.GroupVersionResource) (gvr unversioned.GroupVersionResource, err error) {
	del, err := d.getDelegate()
	if err != nil {
		return unversioned.GroupVersionResource{}, err
	}
	gvr, err = del.ResourceFor(input)
	if err != nil && !d.cl.Fresh() {
		d.Reset()
		gvr, err = d.ResourceFor(input)
	}
	return
}

// ResourcesFor takes a partial resource and returns back the list of
// potential resource in priority order.
func (d *DeferredDiscoveryRESTMapper) ResourcesFor(input unversioned.GroupVersionResource) (gvrs []unversioned.GroupVersionResource, err error) {
	del, err := d.getDelegate()
	if err != nil {
		return nil, err
	}
	gvrs, err = del.ResourcesFor(input)
	if len(gvrs) == 0 && !d.cl.Fresh() {
		d.Reset()
		gvrs, err = d.ResourcesFor(input)
	}
	return
}

// RESTMapping identifies a preferred resource mapping for the
// provided group kind.
func (d *DeferredDiscoveryRESTMapper) RESTMapping(gk unversioned.GroupKind, versions ...string) (m *meta.RESTMapping, err error) {
	del, err := d.getDelegate()
	if err != nil {
		return nil, err
	}
	m, err = del.RESTMapping(gk, versions...)
	if err != nil && !d.cl.Fresh() {
		d.Reset()
		m, err = d.RESTMapping(gk, versions...)
	}
	return
}

// RESTMappings returns the RESTMappings for the provided group kind
// in a rough internal preferred order. If no kind is found, it will
// return a NoResourceMatchError.
func (d *DeferredDiscoveryRESTMapper) RESTMappings(gk unversioned.GroupKind) (ms []*meta.RESTMapping, err error) {
	del, err := d.getDelegate()
	if err != nil {
		return nil, err
	}
	ms, err = del.RESTMappings(gk)
	if len(ms) == 0 && !d.cl.Fresh() {
		d.Reset()
		ms, err = d.RESTMappings(gk)
	}
	return
}

// AliasesForResource returns whether a resource has an alias or not.
func (d *DeferredDiscoveryRESTMapper) AliasesForResource(resource string) (as []string, ok bool) {
	del, err := d.getDelegate()
	if err != nil {
		return nil, false
	}
	as, ok = del.AliasesForResource(resource)
	if len(as) == 0 && !d.cl.Fresh() {
		d.Reset()
		as, ok = d.AliasesForResource(resource)
	}
	return
}

// ResourceSingularizer converts a resource name from plural to
// singular (e.g., from pods to pod).
func (d *DeferredDiscoveryRESTMapper) ResourceSingularizer(resource string) (singular string, err error) {
	del, err := d.getDelegate()
	if err != nil {
		return resource, err
	}
	singular, err = del.ResourceSingularizer(resource)
	if err != nil && !d.cl.Fresh() {
		d.Reset()
		singular, err = d.ResourceSingularizer(resource)
	}
	return
}

func (d *DeferredDiscoveryRESTMapper) String() string {
	del, err := d.getDelegate()
	if err != nil {
		return fmt.Sprintf("DeferredDiscoveryRESTMapper{%v}", err)
	}
	return fmt.Sprintf("DeferredDiscoveryRESTMapper{\n\t%v\n}", del)
}

// Make sure it satisfies the interface
var _ meta.RESTMapper = &DeferredDiscoveryRESTMapper{}
<commit_msg>UPSTREAM: 42275: discovery restmapping should always prefer /v1<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package discovery

import (
	"fmt"
	"sync"

	"k8s.io/kubernetes/pkg/api/errors"
	"k8s.io/kubernetes/pkg/api/meta"
	"k8s.io/kubernetes/pkg/api/unversioned"

	"github.com/golang/glog"
)

// APIGroupResources is an API group with a mapping of versions to
// resources.
type APIGroupResources struct {
	Group unversioned.APIGroup
	// A mapping of version string to a slice of APIResources for
	// that version.
	VersionedResources map[string][]unversioned.APIResource
}

// NewRESTMapper returns a PriorityRESTMapper based on the discovered
// groups and resources passed in.
func NewRESTMapper(groupResources []*APIGroupResources, versionInterfaces meta.VersionInterfacesFunc) meta.RESTMapper {
	unionMapper := meta.MultiRESTMapper{}

	var groupPriority []string
	// /v1 is special.  It should always come first
	resourcePriority := []unversioned.GroupVersionResource{{Group: "", Version: "v1", Resource: meta.AnyResource}}
	kindPriority := []unversioned.GroupVersionKind{{Group: "", Version: "v1", Kind: meta.AnyKind}}

	for _, group := range groupResources {
		groupPriority = append(groupPriority, group.Group.Name)

		if len(group.Group.PreferredVersion.Version) != 0 {
			preferred := group.Group.PreferredVersion.Version
			if _, ok := group.VersionedResources[preferred]; ok {
				resourcePriority = append(resourcePriority, unversioned.GroupVersionResource{
					Group:    group.Group.Name,
					Version:  group.Group.PreferredVersion.Version,
					Resource: meta.AnyResource,
				})

				kindPriority = append(kindPriority, unversioned.GroupVersionKind{
					Group:   group.Group.Name,
					Version: group.Group.PreferredVersion.Version,
					Kind:    meta.AnyKind,
				})
			}
		}

		for _, discoveryVersion := range group.Group.Versions {
			resources, ok := group.VersionedResources[discoveryVersion.Version]
			if !ok {
				continue
			}

			gv := unversioned.GroupVersion{Group: group.Group.Name, Version: discoveryVersion.Version}
			versionMapper := meta.NewDefaultRESTMapper([]unversioned.GroupVersion{gv}, versionInterfaces)

			for _, resource := range resources {
				scope := meta.RESTScopeNamespace
				if !resource.Namespaced {
					scope = meta.RESTScopeRoot
				}
				versionMapper.Add(gv.WithKind(resource.Kind), scope)
				// TODO only do this if it supports listing
				versionMapper.Add(gv.WithKind(resource.Kind+"List"), scope)
			}
			// TODO why is this type not in discovery (at least for "v1")
			versionMapper.Add(gv.WithKind("List"), meta.RESTScopeRoot)
			unionMapper = append(unionMapper, versionMapper)
		}
	}

	for _, group := range groupPriority {
		resourcePriority = append(resourcePriority, unversioned.GroupVersionResource{
			Group:    group,
			Version:  meta.AnyVersion,
			Resource: meta.AnyResource,
		})
		kindPriority = append(kindPriority, unversioned.GroupVersionKind{
			Group:   group,
			Version: meta.AnyVersion,
			Kind:    meta.AnyKind,
		})
	}

	return meta.PriorityRESTMapper{
		Delegate:         unionMapper,
		ResourcePriority: resourcePriority,
		KindPriority:     kindPriority,
	}
}

// GetAPIGroupResources uses the provided discovery client to gather
// discovery information and populate a slice of APIGroupResources.
func GetAPIGroupResources(cl DiscoveryInterface) ([]*APIGroupResources, error) {
	apiGroups, err := cl.ServerGroups()
	if err != nil {
		return nil, err
	}
	var result []*APIGroupResources
	for _, group := range apiGroups.Groups {
		groupResources := &APIGroupResources{
			Group:              group,
			VersionedResources: make(map[string][]unversioned.APIResource),
		}
		for _, version := range group.Versions {
			resources, err := cl.ServerResourcesForGroupVersion(version.GroupVersion)
			if err != nil {
				if errors.IsNotFound(err) {
					continue // ignore as this can race with deletion of 3rd party APIs
				}
				return nil, err
			}
			groupResources.VersionedResources[version.Version] = resources.APIResources
		}
		result = append(result, groupResources)
	}
	return result, nil
}

// DeferredDiscoveryRESTMapper is a RESTMapper that will defer
// initialization of the RESTMapper until the first mapping is
// requested.
type DeferredDiscoveryRESTMapper struct {
	initMu           sync.Mutex
	delegate         meta.RESTMapper
	cl               CachedDiscoveryInterface
	versionInterface meta.VersionInterfacesFunc
}

// NewDeferredDiscoveryRESTMapper returns a
// DeferredDiscoveryRESTMapper that will lazily query the provided
// client for discovery information to do REST mappings.
func NewDeferredDiscoveryRESTMapper(cl CachedDiscoveryInterface, versionInterface meta.VersionInterfacesFunc) *DeferredDiscoveryRESTMapper {
	return &DeferredDiscoveryRESTMapper{
		cl:               cl,
		versionInterface: versionInterface,
	}
}

func (d *DeferredDiscoveryRESTMapper) getDelegate() (meta.RESTMapper, error) {
	d.initMu.Lock()
	defer d.initMu.Unlock()

	if d.delegate != nil {
		return d.delegate, nil
	}

	groupResources, err := GetAPIGroupResources(d.cl)
	if err != nil {
		return nil, err
	}

	d.delegate = NewRESTMapper(groupResources, d.versionInterface)
	return d.delegate, err
}

// Reset resets the internally cached Discovery information and will
// cause the next mapping request to re-discover.
func (d *DeferredDiscoveryRESTMapper) Reset() {
	glog.V(5).Info("Invalidating discovery information")

	d.initMu.Lock()
	defer d.initMu.Unlock()

	d.cl.Invalidate()
	d.delegate = nil
}

// KindFor takes a partial resource and returns back the single match.
// It returns an error if there are multiple matches.
func (d *DeferredDiscoveryRESTMapper) KindFor(resource unversioned.GroupVersionResource) (gvk unversioned.GroupVersionKind, err error) {
	del, err := d.getDelegate()
	if err != nil {
		return unversioned.GroupVersionKind{}, err
	}
	gvk, err = del.KindFor(resource)
	if err != nil && !d.cl.Fresh() {
		d.Reset()
		gvk, err = d.KindFor(resource)
	}
	return
}

// KindsFor takes a partial resource and returns back the list of
// potential kinds in priority order.
func (d *DeferredDiscoveryRESTMapper) KindsFor(resource unversioned.GroupVersionResource) (gvks []unversioned.GroupVersionKind, err error) {
	del, err := d.getDelegate()
	if err != nil {
		return nil, err
	}
	gvks, err = del.KindsFor(resource)
	if len(gvks) == 0 && !d.cl.Fresh() {
		d.Reset()
		gvks, err = d.KindsFor(resource)
	}
	return
}

// ResourceFor takes a partial resource and returns back the single
// match. It returns an error if there are multiple matches.
func (d *DeferredDiscoveryRESTMapper) ResourceFor(input unversioned.GroupVersionResource) (gvr unversioned.GroupVersionResource, err error) {
	del, err := d.getDelegate()
	if err != nil {
		return unversioned.GroupVersionResource{}, err
	}
	gvr, err = del.ResourceFor(input)
	if err != nil && !d.cl.Fresh() {
		d.Reset()
		gvr, err = d.ResourceFor(input)
	}
	return
}

// ResourcesFor takes a partial resource and returns back the list of
// potential resource in priority order.
func (d *DeferredDiscoveryRESTMapper) ResourcesFor(input unversioned.GroupVersionResource) (gvrs []unversioned.GroupVersionResource, err error) {
	del, err := d.getDelegate()
	if err != nil {
		return nil, err
	}
	gvrs, err = del.ResourcesFor(input)
	if len(gvrs) == 0 && !d.cl.Fresh() {
		d.Reset()
		gvrs, err = d.ResourcesFor(input)
	}
	return
}

// RESTMapping identifies a preferred resource mapping for the
// provided group kind.
func (d *DeferredDiscoveryRESTMapper) RESTMapping(gk unversioned.GroupKind, versions ...string) (m *meta.RESTMapping, err error) {
	del, err := d.getDelegate()
	if err != nil {
		return nil, err
	}
	m, err = del.RESTMapping(gk, versions...)
	if err != nil && !d.cl.Fresh() {
		d.Reset()
		m, err = d.RESTMapping(gk, versions...)
	}
	return
}

// RESTMappings returns the RESTMappings for the provided group kind
// in a rough internal preferred order. If no kind is found, it will
// return a NoResourceMatchError.
func (d *DeferredDiscoveryRESTMapper) RESTMappings(gk unversioned.GroupKind) (ms []*meta.RESTMapping, err error) {
	del, err := d.getDelegate()
	if err != nil {
		return nil, err
	}
	ms, err = del.RESTMappings(gk)
	if len(ms) == 0 && !d.cl.Fresh() {
		d.Reset()
		ms, err = d.RESTMappings(gk)
	}
	return
}

// AliasesForResource returns whether a resource has an alias or not.
func (d *DeferredDiscoveryRESTMapper) AliasesForResource(resource string) (as []string, ok bool) {
	del, err := d.getDelegate()
	if err != nil {
		return nil, false
	}
	as, ok = del.AliasesForResource(resource)
	if len(as) == 0 && !d.cl.Fresh() {
		d.Reset()
		as, ok = d.AliasesForResource(resource)
	}
	return
}

// ResourceSingularizer converts a resource name from plural to
// singular (e.g., from pods to pod).
func (d *DeferredDiscoveryRESTMapper) ResourceSingularizer(resource string) (singular string, err error) {
	del, err := d.getDelegate()
	if err != nil {
		return resource, err
	}
	singular, err = del.ResourceSingularizer(resource)
	if err != nil && !d.cl.Fresh() {
		d.Reset()
		singular, err = d.ResourceSingularizer(resource)
	}
	return
}

func (d *DeferredDiscoveryRESTMapper) String() string {
	del, err := d.getDelegate()
	if err != nil {
		return fmt.Sprintf("DeferredDiscoveryRESTMapper{%v}", err)
	}
	return fmt.Sprintf("DeferredDiscoveryRESTMapper{\n\t%v\n}", del)
}

// Make sure it satisfies the interface
var _ meta.RESTMapper = &DeferredDiscoveryRESTMapper{}
<|endoftext|>


<commit_before>package main

import (
	"strings"
	// "encoding/json"
	"io/ioutil"
	// "os"
	"path/filepath"
	"testing"
)

func TestRewriteUrlsInJson(t *testing.T) {

	of, err := ioutil.TempFile("", "renamer-test")
	defer of.Close()
	if err != nil {
		t.Fatal(err)
	}

	var (
		in     = filepath.Join(Cwd(), "fixtures", "cms.strong.json")
		out    = of.Name()
		rel    = "/images"
		needle = "https://drive.google.com/file/d/"
	)

	r := Renamer{
		in,
		out,
		rel,
		needle,
	}

	if err = r.Run(); err != nil {
		t.Fatal(err)
	}

	got, err := ioutil.ReadFile(r.out)
	want, err := ioutil.ReadFile(r.in)
	println(string(got))
	println(string(want))

	if strings.TrimSpace(string(got)) != strings.TrimSpace(string(want)) {
		t.Fatal("in does not equal out")
	}

}
<commit_msg>add passing test want vs got json in renamer<commit_after>package main

import (
	"github.com/clbanning/mxj"
	"io/ioutil"
	"path/filepath"
	"reflect"
	"testing"
)

func TestRewriteUrlsInJson(t *testing.T) {

	of, err := ioutil.TempFile("", "renamer-test")
	defer of.Close()
	if err != nil {
		t.Fatal(err)
	}

	var (
		in     = filepath.Join(Cwd(), "fixtures", "cms.strong.json")
		out    = of.Name()
		rel    = "/images"
		needle = "https://drive.google.com/file/d/"
	)

	r := Renamer{
		in,
		out,
		rel,
		needle,
	}

	if err = r.Run(); err != nil {
		t.Fatal(err)
	}

	got, err := ioutil.ReadFile(r.out)
	want, err := ioutil.ReadFile(r.in)

	gotMap, err := mxj.NewMapJson(got)
	wantMap, err := mxj.NewMapJson(want)

	if !reflect.DeepEqual(gotMap, wantMap) {
		t.Fatal("want does not equal got")
	}

	// v, err := m.ValuesForKey("nophotos")
	// println(v[0].(string))
}
<|endoftext|>


<commit_before>package git

import (
	"container/list"
)

type HistoryWalkerAction int

const (
	// drop commit and do not follow parents
	HWDrop HistoryWalkerAction = 0
	// takes commit but not traverses parents
	HWTakeCommit HistoryWalkerAction = 1 << iota
	// drops commit but traverses parents
	HWFollowParents
	// stops traverse
	HWStop

	// take and follow
	HWTakeAndFollow = HWTakeCommit | HWFollowParents
)

type CommitWalkCallback func(*Commit) (HistoryWalkerAction, error)

type CommitComparator func(left, right *Commit) bool

func walkHistory(start *Commit, callback CommitWalkCallback) (*list.List, error) {
	return walkHistoryLoop([]*Commit{start}, callback, commitRootComparator)
}

func walkFilteredHistory(start *Commit, callback CommitWalkCallback, eq CommitComparator) (*list.List, error) {
	return walkHistoryLoop([]*Commit{start}, callback, eq)
}

// we gurantee that roots are not equal to each other
func walkHistoryLoop(roots []*Commit, callback CommitWalkCallback, eq CommitComparator) (*list.List, error) {
	results := list.New()
	seen := make(map[sha1]struct{})

	for {
		if len(roots) == 0 {
			return results, nil
		}

		var err error

		roots, err = simplifyRoots(roots, eq, seen)
		if err != nil {
			return nil, err
		}

		var next *Commit
		next, roots = extractNewestCommit(roots)

		action, err := callback(next)
		if err != nil {
			return nil, err
		}

		if action&HWTakeCommit > 0 {
			// witness commit
			results.PushBack(next)
			seen[next.Id] = struct{}{}
		}

		if action&HWFollowParents > 0 {
			// follow all parents of commit
			pars, err := parents(next)
			if err != nil {
				return nil, err
			}
			roots = mergeRoots(pars, roots, eq, seen)
		}

		if action&HWStop > 0 {
			return results, nil
		}
	}

	return results, nil
}

func parents(commit *Commit) ([]*Commit, error) {
	parents := make([]*Commit, commit.ParentCount())
	for idx := 0; idx < len(parents); idx++ {
		var err error
		parents[idx], err = commit.Parent(idx)
		if err != nil {
			return nil, err
		}
	}
	return parents, nil
}

func mergeRoots(base, merging []*Commit, eq CommitComparator, seen map[sha1]struct{}) []*Commit {
	newRoots := append([]*Commit(nil), base...)
	for _, needle := range merging {
		found := false
		for _, item := range base {
			if eq(needle, item) {
				// found equal commit in merging roots
				// drop it and mark as seen
				seen[needle.Id] = struct{}{}
				found = true
				break
			}
		}

		if !found {
			// commit is unique enough
			newRoots = append(newRoots, needle)
		}
	}

	return newRoots
}

func skipEqualCommits(commit *Commit, eq CommitComparator, seen map[sha1]struct{}) (*Commit, error) {
	for {
		// we already seen that commit, no point to traverse further
		if _, ok := seen[commit.Id]; ok {
			return nil, nil
		}

		if len(commit.parents) == 0 {
			return commit, nil
		}

		var found bool
		for idx := 0; idx < commit.ParentCount(); idx++ {
			parent, err := commit.Parent(idx)
			if err != nil {
				return nil, err
			}

			if eq(commit, parent) {
				// we have parent that equals to given commit
				// so take this parent as next commit (dropping current)
				// but we will remember that we seen current commit in history
				seen[commit.Id] = struct{}{}
				commit = parent
				found = true
				break
			}
		}

		// all parents of commit was not same to it, so return this commit
		if !found {
			return commit, nil
		}
	}
}

func simplifyRoots(roots []*Commit, eq CommitComparator, seen map[sha1]struct{}) ([]*Commit, error) {
	newRoots := []*Commit{}
	for _, commit := range roots {
		commit, err := skipEqualCommits(commit, eq, seen)
		if err != nil {
			return nil, err
		}
		if commit != nil {
			newRoots = append(newRoots, commit)
		}
	}

	return newRoots, nil
}

func extractNewestCommit(roots []*Commit) (*Commit, []*Commit) {
	if len(roots) == 1 {
		return roots[0], roots[:0]
	}

	target := roots[0]
	targetIdx := 0
	for idx, current := range roots[1:] {
		if current.Committer.When.After(target.Committer.When) {
			target = current
			targetIdx = idx
		}
	}

	// remove picked commit
	roots = append(roots[:targetIdx], roots[targetIdx+1:]...)

	return target, roots
}
<commit_msg>cleanup: add some comments and force 100 column<commit_after>package git

import (
	"container/list"
)

type HistoryWalkerAction int

const (
	// drop commit and do not follow parents
	HWDrop HistoryWalkerAction = 0
	// take commit but not traverse parents
	HWTakeCommit HistoryWalkerAction = 1 << iota
	// drop commit but traverse parents
	HWFollowParents
	// stop traverse
	HWStop

	// take commit and follow parents
	HWTakeAndFollow = HWTakeCommit | HWFollowParents
)

type CommitWalkCallback func(*Commit) (HistoryWalkerAction, error)

// CommitComparator defines callback type for checking commit equalty. If it returns true then
// commits are considered equal. See "History Simplification" chapter of git-log man for details
type CommitComparator func(current, parent *Commit) bool

func walkHistory(start *Commit, callback CommitWalkCallback) (*list.List, error) {
	return walkHistoryLoop([]*Commit{start}, callback, commitRootComparator)
}

func walkFilteredHistory(start *Commit, callback CommitWalkCallback,
	eq CommitComparator) (*list.List, error) {

	return walkHistoryLoop([]*Commit{start}, callback, eq)
}

// roots must be not equal to each other
func walkHistoryLoop(roots []*Commit, callback CommitWalkCallback,
	eq CommitComparator) (*list.List, error) {

	results := list.New()
	seen := make(map[sha1]struct{})

	for {
		if len(roots) == 0 {
			return results, nil
		}

		var err error

		roots, err = simplifyRoots(roots, eq, seen)
		if err != nil {
			return nil, err
		}

		var next *Commit
		next, roots = extractNewestCommit(roots)

		action, err := callback(next)
		if err != nil {
			return nil, err
		}

		if action&HWTakeCommit > 0 {
			// witness commit
			results.PushBack(next)
			seen[next.Id] = struct{}{}
		}

		if action&HWFollowParents > 0 {
			// follow all parents of commit
			pars, err := parents(next)
			if err != nil {
				return nil, err
			}
			roots = mergeRoots(pars, roots, eq, seen)
		}

		if action&HWStop > 0 {
			return results, nil
		}
	}

	return results, nil
}

func parents(commit *Commit) ([]*Commit, error) {
	parents := make([]*Commit, commit.ParentCount())
	for idx := 0; idx < len(parents); idx++ {
		var err error
		parents[idx], err = commit.Parent(idx)
		if err != nil {
			return nil, err
		}
	}
	return parents, nil
}

// mergeRoots will merge two sets of commits and ensure that they are not equal to each other
// the members of base and merging sets already nonequal to each other
func mergeRoots(base, merging []*Commit, eq CommitComparator, seen map[sha1]struct{}) []*Commit {
	newRoots := append([]*Commit(nil), base...)
	for _, needle := range merging {
		found := false
		for _, item := range base {
			if eq(needle, item) {
				// found equal commit in merging roots
				// drop it and mark as seen
				seen[needle.Id] = struct{}{}
				found = true
				break
			}
		}

		if !found {
			// commit is unique enough
			newRoots = append(newRoots, needle)
		}
	}

	return newRoots
}

// skipEqualCommits compares commit to it parents. If it finds a parent
// that equals to current commit the current commit will be dropped and parent will be followed
// see "History Simplification" chapter of git-log man for full details.
func skipEqualCommits(commit *Commit, eq CommitComparator,
	seen map[sha1]struct{}) (*Commit, error) {

	for {
		// we already seen that commit, no point to traverse further
		if _, ok := seen[commit.Id]; ok {
			return nil, nil
		}

		if len(commit.parents) == 0 {
			return commit, nil
		}

		var found bool
		for idx := 0; idx < commit.ParentCount(); idx++ {
			parent, err := commit.Parent(idx)
			if err != nil {
				return nil, err
			}

			if eq(commit, parent) {
				// we have parent that equals to given commit
				// so take this parent as next commit (dropping current)
				// but we will remember that we seen current commit in history
				seen[commit.Id] = struct{}{}
				commit = parent
				found = true
				break
			}
		}

		// all parents of commit was not same to it, so return this commit
		if !found {
			return commit, nil
		}
	}
}

func simplifyRoots(roots []*Commit, eq CommitComparator,
	seen map[sha1]struct{}) ([]*Commit, error) {

	newRoots := []*Commit{}
	for _, commit := range roots {
		commit, err := skipEqualCommits(commit, eq, seen)
		if err != nil {
			return nil, err
		}
		if commit != nil {
			newRoots = append(newRoots, commit)
		}
	}

	return newRoots, nil
}

// extractNewestCommit will find newest commit, extract it and return resulting set
func extractNewestCommit(roots []*Commit) (*Commit, []*Commit) {
	if len(roots) == 1 {
		return roots[0], roots[:0]
	}

	target := roots[0]
	targetIdx := 0
	for idx, current := range roots[1:] {
		if current.Committer.When.After(target.Committer.When) {
			target = current
			targetIdx = idx
		}
	}

	// remove picked commit
	roots = append(roots[:targetIdx], roots[targetIdx+1:]...)

	return target, roots
}
<|endoftext|>


<commit_before>package raygun4go

import (
	"net/http"
	"os"
	"time"

	"github.com/kaeuferportal/stack2struct"
)

// postData is the outmost element of the Raygun-REST-API
type postData struct {
	OccuredOn string      `json:"occurredOn"` // the time the error occured on, format 2006-01-02T15:04:05Z
	Details   detailsData `json:"details"`    // all the details needed by the API
}

// newPostData triggers the creation of and returns a postData-struct. It needs
// the configured context from the Client, the error and the corresponding
// stack trace.
func newPostData(context contextInformation, err error, stack stackTrace) postData {
	return postData{
		OccuredOn: time.Now().Format("2006-01-02T15:04:05Z"),
		Details:   newDetailsData(context, err, stack),
	}
}

// detailsData is the container holding all information regarding the more
// detailed circumstances the error occured in.
type detailsData struct {
	MachineName    string         `json:"machineName"`    // the machine's hostname
	Version        string         `json:"version"`        // the version from context
	Error          errorData      `json:"error"`          // everything we know about the error itself
	Tags           []string       `json:"tags"`           // the tags from context
	UserCustomData UserCustomData `json:"userCustomData"` // the custom data from the context
	Request        requestData    `json:"request"`        // the request from the context
	User           user           `json:"user"`           // the user from the context
	Context        context        `json:"context"`        // the identifier from the context
	Client         clientData     `json:"client"`         // information on this client
}

// newDetailsData returns a struct with all known details. It needs the context,
// the error and the stack trace.
func newDetailsData(c contextInformation, err error, stack stackTrace) detailsData {
	hostname, e := os.Hostname()
	if e != nil {
		hostname = "not available"
	}

	return detailsData{
		MachineName:    hostname,
		Version:        c.Version,
		Error:          newErrorData(err, stack),
		Tags:           c.Tags,
		UserCustomData: c.CustomData,
		Request:        newRequestData(c.Request),
		User:           user{c.User},
		Context:        context{c.Identifier()},
		Client:         clientData{"raygun4go", packageVersion, "https://github.com/kaeuferportal/raygun4go"},
	}
}

// errorData is the struct holding all technical information on the error.
type errorData struct {
	Message    string     `json:"message"`    // the actual message the error produced
	StackTrace stackTrace `json:"stackTrace"` // the error's stack trace
}

// newErrorData fills returns a struct with all the information known about the
// error.
func newErrorData(err error, s stackTrace) errorData {
	return errorData{
		Message:    err.Error(),
		StackTrace: s,
	}
}

// currentStac returns the current stack. However, it omits the first 3 entries
// to avoid cluttering the trace with raygun4go-specific calls.
func currentStack() stackTrace {
	s := make(stackTrace, 0, 0)
	stack2struct.Current(&s)
	return s[3:]
}

// stackTraceElement is one element of the error's stack trace. It is filled by
// stack2struct.
type stackTraceElement struct {
	LineNumber  int    `json:"lineNumber"`
	PackageName string `json:"className"`
	FileName    string `json:"fileName"`
	MethodName  string `json:"methodName"`
}

// stackTrace is the stack the trace will be parsed into.
type stackTrace []stackTraceElement

// AddEntry is the method used by stack2struct to dump parsed elements.
func (s *stackTrace) AddEntry(lineNumber int, packageName, fileName, methodName string) {
	*s = append(*s, stackTraceElement{lineNumber, packageName, fileName, methodName})
}

// requestData holds all information on the request from the context
type requestData struct {
	HostName    string            `json:"hostName"`
	Url         string            `json:"url"`
	HttpMethod  string            `json:"httpMethod"`
	IpAddress   string            `json:"ipAddress"`
	QueryString map[string]string `json:"queryString"` // key-value-pairs from the URI parameters
	Form        map[string]string `json:"form"`        // key-value-pairs from a given form (POST)
	Headers     map[string]string `json:"headers"`     // key-value-pairs from the header
}

// newRequestData parses all information from the request in the context to a
// struct. The struct is empty if no request was set.
func newRequestData(r *http.Request) requestData {
	if r == nil {
		return requestData{}
	}

	r.ParseForm()

	return requestData{
		HostName:    r.Host,
		Url:         r.URL.String(),
		HttpMethod:  r.Method,
		IpAddress:   r.RemoteAddr,
		QueryString: arrayMapToStringMap(r.URL.Query()),
		Form:        arrayMapToStringMap(r.PostForm),
		Headers:     arrayMapToStringMap(r.Header),
	}
}

// clientData is the struct holding information on this client.
type clientData struct {
	Name      string `json:"identifier"`
	Version   string `json:"version"`
	ClientUrl string `json:"clientUrl"`
}

// user holds information on the affected user.
type user struct {
	Identifier string `json:"identifier"`
}

// context holds information on the program context.
type context struct {
	Identifier string `json:"identifier"`
}

// UserCustomData is the interface that needs to be implemented by the custom
// data to be sent with the error. Being 'interface{}' suggests that it could
// be anything, but the data itself or contained data should respond to
// json.Marshal() for the data to be transmitted.
type UserCustomData interface{}
<commit_msg>update packageVersion to reflect new package name<commit_after>package raygun4go

import (
	"net/http"
	"os"
	"time"

	"github.com/kaeuferportal/stack2struct"
)

// postData is the outmost element of the Raygun-REST-API
type postData struct {
	OccuredOn string      `json:"occurredOn"` // the time the error occured on, format 2006-01-02T15:04:05Z
	Details   detailsData `json:"details"`    // all the details needed by the API
}

// newPostData triggers the creation of and returns a postData-struct. It needs
// the configured context from the Client, the error and the corresponding
// stack trace.
func newPostData(context contextInformation, err error, stack stackTrace) postData {
	return postData{
		OccuredOn: time.Now().Format("2006-01-02T15:04:05Z"),
		Details:   newDetailsData(context, err, stack),
	}
}

// detailsData is the container holding all information regarding the more
// detailed circumstances the error occured in.
type detailsData struct {
	MachineName    string         `json:"machineName"`    // the machine's hostname
	Version        string         `json:"version"`        // the version from context
	Error          errorData      `json:"error"`          // everything we know about the error itself
	Tags           []string       `json:"tags"`           // the tags from context
	UserCustomData UserCustomData `json:"userCustomData"` // the custom data from the context
	Request        requestData    `json:"request"`        // the request from the context
	User           user           `json:"user"`           // the user from the context
	Context        context        `json:"context"`        // the identifier from the context
	Client         clientData     `json:"client"`         // information on this client
}

// newDetailsData returns a struct with all known details. It needs the context,
// the error and the stack trace.
func newDetailsData(c contextInformation, err error, stack stackTrace) detailsData {
	hostname, e := os.Hostname()
	if e != nil {
		hostname = "not available"
	}

	return detailsData{
		MachineName:    hostname,
		Version:        c.Version,
		Error:          newErrorData(err, stack),
		Tags:           c.Tags,
		UserCustomData: c.CustomData,
		Request:        newRequestData(c.Request),
		User:           user{c.User},
		Context:        context{c.Identifier()},
		Client:         clientData{"raygun4go", packageVersion, "https://github.com/MindscapeHQ/raygun4go"},
	}
}

// errorData is the struct holding all technical information on the error.
type errorData struct {
	Message    string     `json:"message"`    // the actual message the error produced
	StackTrace stackTrace `json:"stackTrace"` // the error's stack trace
}

// newErrorData fills returns a struct with all the information known about the
// error.
func newErrorData(err error, s stackTrace) errorData {
	return errorData{
		Message:    err.Error(),
		StackTrace: s,
	}
}

// currentStac returns the current stack. However, it omits the first 3 entries
// to avoid cluttering the trace with raygun4go-specific calls.
func currentStack() stackTrace {
	s := make(stackTrace, 0, 0)
	stack2struct.Current(&s)
	return s[3:]
}

// stackTraceElement is one element of the error's stack trace. It is filled by
// stack2struct.
type stackTraceElement struct {
	LineNumber  int    `json:"lineNumber"`
	PackageName string `json:"className"`
	FileName    string `json:"fileName"`
	MethodName  string `json:"methodName"`
}

// stackTrace is the stack the trace will be parsed into.
type stackTrace []stackTraceElement

// AddEntry is the method used by stack2struct to dump parsed elements.
func (s *stackTrace) AddEntry(lineNumber int, packageName, fileName, methodName string) {
	*s = append(*s, stackTraceElement{lineNumber, packageName, fileName, methodName})
}

// requestData holds all information on the request from the context
type requestData struct {
	HostName    string            `json:"hostName"`
	Url         string            `json:"url"`
	HttpMethod  string            `json:"httpMethod"`
	IpAddress   string            `json:"ipAddress"`
	QueryString map[string]string `json:"queryString"` // key-value-pairs from the URI parameters
	Form        map[string]string `json:"form"`        // key-value-pairs from a given form (POST)
	Headers     map[string]string `json:"headers"`     // key-value-pairs from the header
}

// newRequestData parses all information from the request in the context to a
// struct. The struct is empty if no request was set.
func newRequestData(r *http.Request) requestData {
	if r == nil {
		return requestData{}
	}

	r.ParseForm()

	return requestData{
		HostName:    r.Host,
		Url:         r.URL.String(),
		HttpMethod:  r.Method,
		IpAddress:   r.RemoteAddr,
		QueryString: arrayMapToStringMap(r.URL.Query()),
		Form:        arrayMapToStringMap(r.PostForm),
		Headers:     arrayMapToStringMap(r.Header),
	}
}

// clientData is the struct holding information on this client.
type clientData struct {
	Name      string `json:"identifier"`
	Version   string `json:"version"`
	ClientUrl string `json:"clientUrl"`
}

// user holds information on the affected user.
type user struct {
	Identifier string `json:"identifier"`
}

// context holds information on the program context.
type context struct {
	Identifier string `json:"identifier"`
}

// UserCustomData is the interface that needs to be implemented by the custom
// data to be sent with the error. Being 'interface{}' suggests that it could
// be anything, but the data itself or contained data should respond to
// json.Marshal() for the data to be transmitted.
type UserCustomData interface{}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"sort"
	"strings"
)

var (
	asc          = false
	desc         = true
	sortOrderMap = map[string]string{
		"mode": "asc",
		"time": "asc",
		"size": "asc",
		"name": "asc",
	}
)

type sortable struct {
	Infos *[]os.FileInfo
	Key   string
	Order bool
}

func xnor(a, b bool) bool { return !((a || b) && (!a || !b)) }

func (s sortable) Len() int { return len(*s.Infos) }
func (s sortable) Less(i, j int) bool {
	switch s.Key {
	case "mode":
		return xnor((*s.Infos)[i].Mode() > (*s.Infos)[j].Mode(), s.Order)
	case "time":
		return xnor((*s.Infos)[i].ModTime().After((*s.Infos)[j].ModTime()), s.Order)
	case "size":
		return xnor((*s.Infos)[i].Size() > (*s.Infos)[j].Size(), s.Order)
	default:
		return xnor((*s.Infos)[i].Name() > (*s.Infos)[j].Name(), s.Order)
	}
	return xnor((*s.Infos)[i].Name() > (*s.Infos)[j].Name(), s.Order)
}
func (s sortable) Swap(i, j int) { (*s.Infos)[i], (*s.Infos)[j] = (*s.Infos)[j], (*s.Infos)[i] }

func readDir(dirname string, sortby string, order bool) ([]os.FileInfo, error) {
	f, err := os.Open(dirname)
	if err != nil {
		return nil, err
	}
	list, err := f.Readdir(-1)
	f.Close()
	if err != nil {
		return nil, err
	}
	sort.Sort(sortable{&list, sortby, order})
	return list, nil
}

func isProtected(level string, auth string) bool {
	levels := strings.Split(auth, ",")
	for _, x := range levels {
		if x == level {
			return true
		}
	}
	return false
}
<commit_msg>fixed go vet issue<commit_after>package main

import (
	"os"
	"sort"
	"strings"
)

var (
	asc          = false
	desc         = true
	sortOrderMap = map[string]string{
		"mode": "asc",
		"time": "asc",
		"size": "asc",
		"name": "asc",
	}
)

type sortable struct {
	Infos *[]os.FileInfo
	Key   string
	Order bool
}

func xnor(a, b bool) bool { return !((a || b) && (!a || !b)) }

func (s sortable) Len() int { return len(*s.Infos) }
func (s sortable) Less(i, j int) bool {
	switch s.Key {
	case "mode":
		return xnor((*s.Infos)[i].Mode() > (*s.Infos)[j].Mode(), s.Order)
	case "time":
		return xnor((*s.Infos)[i].ModTime().After((*s.Infos)[j].ModTime()), s.Order)
	case "size":
		return xnor((*s.Infos)[i].Size() > (*s.Infos)[j].Size(), s.Order)
	default:
		return xnor((*s.Infos)[i].Name() > (*s.Infos)[j].Name(), s.Order)
	}
}
func (s sortable) Swap(i, j int) { (*s.Infos)[i], (*s.Infos)[j] = (*s.Infos)[j], (*s.Infos)[i] }

func readDir(dirname string, sortby string, order bool) ([]os.FileInfo, error) {
	f, err := os.Open(dirname)
	if err != nil {
		return nil, err
	}
	list, err := f.Readdir(-1)
	f.Close()
	if err != nil {
		return nil, err
	}
	sort.Sort(sortable{&list, sortby, order})
	return list, nil
}

func isProtected(level string, auth string) bool {
	levels := strings.Split(auth, ",")
	for _, x := range levels {
		if x == level {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"time"

	"github.com/andelf/go-curl"
	"github.com/nu7hatch/gouuid"
)

type Config struct {
	Location        string
	ChecksUrl       string
	MeasurementsUrl string
}

type check struct {
	Id  string `json:"id"`
	Url string `json:"url"`
}

type measurement struct {
	Check             check   `json:"check"`
	Id                string  `json:"id"`
	CheckId           string  `json:"check_id"`
	Location          string  `json:"location"`
	Url               string  `json:"url"`
	T                 int     `json:"t"`
	ExitStatus        int     `json:"exit_status"`
	ConnectTime       float64 `json:"connect_time,omitempty"`
	StartTransferTime float64 `json:"starttransfer_time,omitempty"`
	LocalIp           string  `json:"local_ip,omitempty"`
	PrimaryIp         string  `json:"primary_ip,omitempty"`
	TotalTime         float64 `json:"total_time,omitempty"`
	HttpStatus        int     `json:"http_status,omitempty"`
	NameLookupTime    float64 `json:"namelookup_time,omitempty"`
}

func GetEnvWithDefault(env string, def string) string {
	tmp := os.Getenv(env)

	if tmp == "" {
		return def
	}

	return tmp
}

func measure(config Config, c check) measurement {
	var m measurement

	id, _ := uuid.NewV4()
	m.Id = id.String()
	m.CheckId = c.Id
	m.Location = config.Location

	easy := curl.EasyInit()
	defer easy.Cleanup()

	easy.Setopt(curl.OPT_URL, c.Url)

	m.Url = c.Url

	// dummy func for curl output
	noOut := func(buf []byte, userdata interface{}) bool {
		return true
	}

	easy.Setopt(curl.OPT_WRITEFUNCTION, noOut)
	easy.Setopt(curl.OPT_CONNECTTIMEOUT, 10)
	easy.Setopt(curl.OPT_TIMEOUT, 10)

	now := time.Now()
	m.T = int(now.Unix())

	if err := easy.Perform(); err != nil {
		if e, ok := err.(curl.CurlError); ok {
			m.ExitStatus = (int(e))
			return m
		}
		os.Exit(1)
	}

	m.ExitStatus = 0
	http_status, _ := easy.Getinfo(curl.INFO_RESPONSE_CODE)
	m.HttpStatus = http_status.(int)

	connect_time, _ := easy.Getinfo(curl.INFO_CONNECT_TIME)
	m.ConnectTime = connect_time.(float64)

	namelookup_time, _ := easy.Getinfo(curl.INFO_NAMELOOKUP_TIME)
	m.NameLookupTime = namelookup_time.(float64)

	starttransfer_time, _ := easy.Getinfo(curl.INFO_STARTTRANSFER_TIME)
	m.StartTransferTime = starttransfer_time.(float64)

	total_time, _ := easy.Getinfo(curl.INFO_TOTAL_TIME)
	m.TotalTime = total_time.(float64)

	local_ip, _ := easy.Getinfo(curl.INFO_LOCAL_IP)
	m.LocalIp = local_ip.(string)

	primary_ip, _ := easy.Getinfo(curl.INFO_PRIMARY_IP)
	m.PrimaryIp = primary_ip.(string)

	return m
}

func measurer(config Config, checks chan check, measurements chan measurement) {
	for {
		c := <-checks
		m := measure(config, c)

		measurements <- m
	}
}

func recorder(config Config, measurements chan measurement) {
	payload := make([]measurement, 0, 100)
	for {
		m := <-measurements
		payload = append(payload, m)

		s, err := json.Marshal(&payload)
		if err != nil {
			panic(err)
		}

		body := bytes.NewBuffer(s)
		req, err := http.NewRequest("POST", config.MeasurementsUrl, body)
		if err != nil {
			panic(err)
		}

		req.Header.Add("Content-Type", "application/json")
		resp, err := http.DefaultClient.Do(req)
		if err != nil {
			panic(err)
		}
		resp.Body.Close()
		payload = make([]measurement, 0, 100)

		fmt.Println(resp)
	}
}

func get_checks(config Config) []check {
	url := config.ChecksUrl

	res, err := http.Get(url)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

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

	var checks []check
	err = json.Unmarshal(body, &checks)
	if err != nil {
		panic(err)
	}

	return checks
}

func main() {
	var config Config
	config.Location = GetEnvWithDefault("LOCATION", "undefined")
	config.ChecksUrl = GetEnvWithDefault("CHECKS_URL", "https://s3.amazonaws.com/canary-public-data/data.json")
	config.MeasurementsUrl = GetEnvWithDefault("MEASUREMENTS_URL", "http://localhost:5000/measurements")

	fmt.Printf("%s\n", config.MeasurementsUrl)

	check_list := get_checks(config)

	checks := make(chan check)
	measurements := make(chan measurement)

	go measurer(config, checks, measurements)
	go recorder(config, measurements)

	for {
		for _, c := range check_list {
			checks <- c
		}

		time.Sleep(1000 * time.Millisecond)
	}
}
<commit_msg>add the check during measurement<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"time"

	"github.com/andelf/go-curl"
	"github.com/nu7hatch/gouuid"
)

type Config struct {
	Location        string
	ChecksUrl       string
	MeasurementsUrl string
}

type check struct {
	Id  string `json:"id"`
	Url string `json:"url"`
}

type measurement struct {
	Check             check   `json:"check"`
	Id                string  `json:"id"`
	CheckId           string  `json:"check_id"`
	Location          string  `json:"location"`
	Url               string  `json:"url"`
	T                 int     `json:"t"`
	ExitStatus        int     `json:"exit_status"`
	ConnectTime       float64 `json:"connect_time,omitempty"`
	StartTransferTime float64 `json:"starttransfer_time,omitempty"`
	LocalIp           string  `json:"local_ip,omitempty"`
	PrimaryIp         string  `json:"primary_ip,omitempty"`
	TotalTime         float64 `json:"total_time,omitempty"`
	HttpStatus        int     `json:"http_status,omitempty"`
	NameLookupTime    float64 `json:"namelookup_time,omitempty"`
}

func GetEnvWithDefault(env string, def string) string {
	tmp := os.Getenv(env)

	if tmp == "" {
		return def
	}

	return tmp
}

func measure(config Config, c check) measurement {
	var m measurement

	id, _ := uuid.NewV4()
	m.Id = id.String()
	m.Check = c
	m.CheckId = c.Id
	m.Location = config.Location

	easy := curl.EasyInit()
	defer easy.Cleanup()

	easy.Setopt(curl.OPT_URL, c.Url)

	m.Url = c.Url

	// dummy func for curl output
	noOut := func(buf []byte, userdata interface{}) bool {
		return true
	}

	easy.Setopt(curl.OPT_WRITEFUNCTION, noOut)
	easy.Setopt(curl.OPT_CONNECTTIMEOUT, 10)
	easy.Setopt(curl.OPT_TIMEOUT, 10)

	now := time.Now()
	m.T = int(now.Unix())

	if err := easy.Perform(); err != nil {
		if e, ok := err.(curl.CurlError); ok {
			m.ExitStatus = (int(e))
			return m
		}
		os.Exit(1)
	}

	m.ExitStatus = 0
	http_status, _ := easy.Getinfo(curl.INFO_RESPONSE_CODE)
	m.HttpStatus = http_status.(int)

	connect_time, _ := easy.Getinfo(curl.INFO_CONNECT_TIME)
	m.ConnectTime = connect_time.(float64)

	namelookup_time, _ := easy.Getinfo(curl.INFO_NAMELOOKUP_TIME)
	m.NameLookupTime = namelookup_time.(float64)

	starttransfer_time, _ := easy.Getinfo(curl.INFO_STARTTRANSFER_TIME)
	m.StartTransferTime = starttransfer_time.(float64)

	total_time, _ := easy.Getinfo(curl.INFO_TOTAL_TIME)
	m.TotalTime = total_time.(float64)

	local_ip, _ := easy.Getinfo(curl.INFO_LOCAL_IP)
	m.LocalIp = local_ip.(string)

	primary_ip, _ := easy.Getinfo(curl.INFO_PRIMARY_IP)
	m.PrimaryIp = primary_ip.(string)

	return m
}

func measurer(config Config, checks chan check, measurements chan measurement) {
	for {
		c := <-checks
		m := measure(config, c)

		measurements <- m
	}
}

func recorder(config Config, measurements chan measurement) {
	payload := make([]measurement, 0, 100)
	for {
		m := <-measurements
		payload = append(payload, m)

		s, err := json.Marshal(&payload)
		if err != nil {
			panic(err)
		}

		body := bytes.NewBuffer(s)
		req, err := http.NewRequest("POST", config.MeasurementsUrl, body)
		if err != nil {
			panic(err)
		}

		req.Header.Add("Content-Type", "application/json")
		resp, err := http.DefaultClient.Do(req)
		if err != nil {
			panic(err)
		}
		resp.Body.Close()
		payload = make([]measurement, 0, 100)

		fmt.Println(resp)
	}
}

func get_checks(config Config) []check {
	url := config.ChecksUrl

	res, err := http.Get(url)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

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

	var checks []check
	err = json.Unmarshal(body, &checks)
	if err != nil {
		panic(err)
	}

	return checks
}

func main() {
	var config Config
	config.Location = GetEnvWithDefault("LOCATION", "undefined")
	config.ChecksUrl = GetEnvWithDefault("CHECKS_URL", "https://s3.amazonaws.com/canary-public-data/data.json")
	config.MeasurementsUrl = GetEnvWithDefault("MEASUREMENTS_URL", "http://localhost:5000/measurements")

	fmt.Printf("%s\n", config.MeasurementsUrl)

	check_list := get_checks(config)

	checks := make(chan check)
	measurements := make(chan measurement)

	go measurer(config, checks, measurements)
	go recorder(config, measurements)

	for {
		for _, c := range check_list {
			checks <- c
		}

		time.Sleep(1000 * time.Millisecond)
	}
}
<|endoftext|>