<commit_before>package storage

import (
	"io"

	"github.com/lxc/lxd/lxd/instance"
	"github.com/lxc/lxd/lxd/migration"
	"github.com/lxc/lxd/lxd/operations"
	"github.com/lxc/lxd/lxd/state"
	"github.com/lxc/lxd/lxd/storage/drivers"
	"github.com/lxc/lxd/shared/api"
)

// Pool represents a LXD storage pool.
type Pool interface {
	// Internal.
	DaemonState() *state.State

	// Pool.
	ID() int64
	Name() string
	Driver() drivers.Driver

	GetResources() (*api.ResourcesStoragePool, error)
	Delete(localOnly bool, op *operations.Operation) error

	Mount() (bool, error)
	Unmount() (bool, error)

	// Instances.
	CreateInstance(inst instance.Instance, op *operations.Operation) error
	CreateInstanceFromBackup(inst instance.Instance, sourcePath string, op *operations.Operation) error
	CreateInstanceFromCopy(inst instance.Instance, src instance.Instance, snapshots bool, op *operations.Operation) error
	CreateInstanceFromImage(inst instance.Instance, fingerprint string, op *operations.Operation) error
	CreateInstanceFromMigration(inst instance.Instance, conn io.ReadWriteCloser, args migration.VolumeTargetArgs, op *operations.Operation) error
	RenameInstance(inst instance.Instance, newName string, op *operations.Operation) error
	DeleteInstance(inst instance.Instance, op *operations.Operation) error

	MigrateInstance(inst instance.Instance, conn io.ReadWriteCloser, args migration.VolumeSourceArgs, op *operations.Operation) error
	RefreshInstance(inst instance.Instance, src instance.Instance, srcSnapshots []instance.Instance, op *operations.Operation) error
	BackupInstance(inst instance.Instance, targetPath string, optimized bool, snapshots bool, op *operations.Operation) error

	GetInstanceUsage(inst instance.Instance) (int64, error)
	SetInstanceQuota(inst instance.Instance, size string, op *operations.Operation) error

	MountInstance(inst instance.Instance, op *operations.Operation) (bool, error)
	UnmountInstance(inst instance.Instance, op *operations.Operation) (bool, error)
	GetInstanceDisk(inst instance.Instance) (string, error)

	// Instance snapshots.
	CreateInstanceSnapshot(inst instance.Instance, src instance.Instance, op *operations.Operation) error
	RenameInstanceSnapshot(inst instance.Instance, newName string, op *operations.Operation) error
	DeleteInstanceSnapshot(inst instance.Instance, op *operations.Operation) error
	RestoreInstanceSnapshot(inst instance.Instance, op *operations.Operation) error
	MountInstanceSnapshot(inst instance.Instance, op *operations.Operation) (bool, error)
	UnmountInstanceSnapshot(inst instance.Instance, op *operations.Operation) (bool, error)

	// Images.
	EnsureImage(fingerprint string, op *operations.Operation) error
	DeleteImage(fingerprint string, op *operations.Operation) error

	// Custom volumes.
	CreateCustomVolume(volName, desc string, config map[string]string, op *operations.Operation) error
	CreateCustomVolumeFromCopy(volName, desc string, config map[string]string, srcPoolName, srcVolName string, srcVolOnly bool, op *operations.Operation) error
	UpdateCustomVolume(volName, newDesc string, newConfig map[string]string, op *operations.Operation) error
	RenameCustomVolume(volName string, newVolName string, op *operations.Operation) error
	DeleteCustomVolume(volName string, op *operations.Operation) error
	GetCustomVolumeUsage(volName string) (int64, error)
	MountCustomVolume(volName string, op *operations.Operation) (bool, error)
	UnmountCustomVolume(volName string, op *operations.Operation) (bool, error)

	// Custom volume snapshots.
	CreateCustomVolumeSnapshot(volName string, newSnapshotName string, op *operations.Operation) error
	RenameCustomVolumeSnapshot(volName string, newSnapshotName string, op *operations.Operation) error
	DeleteCustomVolumeSnapshot(volName string, op *operations.Operation) error
	RestoreCustomVolume(volName string, snapshotName string, op *operations.Operation) error

	// Custom volume migration.
	MigrationTypes(contentType drivers.ContentType) []migration.Type
	CreateCustomVolumeFromMigration(conn io.ReadWriteCloser, args migration.VolumeTargetArgs, op *operations.Operation) error
	MigrateCustomVolume(conn io.ReadWriteCloser, args migration.VolumeSourceArgs, op *operations.Operation) error
}
<commit_msg>lxd/storage/interfaces: RestoreInstanceSnapshot signature<commit_after>package storage

import (
	"io"

	"github.com/lxc/lxd/lxd/instance"
	"github.com/lxc/lxd/lxd/migration"
	"github.com/lxc/lxd/lxd/operations"
	"github.com/lxc/lxd/lxd/state"
	"github.com/lxc/lxd/lxd/storage/drivers"
	"github.com/lxc/lxd/shared/api"
)

// Pool represents a LXD storage pool.
type Pool interface {
	// Internal.
	DaemonState() *state.State

	// Pool.
	ID() int64
	Name() string
	Driver() drivers.Driver

	GetResources() (*api.ResourcesStoragePool, error)
	Delete(localOnly bool, op *operations.Operation) error

	Mount() (bool, error)
	Unmount() (bool, error)

	// Instances.
	CreateInstance(inst instance.Instance, op *operations.Operation) error
	CreateInstanceFromBackup(inst instance.Instance, sourcePath string, op *operations.Operation) error
	CreateInstanceFromCopy(inst instance.Instance, src instance.Instance, snapshots bool, op *operations.Operation) error
	CreateInstanceFromImage(inst instance.Instance, fingerprint string, op *operations.Operation) error
	CreateInstanceFromMigration(inst instance.Instance, conn io.ReadWriteCloser, args migration.VolumeTargetArgs, op *operations.Operation) error
	RenameInstance(inst instance.Instance, newName string, op *operations.Operation) error
	DeleteInstance(inst instance.Instance, op *operations.Operation) error

	MigrateInstance(inst instance.Instance, conn io.ReadWriteCloser, args migration.VolumeSourceArgs, op *operations.Operation) error
	RefreshInstance(inst instance.Instance, src instance.Instance, srcSnapshots []instance.Instance, op *operations.Operation) error
	BackupInstance(inst instance.Instance, targetPath string, optimized bool, snapshots bool, op *operations.Operation) error

	GetInstanceUsage(inst instance.Instance) (int64, error)
	SetInstanceQuota(inst instance.Instance, size string, op *operations.Operation) error

	MountInstance(inst instance.Instance, op *operations.Operation) (bool, error)
	UnmountInstance(inst instance.Instance, op *operations.Operation) (bool, error)
	GetInstanceDisk(inst instance.Instance) (string, error)

	// Instance snapshots.
	CreateInstanceSnapshot(inst instance.Instance, src instance.Instance, op *operations.Operation) error
	RenameInstanceSnapshot(inst instance.Instance, newName string, op *operations.Operation) error
	DeleteInstanceSnapshot(inst instance.Instance, op *operations.Operation) error
	RestoreInstanceSnapshot(inst instance.Instance, src instance.Instance, op *operations.Operation) error
	MountInstanceSnapshot(inst instance.Instance, op *operations.Operation) (bool, error)
	UnmountInstanceSnapshot(inst instance.Instance, op *operations.Operation) (bool, error)

	// Images.
	EnsureImage(fingerprint string, op *operations.Operation) error
	DeleteImage(fingerprint string, op *operations.Operation) error

	// Custom volumes.
	CreateCustomVolume(volName, desc string, config map[string]string, op *operations.Operation) error
	CreateCustomVolumeFromCopy(volName, desc string, config map[string]string, srcPoolName, srcVolName string, srcVolOnly bool, op *operations.Operation) error
	UpdateCustomVolume(volName, newDesc string, newConfig map[string]string, op *operations.Operation) error
	RenameCustomVolume(volName string, newVolName string, op *operations.Operation) error
	DeleteCustomVolume(volName string, op *operations.Operation) error
	GetCustomVolumeUsage(volName string) (int64, error)
	MountCustomVolume(volName string, op *operations.Operation) (bool, error)
	UnmountCustomVolume(volName string, op *operations.Operation) (bool, error)

	// Custom volume snapshots.
	CreateCustomVolumeSnapshot(volName string, newSnapshotName string, op *operations.Operation) error
	RenameCustomVolumeSnapshot(volName string, newSnapshotName string, op *operations.Operation) error
	DeleteCustomVolumeSnapshot(volName string, op *operations.Operation) error
	RestoreCustomVolume(volName string, snapshotName string, op *operations.Operation) error

	// Custom volume migration.
	MigrationTypes(contentType drivers.ContentType) []migration.Type
	CreateCustomVolumeFromMigration(conn io.ReadWriteCloser, args migration.VolumeTargetArgs, op *operations.Operation) error
	MigrateCustomVolume(conn io.ReadWriteCloser, args migration.VolumeSourceArgs, op *operations.Operation) error
}
<|endoftext|>


<commit_before>/*MIT licence
(c) Jan Piskorski, Bartosz Deptuła, Mateusz Boruń
Wiktor Kacalski & Mikołaj Kordowski
*/

package main

import (
	//print
	"fmt"
	//pobieranie danych
	"bufio"
	"os"
	//operacje na słowach
	"strings"
	//pliki - na razie wystarczy os
	"io/ioutil"
)

func main() {
	fmt.Println("nano-ai 0.0.1")
	//zmienne
	var unprocQuery string
	var purpose int8
	//główna pętla
	for {
		unprocQuery = GetQuery()
		fmt.Println("------------------Informacje--------------------")
		if unprocQuery == "*quit" {
			os.Exit(1)
		}
		purpose = Querypurpose(unprocQuery)
		//typ qypowiedzi: 1 - inform.; 2- pyt. 3 - rozkaz
		println(purpose, unprocQuery)
		if purpose == 1 {
			addtodb(unprocQuery)
		}
		if purpose == 2 {
			dbcontents := Scandb()
			//fmt.Printf("%d\n", dbcontents)
			placeofq := strings.Index(unprocQuery, "*q")
			qprefix := unprocQuery[:placeofq]
			qsuffix := unprocQuery[(placeofq + 2):]
			//fmt.Print(string(placeofq), qprefix,"  ,  ", qsuffix)
			response := GrepIn(dbcontents, qprefix, qsuffix)
			fmt.Println("-----------------Info-koniec--------------------")
			fmt.Printf("%s\n", response[0])

		}
		//na razie wychodzi

	}
}

func GrepIn(contents []string, qprefix, qsuffix string) [16]string {
	var itHasPrefix [15]string
	var answers [16]string
	var pcount int8 = 0
	var acount int8 = 0

	for _, v := range contents {
		if strings.HasPrefix(v, qprefix) {
			//naprawienie błędu z pustymi możliwościami
			if strings.Trim(v, " ") != "" {
				fmt.Printf("GrepIn Prefix: %s\n", v)
				itHasPrefix[pcount] = v
				pcount = pcount + 1
			}
		}
	}
	for _, v := range itHasPrefix {
		if strings.HasSuffix(v, qsuffix) {
			//naprawienie błędu
			if strings.Trim(v, " ") != "" {
				fmt.Printf("GrepIn Suffix: %s\n", v)
				answers[acount] = v
				acount = acount + 1
			}
		}
	}
	//fmt.Printf("%d\n", answers)
	return answers
}
func GetQuery() string {
	var inp string
	fmt.Printf(";> ")
	//źródło to konsola
	scnr := bufio.NewScanner(os.Stdin)
	//skanujemy i wynik do zmiennej
	scnr.Scan()
	inp = scnr.Text()
	//fmt.Printf("%s\n", scnr.Text())
	return inp
}
func Scandb() []string {
	dat, err := ioutil.ReadFile("db1.txt")
	errorcheck(err)
	data := string(dat)
	//informatycznie odpowiednia długość wycinka
	lines := make([]string, 16383)
	lines = strings.Split(data, "\n")
	return lines
}
func Querypurpose(query string) int8 {
	var querytype int8 = 1
	//jak zawiera *q to jest pytaniem
	if strings.Contains(query, "*q") {
		querytype = 2
	}
	//jak zawiera request to jest rozkazem
	if strings.Contains(query, "*request") {
		querytype = 3
	}
	//jeśli nie zawiera żadnego z pow. to nadal =1
	return querytype

}
func addtodb(query string) {
	/*f, err := os.Create("db1.txt")
	  errorcheck(err)
	  d2 := []byte(query+"\n")
	  n2, err := f.Write(d2)
	  errorcheck(err)
	  fmt.Printf("wrote %d bytes\n", n2)
	  f.Close()*/
	// jako odczyt/zapis, dopisywanie, tworzy nowy plik jeżeli nie ma.
	f, err := os.OpenFile("db1.txt", os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
	defer f.Close()
	errorcheck(err)
	//zakodowanie linii
	d2 := []byte(query + "\n")
	//piszemy
	n2, err := f.Write(d2)
	errorcheck(err)
	defer fmt.Printf("wrote %d bytes\n", n2)
}

func errorcheck(e error) {
	if e != nil {
		panic(e)
	}
}
<commit_msg>Base for making synonymes<commit_after>/*MIT licence
(c) Jan Piskorski, Bartosz Deptuła, Mateusz Boruń
Wiktor Kacalski & Mikołaj Kordowski
*/

package main

import (
	//print
	"fmt"
	//pobieranie danych
	"bufio"
	"os"
	//operacje na słowach
	"strings"
	//pliki - na razie wystarczy os
	"io/ioutil"
)

func main() {
	fmt.Println("nano-ai 0.0.1")
	//zmienne
	var unprocQuery string
	var purpose int8
	//główna pętla
	for {
		unprocQuery = GetQuery()
		fmt.Println("------------------Informacje--------------------")
		if unprocQuery == "*quit" {
			os.Exit(1)
		}
		purpose = Querypurpose(unprocQuery)
		//typ qypowiedzi: 1 - inform.; 2- pyt. 3 - rozkaz
		println(purpose, unprocQuery)
		if purpose == 1 {
			addtodb(unprocQuery)
		}
		if purpose == 2 {
			dbcontents := Scandb()
			//fmt.Printf("%d\n", dbcontents)
			placeofq := strings.Index(unprocQuery, "*q")
			qprefix := unprocQuery[:placeofq]
			qsuffix := unprocQuery[(placeofq + 2):]
			//fmt.Print(string(placeofq), qprefix,"  ,  ", qsuffix)
			response := GrepIn(dbcontents, qprefix, qsuffix)
			fmt.Println("-----------------Info-koniec--------------------")
			fmt.Printf("%s\n", response[0])

		}
		//synonimy

	}
}

func GrepIn(contents []string, qprefix, qsuffix string) []string {
	var itHasPrefix := make([]string, 1, 16000)
	var answers := make([]string,1, 16001)
	var pcount int8 = 0
	var acount int8 = 0

	for _, v := range contents {
		if strings.HasPrefix(v, qprefix) {
			//naprawienie błędu z pustymi możliwościami
			if strings.Trim(v, " ") != "" {
				fmt.Printf("GrepIn Prefix: %s\n", v)
				itHasPrefix[pcount] = v
				pcount = pcount + 1
			}
		}
	}
	for _, v := range itHasPrefix {
		if strings.HasSuffix(v, qsuffix) {
			//naprawienie błędu
			if strings.Trim(v, " ") != "" {
				fmt.Printf("GrepIn Suffix: %s\n", v)
				answers[acount] = v
				acount = acount + 1
			}
		}
	}
	//fmt.Printf("%d\n", answers)
	return answers
}
func GetQuery() string {
	var inp string
	fmt.Printf(";> ")
	//źródło to konsola
	scnr := bufio.NewScanner(os.Stdin)
	//skanujemy i wynik do zmiennej
	scnr.Scan()
	inp = scnr.Text()
	//fmt.Printf("%s\n", scnr.Text())
	return inp
}
func Scandb() []string {
	dat, err := ioutil.ReadFile("db1.txt")
	errorcheck(err)
	data := string(dat)
	//informatycznie odpowiednia długość wycinka
	lines := make([]string, 16383)
	lines = strings.Split(data, "\n")
	return lines
}
func Querypurpose(query string) int8 {
	var querytype int8 = 1
	//jak zawiera *q to jest pytaniem
	if strings.Contains(query, "*q") {
		querytype = 2
	}
	//jak zawiera request to jest rozkazem
	if strings.Contains(query, "*request") {
		querytype = 3
	}
	//jeśli nie zawiera żadnego z pow. to nadal =1
	return querytype

}
func addtodb(query string) {
	/*f, err := os.Create("db1.txt")
	  errorcheck(err)
	  d2 := []byte(query+"\n")
	  n2, err := f.Write(d2)
	  errorcheck(err)
	  fmt.Printf("wrote %d bytes\n", n2)
	  f.Close()*/
	// jako odczyt/zapis, dopisywanie, tworzy nowy plik jeżeli nie ma.
	f, err := os.OpenFile("db1.txt", os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
	defer f.Close()
	errorcheck(err)
	//zakodowanie linii
	d2 := []byte(query + "\n")
	//piszemy
	n2, err := f.Write(d2)
	errorcheck(err)
	defer fmt.Printf("wrote %d bytes\n", n2)
}

/*
func FindAnalogical(query SlicedQuery) []string {
	abvc
}
func BaseWordOf(word string) string {
	abc
}
func RemoveSynonymes(query SlicedQuery) SlicedQuery {
	abc
}
func AddSynonyme(word, base string) {
	abc
}
func GrepForSynonymes {
	abc
}
type SlicedQuery struct {
	obj, verb, subject string
}

*/

func errorcheck(e error) {
	if e != nil {
		panic(e)
	}
}
<|endoftext|>


<commit_before>/*
(BSD 2-clause license)

Copyright (c) 2014, Shawn Webb
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

   * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package network

import (
    "fmt"
    "strconv"
    "errors"
    "strings"
    "os/exec"
    "encoding/json"
    "github.com/coopernurse/gorp"
    "github.com/virtbsd/VirtualMachine"
    "github.com/virtbsd/util"
    "github.com/nu7hatch/gouuid"
)

type NetworkPhysical struct {
    NetworkPhysicalID int
    NetworkUUID string
    Device string
}

type DeviceAddress struct {
    DeviceAddressID int
    DeviceUUID string
    Address string
}

type DeviceOption struct {
    DeviceOptionID int
    DeviceUUID string
    OptionKey string
    OptionValue string
}

type Network struct {
    UUID string
    Name string
    DeviceID int
    Options map[string]string `db:"-"`
    Addresses []string `db:"-"`
    Physicals []string `db:"-"`
}

type NetworkDevice struct {
    UUID string
    DeviceID int
    Options map[string]string `db:"-"`
    Addresses []string `db:"-"`
    Network *Network `db:"-"`
    NetworkUUID string
    VmUUID string
}

type Route struct {
    RouteID int
    VmUUID string
    Source string
    Destination string
}

type NetworkJSON struct {
    UUID string
    Name string
    Status string
    Options map[string]string
    Addresses []string
    Physicals []string
}

type NetworkDeviceJSON struct {
    UUID string
    Status string
    Options map[string]string
    Addresses []string
    Network *Network
}

func GetNetworks(db *gorp.DbMap) []Network {
    var networks []Network
    _, err := db.Select(&networks, "select * from Network")

    if err != nil {
        panic(err)
        return []Network{}
    }

    return networks
}

func GetNetwork(db map[string]interface{}, uuid string) *Network {
    var obj interface{}
    var err error

    if _, ok := db["dbmap"]; ok == true {
        obj, err = db["dbmap"].(*gorp.DbMap).Get(Network{}, uuid)
        if err != nil {
            panic(err)
            return nil
        }
    } else {
        obj, err = db["sqlexecutor"].(gorp.SqlExecutor).Get(Network{}, uuid)
        if err != nil {
            panic(err);
            return nil
        }
    }

    return obj.(*Network)
}

func (network *Network) PostGet(s gorp.SqlExecutor) error {
    var physicals []NetworkPhysical
    var options []DeviceOption
    var addresses []DeviceAddress

    _, err := s.Select(&physicals, "select * from NetworkPhysical where NetworkUUID = ?", network.UUID)
    if err == nil {
        for i := 0; i < len(physicals); i++ {
            network.Physicals = append(network.Physicals, physicals[i].Device)
        }
    } else {
        panic(err)
    }

    _, err = s.Select(&options, "select * from DeviceOption where DeviceUUID = ?", network.UUID)
    if err == nil {
        for i := 0; i < len(options); i++ {
            network.Options[options[i].OptionKey] = options[i].OptionValue
        }
    } else {
        panic(err)
    }

    _, err = s.Select(&addresses, "select * from DeviceAddress where DeviceUUID = ?", network.UUID)
    if err == nil {
        for i := 0; i < len(addresses); i++ {
            network.Addresses = append(network.Addresses, addresses[i].Address)
        }
    } else {
        panic(err)
    }

    return nil
}

func (device *NetworkDevice) PostGet(s gorp.SqlExecutor) error {
    device.Network = GetNetwork(map[string]interface{}{"sqlexecutor": s}, device.NetworkUUID)
    return nil
}

func GetNetworkDevices(db map[string]interface{}, vm VirtualMachine.VirtualMachine) []*NetworkDevice {
    var devices []*NetworkDevice

    if _, ok := db["dbmap"]; ok == true {
        _, err := db["dbmap"].(*gorp.DbMap).Select(&devices, "select * from NetworkDevice where VmUUID = ?", vm.GetUUID())
        if err != nil {
            panic(err)
            return nil
        }
    } else {
        _, err := db["sqlexecutor"].(gorp.SqlExecutor).Select(&devices, "select * from NetworkDevice where VmUUID = ?", vm.GetUUID())
        if err != nil {
            panic(err);
            return nil
        }
    }

    return devices
}

func (network *Network) IsOnline() bool {
    id := strconv.Itoa(network.DeviceID)

    cmd := exec.Command("/sbin/ifconfig", "bridge" + id)
    err := cmd.Run()

    if err != nil {
        return false
    }

    return true
}

func (network *Network) Start() error {
    id := strconv.Itoa(network.DeviceID)

    if network.IsOnline() {
        return nil
    }

    cmd := exec.Command("/sbin/ifconfig", "bridge" + id, "create")
    for k, v := range network.Options {
        cmd.Args = append(cmd.Args, k)
        if len(v) > 0 {
            cmd.Args = append(cmd.Args, v)
        }
    }

    if rawoutput, err := cmd.CombinedOutput(); err != nil {
        return fmt.Errorf("ERROR: ifconfig bridge%s create: %s", id, virtbsdutil.ByteToString(rawoutput))
    }

    cmd = exec.Command("/sbin/ifconfig", "bridge" + id, "up")
    if rawoutput, err := cmd.CombinedOutput(); err != nil {
        return fmt.Errorf("ERROR: ifconfig bridge%s up: %s", id, virtbsdutil.ByteToString(rawoutput))
    }

    for i := range network.Physicals {
        cmd = exec.Command("/sbin/ifconfig", "bridge" + id, "addm", network.Physicals[i])
        if rawoutput, err := cmd.CombinedOutput(); err != nil {
            return fmt.Errorf("ERROR: ifconfig bridge%s addm %s: %s", id, network.Physicals[i], virtbsdutil.ByteToString(rawoutput))
        }
    }

    for i := range network.Addresses {
        proto := "inet"
        if strings.Index(network.Addresses[i], ":") >= 0 {
            proto = "inet6"
        }

        cmd = exec.Command("/sbin/ifconfig", "bridge" + id, proto, network.Addresses[i], "alias")
        if rawoutput, err := cmd.CombinedOutput(); err != nil {
            return fmt.Errorf("ERROR: ifconfig bridge%s %s %s alias: %s", id, proto, network.Addresses[i], virtbsdutil.ByteToString(rawoutput))
        }
    }

    return nil
}

func (network *Network) Stop() error {
    id := strconv.Itoa(network.DeviceID)

    if network.IsOnline() == false {
        return nil
    }

    cmd := exec.Command("/sbin/ifconfig", "bridge" + id, "destroy")
    err := cmd.Run()

    return err
}

func (device *NetworkDevice) IsOnline() bool {
    id := strconv.Itoa(device.DeviceID)

    cmd := exec.Command("/sbin/ifconfig", "epair" + id + "a")
    err := cmd.Run()

    if err != nil {
        return false
    }

    return true
}

func (device *NetworkDevice) BringHostOnline() error {
    id := strconv.Itoa(device.DeviceID)

    if device.Network.IsOnline() == false {
        if err := device.Network.Start(); err != nil {
            return err
        }
    }

    if device.IsOnline() == true {
        if err := device.BringOffline(); err != nil {
            return err
        }
    }

    cmd := exec.Command("/sbin/ifconfig", "epair" + id, "create")
    if rawoutput, err := cmd.CombinedOutput(); err != nil {
        return fmt.Errorf("ERROR: ifconfig epair%sa create: %s", id, virtbsdutil.ByteToString(rawoutput))
    }

    cmd = exec.Command("/sbin/ifconfig", "bridge" + strconv.Itoa(device.Network.DeviceID), "addm", "epair" + id + "a")
    if rawoutput, err := cmd.CombinedOutput(); err != nil {
        return fmt.Errorf("ERROR: ifconfig bridge%s addm epair%sa: %s", strconv.Itoa(device.Network.DeviceID), id, virtbsdutil.ByteToString(rawoutput))
    }

    return nil
}

func (device *NetworkDevice) BringGuestOnline(vm VirtualMachine.VirtualMachine) error {
    id := strconv.Itoa(device.DeviceID)
    vmid := vm.GetUUID()
    deviceid := "epair" + id + "b"

    if vm.IsOnline() == false {
        return errors.New("VM is turned off. VM must be turned on to have its networking stack brought online")
    }

    if device.IsOnline() == false {
        if err := device.BringHostOnline(); err != nil {
            return err
        }
    }

    cmd := exec.Command("/sbin/ifconfig", deviceid, "vnet", vmid)
    for k, v := range device.Options {
        cmd.Args = append(cmd.Args, k)
        if len(v) > 0 {
            cmd.Args = append(cmd.Args, v)
        }
    }

    err := cmd.Run()

    if err != nil {
        return err
    }

    for i := range device.Addresses {
        proto := "inet"
        if strings.Index(device.Addresses[i], ":") >= 0 {
            proto = "inet6"
        }

        cmd = exec.Command("/usr/sbin/jexec", vmid, "/sbin/ifconfig", deviceid, proto, device.Addresses[i], "alias")
        err = cmd.Run()

        if err != nil {
            device.BringOffline()
            return err
        }
    }

    cmd = exec.Command("/usr/sbin/jexec", vmid, "/sbin/ifconfig", deviceid, "up")

    return nil
}

func (device *NetworkDevice) BringOffline() error {
    id := strconv.Itoa(device.DeviceID)

    if device.IsOnline() == false {
        return nil
    }

    cmd := exec.Command("/sbin/ifconfig", "epair" + id + "a", "destroy")
    err := cmd.Run()

    return err
}

func (network *Network) Persist(db *gorp.DbMap) error {
    return nil
}

func (device *NetworkDevice) Persist(db *gorp.DbMap, vm VirtualMachine.VirtualMachine) error {
    device.Network.Persist(db)

    if len(device.UUID) == 0 {
        uuid, _ := uuid.NewV4()
        device.UUID = uuid.String()

        db.Insert(device)
        return nil
    } else {
        db.Update(device)
    }

    return nil
}

func (network *Network) MarshalJSON() ([]byte, error) {
    obj := NetworkJSON{}
    obj.UUID = network.UUID
    obj.Name = network.Name
    obj.Options = network.Options
    obj.Addresses = network.Addresses
    obj.Physicals = network.Physicals

    if network.IsOnline() {
        obj.Status = "Online"
    } else {
        obj.Status = "Offline"
    }

    return json.MarshalIndent(obj, "", "    ")
}

func (device *NetworkDevice) MarshalJSON() ([]byte, error) {
    obj := NetworkDeviceJSON{}
    obj.UUID = device.UUID
    obj.Options = device.Options
    obj.Addresses = device.Addresses
    obj.Network = device.Network

    if device.IsOnline() {
        obj.Status = "Online"
    } else {
        obj.Status = "Offline"
    }

    bytes, err := json.MarshalIndent(obj, "", "    ")
    return bytes, err
}
<commit_msg>Change how the addresses, options, etc. are loaded in Network and NetworkDevice. Fully bring up the network device. Fix bugs.<commit_after>/*
(BSD 2-clause license)

Copyright (c) 2014, Shawn Webb
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

   * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package network

import (
    "fmt"
    "strconv"
    "errors"
    "strings"
    "os/exec"
    "encoding/json"
    "github.com/coopernurse/gorp"
    "github.com/virtbsd/VirtualMachine"
    "github.com/virtbsd/util"
    "github.com/nu7hatch/gouuid"
)

type NetworkPhysical struct {
    NetworkPhysicalID int
    NetworkUUID string
    Device string
}

type DeviceAddress struct {
    DeviceAddressID int
    DeviceUUID string
    Address string
}

type DeviceOption struct {
    DeviceOptionID int
    DeviceUUID string
    OptionKey string
    OptionValue string
}

type Network struct {
    UUID string
    Name string
    DeviceID int
    Options []*DeviceOption `db:"-"`
    Addresses []*DeviceAddress `db:"-"`
    Physicals []*NetworkPhysical `db:"-"`
}

type NetworkDevice struct {
    UUID string
    DeviceID int
    Options []*DeviceOption `db:"-"`
    Addresses []*DeviceAddress `db:"-"`
    Network *Network `db:"-"`
    NetworkUUID string
    VmUUID string
}

type Route struct {
    RouteID int
    VmUUID string
    Source string
    Destination string
}

type NetworkJSON struct {
    UUID string
    DeviceID int
    Name string
    Status string
    Options []*DeviceOption
    Addresses []*DeviceAddress
    Physicals []*NetworkPhysical
}

type NetworkDeviceJSON struct {
    UUID string
    DeviceID int
    Status string
    Options []*DeviceOption
    Addresses []*DeviceAddress
    Network *Network
}

func GetNetworks(db *gorp.DbMap) []Network {
    var networks []Network
    _, err := db.Select(&networks, "select * from Network")

    if err != nil {
        panic(err)
        return []Network{}
    }

    return networks
}

func GetNetwork(db map[string]interface{}, uuid string) *Network {
    var obj interface{}
    var err error

    if _, ok := db["dbmap"]; ok == true {
        obj, err = db["dbmap"].(*gorp.DbMap).Get(Network{}, uuid)
        if err != nil {
            panic(err)
            return nil
        }
    } else {
        obj, err = db["sqlexecutor"].(gorp.SqlExecutor).Get(Network{}, uuid)
        if err != nil {
            panic(err);
            return nil
        }
    }

    return obj.(*Network)
}

func (network *Network) PostGet(s gorp.SqlExecutor) error {
    _, err := s.Select(&network.Physicals, "select * from NetworkPhysical where NetworkUUID = ?", network.UUID)
    if err != nil {
        panic(err)
    }

    _, err = s.Select(&network.Options, "select * from DeviceOption where DeviceUUID = ?", network.UUID)
    if err != nil {
        panic(err)
    }

    _, err = s.Select(&network.Addresses, "select * from DeviceAddress where DeviceUUID = ?", network.UUID)
    if err != nil {
        panic(err)
    }

    return nil
}

func (device *NetworkDevice) PostGet(s gorp.SqlExecutor) error {
    device.Network = GetNetwork(map[string]interface{}{"sqlexecutor": s}, device.NetworkUUID)

    if _, err := s.Select(&device.Options, "select * from DeviceOption where DeviceUUID = ?", device.UUID); err != nil {
        panic(err)
    }

    if _, err := s.Select(&device.Addresses, "select * from DeviceAddress where DeviceUUID = ?", device.UUID); err != nil {
        panic(err)
    }

    return nil
}

func GetNetworkDevices(db map[string]interface{}, vm VirtualMachine.VirtualMachine) []*NetworkDevice {
    var devices []*NetworkDevice

    if _, ok := db["dbmap"]; ok == true {
        _, err := db["dbmap"].(*gorp.DbMap).Select(&devices, "select * from NetworkDevice where VmUUID = ?", vm.GetUUID())
        if err != nil {
            panic(err)
            return nil
        }
    } else {
        _, err := db["sqlexecutor"].(gorp.SqlExecutor).Select(&devices, "select * from NetworkDevice where VmUUID = ?", vm.GetUUID())
        if err != nil {
            panic(err);
            return nil
        }
    }

    return devices
}

func (network *Network) IsOnline() bool {
    id := strconv.Itoa(network.DeviceID)

    cmd := exec.Command("/sbin/ifconfig", "bridge" + id)
    err := cmd.Run()

    if err != nil {
        return false
    }

    return true
}

func (network *Network) Start() error {
    id := strconv.Itoa(network.DeviceID)

    if network.IsOnline() {
        return nil
    }

    cmd := exec.Command("/sbin/ifconfig", "bridge" + id, "create")
    for _, option := range network.Options {
        cmd.Args = append(cmd.Args, option.OptionKey)
        if len(option.OptionValue) > 0 {
            cmd.Args = append(cmd.Args, option.OptionValue)
        }
    }

    if rawoutput, err := cmd.CombinedOutput(); err != nil {
        return fmt.Errorf("ERROR: ifconfig bridge%s create: %s", id, virtbsdutil.ByteToString(rawoutput))
    }

    cmd = exec.Command("/sbin/ifconfig", "bridge" + id, "up")
    if rawoutput, err := cmd.CombinedOutput(); err != nil {
        return fmt.Errorf("ERROR: ifconfig bridge%s up: %s", id, virtbsdutil.ByteToString(rawoutput))
    }

    for _, physical := range network.Physicals {
        cmd = exec.Command("/sbin/ifconfig", "bridge" + id, "addm", physical.Device)
        if rawoutput, err := cmd.CombinedOutput(); err != nil {
            return fmt.Errorf("ERROR: ifconfig bridge%s addm %s: %s", id, physical.Device, virtbsdutil.ByteToString(rawoutput))
        }
    }

    for _, address := range network.Addresses {
        proto := "inet"
        if strings.Index(address.Address, ":") >= 0 {
            proto = "inet6"
        }

        cmd = exec.Command("/sbin/ifconfig", "bridge" + id, proto, address.Address, "alias")
        if rawoutput, err := cmd.CombinedOutput(); err != nil {
            return fmt.Errorf("ERROR: ifconfig bridge%s %s %s alias: %s", id, proto, address.Address, virtbsdutil.ByteToString(rawoutput))
        }
    }

    return nil
}

func (network *Network) Stop() error {
    id := strconv.Itoa(network.DeviceID)

    if network.IsOnline() == false {
        return nil
    }

    cmd := exec.Command("/sbin/ifconfig", "bridge" + id, "destroy")
    err := cmd.Run()

    return err
}

func (device *NetworkDevice) IsOnline() bool {
    id := strconv.Itoa(device.DeviceID)

    cmd := exec.Command("/sbin/ifconfig", "epair" + id + "a")
    err := cmd.Run()

    if err != nil {
        return false
    }

    return true
}

func (device *NetworkDevice) BringHostOnline() error {
    id := strconv.Itoa(device.DeviceID)

    if device.Network.IsOnline() == false {
        if err := device.Network.Start(); err != nil {
            return err
        }
    }

    if device.IsOnline() == true {
        if err := device.BringOffline(); err != nil {
            return err
        }
    }

    cmd := exec.Command("/sbin/ifconfig", "epair" + id, "create")
    if rawoutput, err := cmd.CombinedOutput(); err != nil {
        return fmt.Errorf("ERROR: ifconfig epair%sa create: %s", id, virtbsdutil.ByteToString(rawoutput))
    }

    cmd = exec.Command("/sbin/ifconfig", "bridge" + strconv.Itoa(device.Network.DeviceID), "addm", "epair" + id + "a")
    if rawoutput, err := cmd.CombinedOutput(); err != nil {
        return fmt.Errorf("ERROR: ifconfig bridge%s addm epair%sa: %s", strconv.Itoa(device.Network.DeviceID), id, virtbsdutil.ByteToString(rawoutput))
    }

    cmd = exec.Command("/sbin/ifconfig", "epair" + id + "a", "up")
    if rawoutput, err := cmd.CombinedOutput(); err != nil {
        return fmt.Errorf("ERROR: ifconfig epair%sa create: %s", id, virtbsdutil.ByteToString(rawoutput))
    }

    return nil
}

func (device *NetworkDevice) BringGuestOnline(vm VirtualMachine.VirtualMachine) error {
    id := strconv.Itoa(device.DeviceID)
    vmid := vm.GetUUID()
    deviceid := "epair" + id + "b"
    needs_dhcp := false

    if vm.IsOnline() == false {
        return errors.New("VM is turned off. VM must be turned on to have its networking stack brought online")
    }

    if device.IsOnline() == false {
        if err := device.BringHostOnline(); err != nil {
            return err
        }
    }

    cmd := exec.Command("/sbin/ifconfig", deviceid, "vnet", vmid)
    for _, option := range device.Options {
        if option.OptionKey == "DHCP" {
            needs_dhcp = true
            continue
        }

        cmd.Args = append(cmd.Args, option.OptionKey)
        if len(option.OptionValue) > 0 {
            cmd.Args = append(cmd.Args, option.OptionValue)
        }
    }

    err := cmd.Run()

    if err != nil {
        return err
    }

    if needs_dhcp {
        cmd = exec.Command("/usr/sbin/jexec", vmid, "/sbin/dhclient", deviceid)
        if rawoutput, err := cmd.CombinedOutput(); err != nil {
            return fmt.Errorf("/sbin/dhclient %s: %s", deviceid, virtbsdutil.ByteToString(rawoutput))
        }
    }

    for _, address := range device.Addresses {
        proto := "inet"
        if strings.Index(address.Address, ":") >= 0 {
            proto = "inet6"
        }

        cmd = exec.Command("/usr/sbin/jexec", vmid, "/sbin/ifconfig", deviceid, proto, address.Address, "alias")
        err = cmd.Run()

        if err != nil {
            device.BringOffline()
            return err
        }
    }

    cmd = exec.Command("/usr/sbin/jexec", vmid, "/sbin/ifconfig", deviceid, "up")

    return nil
}

func (device *NetworkDevice) BringOffline() error {
    id := strconv.Itoa(device.DeviceID)

    if device.IsOnline() == false {
        return nil
    }

    cmd := exec.Command("/sbin/ifconfig", "epair" + id + "a", "destroy")
    err := cmd.Run()

    return err
}

func (network *Network) Persist(db *gorp.DbMap) error {
    return nil
}

func (device *NetworkDevice) Persist(db *gorp.DbMap, vm VirtualMachine.VirtualMachine) error {
    device.Network.Persist(db)

    if len(device.UUID) == 0 {
        uuid, _ := uuid.NewV4()
        device.UUID = uuid.String()

        db.Insert(device)
        return nil
    } else {
        db.Update(device)
    }

    return nil
}

func (network *Network) MarshalJSON() ([]byte, error) {
    obj := NetworkJSON{}
    obj.UUID = network.UUID
    obj.DeviceID = network.DeviceID
    obj.Name = network.Name
    obj.Options = network.Options
    obj.Addresses = network.Addresses
    obj.Physicals = network.Physicals

    if network.IsOnline() {
        obj.Status = "Online"
    } else {
        obj.Status = "Offline"
    }

    return json.MarshalIndent(obj, "", "    ")
}

func (device *NetworkDevice) MarshalJSON() ([]byte, error) {
    obj := NetworkDeviceJSON{}
    obj.UUID = device.UUID
    obj.DeviceID = device.DeviceID
    obj.Options = device.Options
    obj.Addresses = device.Addresses
    obj.Network = device.Network

    if device.IsOnline() {
        obj.Status = "Online"
    } else {
        obj.Status = "Offline"
    }

    bytes, err := json.MarshalIndent(obj, "", "    ")
    return bytes, err
}
<|endoftext|>


<commit_before>// Package script is a library facilitating the creation of programs that resemble
// bash scripts.
package script

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strings"
	"syscall"

	"github.com/tomclegg/nbtee"
)

// ProcessResult contains the results of a process execution be it successful or not.
type ProcessResult struct {
	Cmd          *exec.Cmd
	ProcessState *os.ProcessState
	ProcessError error
	stdoutBuffer *bytes.Buffer
	stderrBuffer *bytes.Buffer
}

// Output returns a string representation of the output of the process denoted
// by this struct.
func (pr *ProcessResult) Output() string {
	return pr.stdoutBuffer.String()
}

// Error returns a string representation of the stderr output of the process denoted
// by this struct.
func (pr *ProcessResult) Error() string {
	return pr.stderrBuffer.String()
}

// Successful returns true iff the process denoted by this struct was run
// successfully. Success is defined as the exit code being set to 0.
func (pr *ProcessResult) Successful() bool {
	fmt.Println(pr.ExitCode())
	return pr.ExitCode() == 0
}

// StateString returns a string representation of the process denoted by
// this struct
func (pr *ProcessResult) StateString() string {
	state := pr.ProcessState
	return fmt.Sprintf("PID: %q, Exited: %t, Exit Code: %q, Success: %t, User Time: %q", state.Pid(), state.Exited(), pr.ExitCode(), state.Success(), state.UserTime())
}

// ExitCode returns the exit code of the command denoted by this struct
func (pr *ProcessResult) ExitCode() int {
	var waitStatus syscall.WaitStatus
	if exitError, ok := pr.ProcessError.(*exec.ExitError); ok {
		waitStatus = exitError.Sys().(syscall.WaitStatus)
	} else {
		waitStatus = pr.ProcessState.Sys().(syscall.WaitStatus)
	}
	return waitStatus.ExitStatus()
}

// CommandPath finds the full path of a binary given its name.
func (c *Context) CommandPath(name string) string {
	cmd := exec.Command("which", name)
	cmdOutput, err := cmd.Output()
	if err != nil {
		return ""
	}
	return strings.Trim(string(cmdOutput), "\n")
}

// CommandExists checks if a given binary exists in PATH.
func (c *Context) CommandExists(name string) bool {
	return c.CommandPath(name) != ""
}

// MustCommandExist ensures a given binary exists in PATH, otherwise panics.
func (c *Context) MustCommandExist(name string) {
	if !c.CommandExists(name) {
		panic(fmt.Errorf("Command %s is not available. Please make sure it is installed and accessible.", name))
	}
}

// ExecuteDebug executes a system command, stdout and stderr are piped
func (c *Context) ExecuteDebug(name string, args ...string) (pr *ProcessResult, err error) {
	pr, err = c.Execute(false, false, name, args...)
	return
}

// ExecuteSilent executes a  system command without outputting stdout (it is
// still captured and can be retrieved using LastOutput())
func (c *Context) ExecuteSilent(name string, args ...string) (pr *ProcessResult, err error) {
	pr, err = c.Execute(true, false, name, args...)
	return
}

// ExecuteFullySilent executes a system command without outputting stdout or
// stderr (both are still captured and can be retrieved using LastOutput() and
// LastError())
func (c *Context) ExecuteFullySilent(name string, args ...string) (pr *ProcessResult, err error) {
	pr, err = c.Execute(true, true, name, args...)
	return
}

// MustExecuteDebug ensures a system command to be executed, otherwise panics
func (c *Context) MustExecuteDebug(name string, args ...string) (pr *ProcessResult) {
	pr, err := c.Execute(false, false, name, args...)
	if err != nil {
		panic(err)
	}
	return
}

// MustExecuteSilent ensures a system command to be executed without outputting
// stdout, otherwise panics
func (c *Context) MustExecuteSilent(name string, args ...string) (pr *ProcessResult) {
	pr, err := c.ExecuteSilent(name, args...)
	if err != nil {
		panic(err)
	}
	return
}

// MustExecuteFullySilent ensures a system command to be executed without
// outputting stdout and stderr, otherwise panics
func (c *Context) MustExecuteFullySilent(name string, args ...string) (pr *ProcessResult) {
	pr, err := c.ExecuteFullySilent(name, args...)
	if err != nil {
		panic(err)
	}
	return
}

// Execute executes a system command with configurable stdout and stderr output
// https://github.com/golang/go/issues/9307
func (c *Context) Execute(stdoutSilent bool, stderrSilent bool, name string, args ...string) (pr *ProcessResult, err error) {
	pr = &ProcessResult{}

	cmd := exec.Command(name, args...)

	cmd.Dir = c.workingDir
	cmd.Env = c.getFullEnv()

	// handling Stdout and Stderr
	// idea from http://nathanleclaire.com/blog/2014/12/29/shelled-out-commands-in-golang/
	//var wg sync.WaitGroup

	//multiStdoutWriter := io.MultiWriter(os.Stdout, pr.stdoutBuffer)
	multiStdoutWriter := nbtee.NewWriter(8).Start()
	multiStdoutWriter.Add(os.Stdout)
	multiStdoutWriter.Add(pr.stdoutBuffer)
	multiStderrWriter := io.MultiWriter(os.Stderr, pr.stderrBuffer)

	cmd.Stdout = multiStdoutWriter
	cmd.Stdout = os.Stdout
	cmd.Stderr = multiStderrWriter
	cmd.Stderr = os.Stderr

	fmt.Println("starting")
	err = cmd.Start()
	if err != nil {
		return nil, err
	}
	fmt.Println("running")

	err = cmd.Wait()
	fmt.Println("finished")
	// make sure all output is captured and processed before continuing
	//wg.Wait()

	pr.Cmd = cmd
	pr.ProcessState = cmd.ProcessState
	pr.ProcessError = err

	return pr, err
}

// internal
func outputHandler(scanner *bufio.Scanner, output bool, buffer *bytes.Buffer) {
	for scanner.Scan() {
		text := scanner.Text()
		if buffer.Len() > 0 {
			buffer.WriteString("\n")
		}
		_, err := buffer.WriteString(text)
		if err != nil {
			panic(err)
		}
		if output {
			fmt.Println(text, buffer.String())
		}
	}
}
<commit_msg>Fix output and error capturing<commit_after>// Package script is a library facilitating the creation of programs that resemble
// bash scripts.
package script

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strings"
	"syscall"
)

// ProcessResult contains the results of a process execution be it successful or not.
type ProcessResult struct {
	Cmd          *exec.Cmd
	ProcessState *os.ProcessState
	ProcessError error
	stdoutBuffer *bytes.Buffer
	stderrBuffer *bytes.Buffer
}

// NewProcessResult creates a new empty ProcessResult
func NewProcessResult() *ProcessResult {
	p := &ProcessResult{}
	p.stdoutBuffer = bytes.NewBuffer(make([]byte, 0, 100))
	p.stderrBuffer = bytes.NewBuffer(make([]byte, 0, 100))
	return p
}

// Output returns a string representation of the output of the process denoted
// by this struct.
func (pr *ProcessResult) Output() string {
	return pr.stdoutBuffer.String()
}

// Error returns a string representation of the stderr output of the process denoted
// by this struct.
func (pr *ProcessResult) Error() string {
	return pr.stderrBuffer.String()
}

// Successful returns true iff the process denoted by this struct was run
// successfully. Success is defined as the exit code being set to 0.
func (pr *ProcessResult) Successful() bool {
	fmt.Println(pr.ExitCode())
	return pr.ExitCode() == 0
}

// StateString returns a string representation of the process denoted by
// this struct
func (pr *ProcessResult) StateString() string {
	state := pr.ProcessState
	return fmt.Sprintf("PID: %q, Exited: %t, Exit Code: %q, Success: %t, User Time: %q", state.Pid(), state.Exited(), pr.ExitCode(), state.Success(), state.UserTime())
}

// ExitCode returns the exit code of the command denoted by this struct
func (pr *ProcessResult) ExitCode() int {
	var waitStatus syscall.WaitStatus
	if exitError, ok := pr.ProcessError.(*exec.ExitError); ok {
		waitStatus = exitError.Sys().(syscall.WaitStatus)
	} else {
		waitStatus = pr.ProcessState.Sys().(syscall.WaitStatus)
	}
	return waitStatus.ExitStatus()
}

// CommandPath finds the full path of a binary given its name.
func (c *Context) CommandPath(name string) string {
	cmd := exec.Command("which", name)
	cmdOutput, err := cmd.Output()
	if err != nil {
		return ""
	}
	return strings.Trim(string(cmdOutput), "\n")
}

// CommandExists checks if a given binary exists in PATH.
func (c *Context) CommandExists(name string) bool {
	return c.CommandPath(name) != ""
}

// MustCommandExist ensures a given binary exists in PATH, otherwise panics.
func (c *Context) MustCommandExist(name string) {
	if !c.CommandExists(name) {
		panic(fmt.Errorf("Command %s is not available. Please make sure it is installed and accessible.", name))
	}
}

// ExecuteDebug executes a system command, stdout and stderr are piped
func (c *Context) ExecuteDebug(name string, args ...string) (pr *ProcessResult, err error) {
	pr, err = c.Execute(false, false, name, args...)
	return
}

// ExecuteSilent executes a  system command without outputting stdout (it is
// still captured and can be retrieved using LastOutput())
func (c *Context) ExecuteSilent(name string, args ...string) (pr *ProcessResult, err error) {
	pr, err = c.Execute(true, false, name, args...)
	return
}

// ExecuteFullySilent executes a system command without outputting stdout or
// stderr (both are still captured and can be retrieved using LastOutput() and
// LastError())
func (c *Context) ExecuteFullySilent(name string, args ...string) (pr *ProcessResult, err error) {
	pr, err = c.Execute(true, true, name, args...)
	return
}

// MustExecuteDebug ensures a system command to be executed, otherwise panics
func (c *Context) MustExecuteDebug(name string, args ...string) (pr *ProcessResult) {
	pr, err := c.Execute(false, false, name, args...)
	if err != nil {
		panic(err)
	}
	return
}

// MustExecuteSilent ensures a system command to be executed without outputting
// stdout, otherwise panics
func (c *Context) MustExecuteSilent(name string, args ...string) (pr *ProcessResult) {
	pr, err := c.ExecuteSilent(name, args...)
	if err != nil {
		panic(err)
	}
	return
}

// MustExecuteFullySilent ensures a system command to be executed without
// outputting stdout and stderr, otherwise panics
func (c *Context) MustExecuteFullySilent(name string, args ...string) (pr *ProcessResult) {
	pr, err := c.ExecuteFullySilent(name, args...)
	if err != nil {
		panic(err)
	}
	return
}

// Execute executes a system command with configurable stdout and stderr output
// https://github.com/golang/go/issues/9307
func (c *Context) Execute(stdoutSilent bool, stderrSilent bool, name string, args ...string) (pr *ProcessResult, err error) {
	pr = NewProcessResult()

	cmd := exec.Command(name, args...)

	cmd.Dir = c.workingDir
	cmd.Env = c.getFullEnv()

	if stderrSilent {
		cmd.Stderr = pr.stderrBuffer
	} else {
		cmd.Stderr = io.MultiWriter(os.Stderr, pr.stderrBuffer)
	}
	if stderrSilent {
		cmd.Stdout = pr.stdoutBuffer
	} else {
		cmd.Stdout = io.MultiWriter(os.Stdout, pr.stdoutBuffer)
	}

	err = cmd.Start()
	if err != nil {
		return nil, err
	}

	err = cmd.Wait()
	// make sure all output is captured and processed before continuing
	//wg.Wait()

	pr.Cmd = cmd
	pr.ProcessState = cmd.ProcessState
	pr.ProcessError = err

	return pr, err
}

// internal
func outputHandler(scanner *bufio.Scanner, output bool, buffer *bytes.Buffer) {
	for scanner.Scan() {
		text := scanner.Text()
		if buffer.Len() > 0 {
			buffer.WriteString("\n")
		}
		_, err := buffer.WriteString(text)
		if err != nil {
			panic(err)
		}
		if output {
			fmt.Println(text, buffer.String())
		}
	}
}
<|endoftext|>


<commit_before>package irc_test

import (
	. "github.com/jriddick/geoffrey/irc"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Irc", func() {
	var (
		client *IRC
		cfg    Config
		emp    Config
	)

	BeforeEach(func() {
		cfg = Config{
			Hostname:           "localhost",
			Port:               6697,
			Secure:             false,
			InsecureSkipVerify: false,
		}
		emp = Config{}
		client = NewIRC(cfg)
	})

	AfterEach(func() {
		client.Disconnect()
	})

	It("should be able to create an irc client", func() {
		Expect(NewIRC(cfg)).NotTo(BeNil())
	})

	It("should be able to connect", func() {
		Expect(client.Connect()).NotTo(HaveOccurred())
	})

	It("should not be able to connect with an empty configuration", func() {
		Expect(NewIRC(emp).Connect()).To(HaveOccurred())
	})

	It("should be able to read from the server", func(done Done) {
		By("connecting to the server")
		Expect(client.Connect()).NotTo(HaveOccurred())

		By("getting the reader")
		reader := client.Reader()
		Expect(reader).NotTo(BeNil())

		msg := <-reader
		Expect(msg).NotTo(BeNil())
		Expect(msg.String()).NotTo(BeEmpty())

		close(done)
	}, 2)

	It("should be able to register to the server", func(done Done) {
		By("connecting to the server")
		Expect(client.Connect()).NotTo(HaveOccurred())

		By("getting the reader and writer")
		reader := client.Reader()
		Expect(reader).NotTo(BeNil())
		writer := client.Writer()
		Expect(writer).NotTo(BeNil())

		By("sending nick and user")
		writer <- "NICK geoffrey"
		writer <- "USER geoffrey 0 * :geoffrey"

		for {
			line, ok := <-reader
			Expect(ok).To(BeTrue())

			if line.Command == RPL_WELCOME {
				break
			}
		}

		close(done)
	}, 2)

	It("should be able to reconnect to the server", func(done Done) {
		By("connecting to the server")
		Expect(client.Connect()).NotTo(HaveOccurred())

		By("reading from the server")
		Expect(<-client.Reader()).NotTo(BeNil())

		By("reconnecting")
		Expect(client.Reconnect()).NotTo(HaveOccurred())

		By("reading from the server")
		Expect(<-client.Reader()).NotTo(BeNil())

		close(done)
	}, 2)
})
<commit_msg>added test case for empty messages<commit_after>package irc_test

import (
	. "github.com/jriddick/geoffrey/irc"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Irc", func() {
	var (
		client *IRC
		cfg    Config
		emp    Config
	)

	BeforeEach(func() {
		cfg = Config{
			Hostname:           "localhost",
			Port:               6697,
			Secure:             false,
			InsecureSkipVerify: false,
		}
		emp = Config{}
		client = NewIRC(cfg)
	})

	AfterEach(func() {
		client.Disconnect()
	})

	It("should be able to create an irc client", func() {
		Expect(NewIRC(cfg)).NotTo(BeNil())
	})

	It("should be able to connect", func() {
		Expect(client.Connect()).NotTo(HaveOccurred())
	})

	It("should not be able to connect with an empty configuration", func() {
		Expect(NewIRC(emp).Connect()).To(HaveOccurred())
	})

	It("should be able to read from the server", func(done Done) {
		By("connecting to the server")
		Expect(client.Connect()).NotTo(HaveOccurred())

		By("getting the reader")
		reader := client.Reader()
		Expect(reader).NotTo(BeNil())

		msg := <-reader
		Expect(msg).NotTo(BeNil())
		Expect(msg.String()).NotTo(BeEmpty())

		close(done)
	}, 5)

	It("should be able to register to the server", func(done Done) {
		By("connecting to the server")
		Expect(client.Connect()).NotTo(HaveOccurred())

		By("getting the reader and writer")
		reader := client.Reader()
		Expect(reader).NotTo(BeNil())
		writer := client.Writer()
		Expect(writer).NotTo(BeNil())

		By("sending nick and user")
		writer <- "NICK geoffrey"
		writer <- "USER geoffrey 0 * :geoffrey"

		for {
			line, ok := <-reader
			Expect(ok).To(BeTrue())

			if line.Command == RPL_WELCOME {
				break
			}
		}

		close(done)
	}, 5)

	It("should be able to reconnect to the server", func(done Done) {
		By("connecting to the server")
		Expect(client.Connect()).NotTo(HaveOccurred())

		By("reading from the server")
		Expect(<-client.Reader()).NotTo(BeNil())

		By("reconnecting")
		Expect(client.Reconnect()).NotTo(HaveOccurred())

		By("reading from the server")
		Expect(<-client.Reader()).NotTo(BeNil())

		close(done)
	}, 5)

	It("should not be able to send empty messages", func(done Done) {
		By("connecting to the server")
		Expect(client.Connect()).NotTo(HaveOccurred())

		By("sending an empty message")
		client.Writer() <- ""

		Expect(<-client.Errors()).NotTo(BeNil())

		close(done)
	}, 5)
})
<|endoftext|>


<commit_before>package chromedp

import (
	"context"
	"errors"
	"fmt"
	"log"
	"os"
	"sync"
	"sync/atomic"
	"time"

	easyjson "github.com/mailru/easyjson"

	"github.com/chromedp/cdproto"
	"github.com/chromedp/cdproto/browser"
	"github.com/chromedp/cdproto/cdp"
	"github.com/chromedp/cdproto/target"
)

// Browser is the high-level Chrome DevTools Protocol browser manager, handling
// the browser process runner, WebSocket clients, associated targets, and
// network, page, and DOM events.
type Browser struct {
	// LostConnection is closed when the websocket connection to Chrome is
	// dropped. This can be useful to make sure that Browser's context is
	// cancelled (and the handler stopped) once the connection has failed.
	LostConnection chan struct{}

	dialTimeout time.Duration

	// pages keeps track of the attached targets, indexed by each's session
	// ID. The only reaon this is a field is so that the tests can check the
	// map once a browser is closed.
	pages map[target.SessionID]*Target

	listenersMu sync.Mutex
	listeners   []cancelableListener

	conn Transport

	// next is the next message id.
	next int64

	// newTabQueue is the queue used to create new target handlers, once a new
	// tab is created and attached to. The newly created Target is sent back
	// via newTabResult.
	newTabQueue chan *Target

	// cmdQueue is the outgoing command queue.
	cmdQueue chan *cdproto.Message

	// logging funcs
	logf func(string, ...interface{})
	errf func(string, ...interface{})
	dbgf func(string, ...interface{})

	// The optional fields below are helpful for some tests.

	// process can be initialized by the allocators which start a process
	// when allocating a browser.
	process *os.Process

	// userDataDir can be initialized by the allocators which set up user
	// data dirs directly.
	userDataDir string
}

// NewBrowser creates a new browser. Typically, this function wouldn't be called
// directly, as the Allocator interface takes care of it.
func NewBrowser(ctx context.Context, urlstr string, opts ...BrowserOption) (*Browser, error) {
	b := &Browser{
		LostConnection: make(chan struct{}),

		dialTimeout: 10 * time.Second,

		newTabQueue: make(chan *Target),

		// Fit some jobs without blocking, to reduce blocking in Execute.
		cmdQueue: make(chan *cdproto.Message, 32),

		logf: log.Printf,
	}
	// apply options
	for _, o := range opts {
		o(b)
	}
	// ensure errf is set
	if b.errf == nil {
		b.errf = func(s string, v ...interface{}) { b.logf("ERROR: "+s, v...) }
	}

	dialCtx := ctx
	if b.dialTimeout > 0 {
		var cancel context.CancelFunc
		dialCtx, cancel = context.WithTimeout(ctx, b.dialTimeout)
		defer cancel()
	}

	var err error
	urlstr = forceIP(urlstr)
	b.conn, err = DialContext(dialCtx, urlstr, WithConnDebugf(b.dbgf))
	if err != nil {
		return nil, fmt.Errorf("could not dial %q: %v", urlstr, err)
	}

	go b.run(ctx)
	return b, nil
}

func (b *Browser) newExecutorForTarget(ctx context.Context, targetID target.ID, sessionID target.SessionID) (*Target, error) {
	if targetID == "" {
		return nil, errors.New("empty target ID")
	}
	if sessionID == "" {
		return nil, errors.New("empty session ID")
	}
	t := &Target{
		browser:   b,
		TargetID:  targetID,
		SessionID: sessionID,

		messageQueue: make(chan *cdproto.Message, 1024),
		frames:       make(map[cdp.FrameID]*cdp.Frame),

		logf: b.logf,
		errf: b.errf,
	}

	// This send should be blocking, to ensure the tab is inserted into the
	// map before any more target events are routed.
	select {
	case <-ctx.Done():
		return nil, ctx.Err()
	case b.newTabQueue <- t:
	}
	return t, nil
}

func (b *Browser) Execute(ctx context.Context, method string, params easyjson.Marshaler, res easyjson.Unmarshaler) error {
	if method == browser.CommandClose {
		return fmt.Errorf("to close the browser, cancel its context or use chromedp.Cancel")
	}

	id := atomic.AddInt64(&b.next, 1)
	lctx, cancel := context.WithCancel(ctx)
	ch := make(chan *cdproto.Message, 1)
	fn := func(ev interface{}) {
		if msg, ok := ev.(*cdproto.Message); ok && msg.ID == id {
			select {
			case <-ctx.Done():
			case ch <- msg:
			}
			cancel()
		}
	}
	b.listenersMu.Lock()
	b.listeners = append(b.listeners, cancelableListener{lctx, fn})
	b.listenersMu.Unlock()

	// send command
	var buf []byte
	if params != nil {
		var err error
		buf, err = easyjson.Marshal(params)
		if err != nil {
			return err
		}
	}
	cmd := &cdproto.Message{
		ID:     id,
		Method: cdproto.MethodType(method),
		Params: buf,
	}
	select {
	case <-ctx.Done():
		return ctx.Err()
	case b.cmdQueue <- cmd:
	}

	// wait for result
	select {
	case <-ctx.Done():
		return ctx.Err()
	case msg := <-ch:
		switch {
		case msg == nil:
			return ErrChannelClosed
		case msg.Error != nil:
			return msg.Error
		case res != nil:
			return easyjson.Unmarshal(msg.Result, res)
		}
	}
	return nil
}

func (b *Browser) run(ctx context.Context) {
	defer b.conn.Close()

	// incomingQueue is the queue of incoming target events, to be routed by
	// their session ID.
	incomingQueue := make(chan *cdproto.Message, 1)

	delTabQueue := make(chan target.SessionID, 1)

	// This goroutine continuously reads events from the websocket
	// connection. The separate goroutine is needed since a websocket read
	// is blocking, so it cannot be used in a select statement.
	go func() {
		for {
			msg := new(cdproto.Message)
			if err := b.conn.Read(ctx, msg); err != nil {
				// If the websocket failed, most likely Chrome was closed or
				// crashed. Signal that so the entire browser handler can be
				// stopped.
				close(b.LostConnection)
				return
			}

			switch {
			case msg.SessionID != "" && (msg.Method != "" || msg.ID != 0):
				select {
				case <-ctx.Done():
					return
				case incomingQueue <- msg:
				}

			case msg.Method != "":
				ev, err := cdproto.UnmarshalMessage(msg)
				if err != nil {
					b.errf("%s", err)
					continue
				}
				b.listenersMu.Lock()
				b.listeners = runListeners(b.listeners, ev)
				b.listenersMu.Unlock()

				if ev, ok := ev.(*target.EventDetachedFromTarget); ok {
					delTabQueue <- ev.SessionID
				}

			case msg.ID != 0:
				b.listenersMu.Lock()
				b.listeners = runListeners(b.listeners, msg)
				b.listenersMu.Unlock()

			default:
				b.errf("ignoring malformed incoming message (missing id or method): %#v", msg)
			}
		}
	}()

	b.pages = make(map[target.SessionID]*Target, 32)
	for {
		select {
		case <-ctx.Done():
			return

		case msg := <-b.cmdQueue:
			if err := b.conn.Write(ctx, msg); err != nil {
				b.errf("%s", err)
				continue
			}

		case t := <-b.newTabQueue:
			if _, ok := b.pages[t.SessionID]; ok {
				b.errf("executor for %q already exists", t.SessionID)
			}
			b.pages[t.SessionID] = t

		case sessionID := <-delTabQueue:
			if _, ok := b.pages[sessionID]; !ok {
				b.errf("executor for %q doesn't exist", sessionID)
			}
			delete(b.pages, sessionID)

		case m := <-incomingQueue:
			page, ok := b.pages[m.SessionID]
			if !ok {
				// A page we recently closed still sending events.
				continue
			}

			select {
			case <-ctx.Done():
				return
			case page.messageQueue <- m:
			}

		case <-b.LostConnection:
			return // to avoid "write: broken pipe" errors
		}
	}
}

// BrowserOption is a browser option.
type BrowserOption = func(*Browser)

// WithBrowserLogf is a browser option to specify a func to receive general logging.
func WithBrowserLogf(f func(string, ...interface{})) BrowserOption {
	return func(b *Browser) { b.logf = f }
}

// WithBrowserErrorf is a browser option to specify a func to receive error logging.
func WithBrowserErrorf(f func(string, ...interface{})) BrowserOption {
	return func(b *Browser) { b.errf = f }
}

// WithBrowserDebugf is a browser option to specify a func to log actual
// websocket messages.
func WithBrowserDebugf(f func(string, ...interface{})) BrowserOption {
	return func(b *Browser) { b.dbgf = f }
}

// WithConsolef is a browser option to specify a func to receive chrome log events.
//
// Note: NOT YET IMPLEMENTED.
func WithConsolef(f func(string, ...interface{})) BrowserOption {
	return func(b *Browser) {}
}

// WithDialTimeout is a browser option to specify the timeout when dialing a
// browser's websocket address. The default is ten seconds; use a zero duration
// to not use a timeout.
func WithDialTimeout(d time.Duration) BrowserOption {
	return func(b *Browser) { b.dialTimeout = d }
}
<commit_msg>reposition field for aligned atomic access on arm<commit_after>package chromedp

import (
	"context"
	"errors"
	"fmt"
	"log"
	"os"
	"sync"
	"sync/atomic"
	"time"

	easyjson "github.com/mailru/easyjson"

	"github.com/chromedp/cdproto"
	"github.com/chromedp/cdproto/browser"
	"github.com/chromedp/cdproto/cdp"
	"github.com/chromedp/cdproto/target"
)

// Browser is the high-level Chrome DevTools Protocol browser manager, handling
// the browser process runner, WebSocket clients, associated targets, and
// network, page, and DOM events.
type Browser struct {
	// next is the next message id.
	// NOTE: needs to be 64-bit aligned for 32-bit targets too, so be careful when moving this field.
	// This will be eventually done by the compiler once https://github.com/golang/go/issues/599 is fixed.
	next int64

	// LostConnection is closed when the websocket connection to Chrome is
	// dropped. This can be useful to make sure that Browser's context is
	// cancelled (and the handler stopped) once the connection has failed.
	LostConnection chan struct{}

	dialTimeout time.Duration

	// pages keeps track of the attached targets, indexed by each's session
	// ID. The only reaon this is a field is so that the tests can check the
	// map once a browser is closed.
	pages map[target.SessionID]*Target

	listenersMu sync.Mutex
	listeners   []cancelableListener

	conn Transport

	// newTabQueue is the queue used to create new target handlers, once a new
	// tab is created and attached to. The newly created Target is sent back
	// via newTabResult.
	newTabQueue chan *Target

	// cmdQueue is the outgoing command queue.
	cmdQueue chan *cdproto.Message

	// logging funcs
	logf func(string, ...interface{})
	errf func(string, ...interface{})
	dbgf func(string, ...interface{})

	// The optional fields below are helpful for some tests.

	// process can be initialized by the allocators which start a process
	// when allocating a browser.
	process *os.Process

	// userDataDir can be initialized by the allocators which set up user
	// data dirs directly.
	userDataDir string
}

// NewBrowser creates a new browser. Typically, this function wouldn't be called
// directly, as the Allocator interface takes care of it.
func NewBrowser(ctx context.Context, urlstr string, opts ...BrowserOption) (*Browser, error) {
	b := &Browser{
		LostConnection: make(chan struct{}),

		dialTimeout: 10 * time.Second,

		newTabQueue: make(chan *Target),

		// Fit some jobs without blocking, to reduce blocking in Execute.
		cmdQueue: make(chan *cdproto.Message, 32),

		logf: log.Printf,
	}
	// apply options
	for _, o := range opts {
		o(b)
	}
	// ensure errf is set
	if b.errf == nil {
		b.errf = func(s string, v ...interface{}) { b.logf("ERROR: "+s, v...) }
	}

	dialCtx := ctx
	if b.dialTimeout > 0 {
		var cancel context.CancelFunc
		dialCtx, cancel = context.WithTimeout(ctx, b.dialTimeout)
		defer cancel()
	}

	var err error
	urlstr = forceIP(urlstr)
	b.conn, err = DialContext(dialCtx, urlstr, WithConnDebugf(b.dbgf))
	if err != nil {
		return nil, fmt.Errorf("could not dial %q: %v", urlstr, err)
	}

	go b.run(ctx)
	return b, nil
}

func (b *Browser) newExecutorForTarget(ctx context.Context, targetID target.ID, sessionID target.SessionID) (*Target, error) {
	if targetID == "" {
		return nil, errors.New("empty target ID")
	}
	if sessionID == "" {
		return nil, errors.New("empty session ID")
	}
	t := &Target{
		browser:   b,
		TargetID:  targetID,
		SessionID: sessionID,

		messageQueue: make(chan *cdproto.Message, 1024),
		frames:       make(map[cdp.FrameID]*cdp.Frame),

		logf: b.logf,
		errf: b.errf,
	}

	// This send should be blocking, to ensure the tab is inserted into the
	// map before any more target events are routed.
	select {
	case <-ctx.Done():
		return nil, ctx.Err()
	case b.newTabQueue <- t:
	}
	return t, nil
}

func (b *Browser) Execute(ctx context.Context, method string, params easyjson.Marshaler, res easyjson.Unmarshaler) error {
	if method == browser.CommandClose {
		return fmt.Errorf("to close the browser, cancel its context or use chromedp.Cancel")
	}

	id := atomic.AddInt64(&b.next, 1)
	lctx, cancel := context.WithCancel(ctx)
	ch := make(chan *cdproto.Message, 1)
	fn := func(ev interface{}) {
		if msg, ok := ev.(*cdproto.Message); ok && msg.ID == id {
			select {
			case <-ctx.Done():
			case ch <- msg:
			}
			cancel()
		}
	}
	b.listenersMu.Lock()
	b.listeners = append(b.listeners, cancelableListener{lctx, fn})
	b.listenersMu.Unlock()

	// send command
	var buf []byte
	if params != nil {
		var err error
		buf, err = easyjson.Marshal(params)
		if err != nil {
			return err
		}
	}
	cmd := &cdproto.Message{
		ID:     id,
		Method: cdproto.MethodType(method),
		Params: buf,
	}
	select {
	case <-ctx.Done():
		return ctx.Err()
	case b.cmdQueue <- cmd:
	}

	// wait for result
	select {
	case <-ctx.Done():
		return ctx.Err()
	case msg := <-ch:
		switch {
		case msg == nil:
			return ErrChannelClosed
		case msg.Error != nil:
			return msg.Error
		case res != nil:
			return easyjson.Unmarshal(msg.Result, res)
		}
	}
	return nil
}

func (b *Browser) run(ctx context.Context) {
	defer b.conn.Close()

	// incomingQueue is the queue of incoming target events, to be routed by
	// their session ID.
	incomingQueue := make(chan *cdproto.Message, 1)

	delTabQueue := make(chan target.SessionID, 1)

	// This goroutine continuously reads events from the websocket
	// connection. The separate goroutine is needed since a websocket read
	// is blocking, so it cannot be used in a select statement.
	go func() {
		for {
			msg := new(cdproto.Message)
			if err := b.conn.Read(ctx, msg); err != nil {
				// If the websocket failed, most likely Chrome was closed or
				// crashed. Signal that so the entire browser handler can be
				// stopped.
				close(b.LostConnection)
				return
			}

			switch {
			case msg.SessionID != "" && (msg.Method != "" || msg.ID != 0):
				select {
				case <-ctx.Done():
					return
				case incomingQueue <- msg:
				}

			case msg.Method != "":
				ev, err := cdproto.UnmarshalMessage(msg)
				if err != nil {
					b.errf("%s", err)
					continue
				}
				b.listenersMu.Lock()
				b.listeners = runListeners(b.listeners, ev)
				b.listenersMu.Unlock()

				if ev, ok := ev.(*target.EventDetachedFromTarget); ok {
					delTabQueue <- ev.SessionID
				}

			case msg.ID != 0:
				b.listenersMu.Lock()
				b.listeners = runListeners(b.listeners, msg)
				b.listenersMu.Unlock()

			default:
				b.errf("ignoring malformed incoming message (missing id or method): %#v", msg)
			}
		}
	}()

	b.pages = make(map[target.SessionID]*Target, 32)
	for {
		select {
		case <-ctx.Done():
			return

		case msg := <-b.cmdQueue:
			if err := b.conn.Write(ctx, msg); err != nil {
				b.errf("%s", err)
				continue
			}

		case t := <-b.newTabQueue:
			if _, ok := b.pages[t.SessionID]; ok {
				b.errf("executor for %q already exists", t.SessionID)
			}
			b.pages[t.SessionID] = t

		case sessionID := <-delTabQueue:
			if _, ok := b.pages[sessionID]; !ok {
				b.errf("executor for %q doesn't exist", sessionID)
			}
			delete(b.pages, sessionID)

		case m := <-incomingQueue:
			page, ok := b.pages[m.SessionID]
			if !ok {
				// A page we recently closed still sending events.
				continue
			}

			select {
			case <-ctx.Done():
				return
			case page.messageQueue <- m:
			}

		case <-b.LostConnection:
			return // to avoid "write: broken pipe" errors
		}
	}
}

// BrowserOption is a browser option.
type BrowserOption = func(*Browser)

// WithBrowserLogf is a browser option to specify a func to receive general logging.
func WithBrowserLogf(f func(string, ...interface{})) BrowserOption {
	return func(b *Browser) { b.logf = f }
}

// WithBrowserErrorf is a browser option to specify a func to receive error logging.
func WithBrowserErrorf(f func(string, ...interface{})) BrowserOption {
	return func(b *Browser) { b.errf = f }
}

// WithBrowserDebugf is a browser option to specify a func to log actual
// websocket messages.
func WithBrowserDebugf(f func(string, ...interface{})) BrowserOption {
	return func(b *Browser) { b.dbgf = f }
}

// WithConsolef is a browser option to specify a func to receive chrome log events.
//
// Note: NOT YET IMPLEMENTED.
func WithConsolef(f func(string, ...interface{})) BrowserOption {
	return func(b *Browser) {}
}

// WithDialTimeout is a browser option to specify the timeout when dialing a
// browser's websocket address. The default is ten seconds; use a zero duration
// to not use a timeout.
func WithDialTimeout(d time.Duration) BrowserOption {
	return func(b *Browser) { b.dialTimeout = d }
}
<|endoftext|>


<commit_before>// Copyright 2022 The Ebitengine 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.

//go:build !android && !ios && !js && opengles

package opengl

import (
	"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl/gl"
)

// NewGraphics creates an implementation of graphicsdriver.Graphics for OpenGL.
// The returned graphics value is nil iff the error is not nil.
func NewGraphics() (graphicsdriver.Graphics, error) {
	g := &Graphics{}
	g.context.ctx = gl.DefaultContext{}
	return g, nil
}
<commit_msg>internal/graphicsdriver/opengl: bug fix: compile error<commit_after>// Copyright 2022 The Ebitengine 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.

//go:build !android && !ios && !js && opengles

package opengl

import (
	"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
	"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl/gl"
)

// NewGraphics creates an implementation of graphicsdriver.Graphics for OpenGL.
// The returned graphics value is nil iff the error is not nil.
func NewGraphics() (graphicsdriver.Graphics, error) {
	g := &Graphics{}
	g.context.ctx = gl.DefaultContext{}
	return g, nil
}
<|endoftext|>


<commit_before>package workflow

import (
	"bytes"
	"fmt"
	"strings"

	"github.com/fsamin/go-dump"
	"github.com/go-gorp/gorp"

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

func getNodeJobRunParameters(db gorp.SqlExecutor, j sdk.Job, run *sdk.WorkflowNodeRun, stage *sdk.Stage) ([]sdk.Parameter, *sdk.MultiError) {
	params := run.BuildParameters
	tmp := map[string]string{}

	tmp["cds.stage"] = stage.Name
	tmp["cds.job"] = j.Action.Name
	errm := &sdk.MultiError{}

	for k, v := range tmp {
		s, err := sdk.Interpolate(v, tmp)
		if err != nil {
			errm.Append(err)
			continue
		}
		sdk.AddParameter(&params, k, sdk.StringParameter, s)
	}

	if errm.IsEmpty() {
		return params, nil
	}
	return params, errm
}

// GetNodeBuildParameters returns build parameters with default values for cds.version, cds.run, cds.run.number, cds.run.subnumber
func GetNodeBuildParameters(proj *sdk.Project, w *sdk.Workflow, n *sdk.WorkflowNode, pipelineParameters []sdk.Parameter, payload interface{}) ([]sdk.Parameter, error) {
	vars := map[string]string{}
	tmpProj := sdk.ParametersFromProjectVariables(proj)
	for k, v := range tmpProj {
		vars[k] = v
	}

	// compute application variables
	if n.Context != nil && n.Context.Application != nil {
		vars["cds.application"] = n.Context.Application.Name
		tmp := sdk.ParametersFromApplicationVariables(n.Context.Application)
		for k, v := range tmp {
			vars[k] = v
		}
	}

	// compute environment variables
	if n.Context != nil && n.Context.Environment != nil {
		vars["cds.environment"] = n.Context.Environment.Name
		tmp := sdk.ParametersFromEnvironmentVariables(n.Context.Environment)
		for k, v := range tmp {
			vars[k] = v
		}
	}

	// compute pipeline parameters
	tmpPip := sdk.ParametersFromPipelineParameters(pipelineParameters)
	for k, v := range tmpPip {
		vars[k] = v
	}

	// compute payload
	errm := &sdk.MultiError{}
	e := dump.NewDefaultEncoder(new(bytes.Buffer))
	e.Formatters = []dump.KeyFormatterFunc{dump.WithDefaultLowerCaseFormatter()}
	e.ExtraFields.DetailedMap = false
	e.ExtraFields.DetailedStruct = false
	e.ExtraFields.Len = false
	e.ExtraFields.Type = false
	vars, errdump := e.ToStringMap(payload)

	if errdump != nil {
		log.Error("GetNodeBuildParameters> do-dump error: %v", errdump)
		errm.Append(errdump)
	}

	log.Debug("GetNodeBuildParameters> compute payload :%#v", payload)

	// TODO Update suggest.go  with new variable

	vars["cds.project"] = w.ProjectKey
	vars["cds.workflow"] = w.Name
	vars["cds.pipeline"] = n.Pipeline.Name

	params := []sdk.Parameter{}
	for k, v := range vars {
		sdk.AddParameter(&params, k, sdk.StringParameter, v)
	}

	if errm.IsEmpty() {
		return params, nil
	}

	return params, errm
}

func getParentParameters(db gorp.SqlExecutor, run *sdk.WorkflowNodeRun, nodeRunIds []int64, payload map[string]string) ([]sdk.Parameter, error) {
	//Load workflow run
	w, err := LoadRunByID(db, run.WorkflowRunID)
	if err != nil {
		return nil, sdk.WrapError(err, "getParentParameters> Unable to load workflow run")
	}

	params := []sdk.Parameter{}
	for _, nodeRunID := range nodeRunIds {
		parentNodeRun, errNR := LoadNodeRunByID(db, nodeRunID)
		if errNR != nil {
			return nil, sdk.WrapError(errNR, "getParentParameters> Cannot get parent node run")
		}

		node := w.Workflow.GetNode(parentNodeRun.WorkflowNodeID)
		if node == nil {
			return nil, sdk.WrapError(fmt.Errorf("Unable to find node %d in workflow", parentNodeRun.WorkflowNodeID), "getParentParameters>")
		}

		for i := range parentNodeRun.BuildParameters {
			p := &parentNodeRun.BuildParameters[i]

			if p.Name == "" || p.Name == "cds.semver" || p.Name == "cds.release.version" ||
				strings.HasPrefix(p.Name, "cds.proj") || strings.HasPrefix(p.Name, "workflow.") ||
				strings.HasPrefix(p.Name, "cds.version") || strings.HasPrefix(p.Name, "cds.run.number") ||
				strings.HasPrefix(p.Name, "cds.workflow") {
				continue
			}

			// Do not duplicate variable from payload
			if _, ok := payload[p.Name]; ok {
				continue
			}

			prefix := "workflow." + node.Name + "."
			if strings.HasPrefix(p.Name, "cds.") {
				p.Name = strings.Replace(p.Name, "cds.", prefix, 1)
			} else {
				p.Name = prefix + p.Name
			}
		}
		params = append(params, parentNodeRun.BuildParameters...)
	}
	return params, nil
}

func getNodeRunBuildParameters(db gorp.SqlExecutor, proj *sdk.Project, run *sdk.WorkflowNodeRun) ([]sdk.Parameter, error) {
	//Load workflow run
	w, err := LoadRunByID(db, run.WorkflowRunID)
	if err != nil {
		return nil, sdk.WrapError(err, "getNodeRunParameters> Unable to load workflow run")
	}

	//Load node definition
	n := w.Workflow.GetNode(run.WorkflowNodeID)
	if n == nil {
		return nil, sdk.WrapError(fmt.Errorf("Unable to find node %d in workflow", run.WorkflowNodeID), "getNodeRunParameters>")
	}

	//Get node build parameters
	errm := &sdk.MultiError{}
	params, errparam := GetNodeBuildParameters(proj, &w.Workflow, n, run.PipelineParameters, run.Payload)
	if errparam != nil {
		err, ok := errparam.(*sdk.MultiError)
		if ok {
			errm = err
		} else {
			return nil, sdk.WrapError(err, "getNodeRunParameters> Unable to compute node build parameters")
		}
	}

	//override default parameters value
	tmp := sdk.ParametersToMap(params)
	tmp["cds.version"] = fmt.Sprintf("%d", run.Number)
	tmp["cds.run"] = fmt.Sprintf("%d.%d", run.Number, run.SubNumber)
	tmp["cds.run.number"] = fmt.Sprintf("%d", run.Number)
	tmp["cds.run.subnumber"] = fmt.Sprintf("%d", run.SubNumber)

	params = []sdk.Parameter{}
	for k, v := range tmp {
		s, err := sdk.Interpolate(v, tmp)
		if err != nil {
			errm.Append(err)
			continue
		}
		sdk.AddParameter(&params, k, sdk.StringParameter, s)
	}

	if errm.IsEmpty() {
		return params, nil
	}

	return params, errm
}
<commit_msg>fix (api): missing context variables in workflow run (#1405)<commit_after>package workflow

import (
	"bytes"
	"fmt"
	"strings"

	"github.com/fsamin/go-dump"
	"github.com/go-gorp/gorp"

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

func getNodeJobRunParameters(db gorp.SqlExecutor, j sdk.Job, run *sdk.WorkflowNodeRun, stage *sdk.Stage) ([]sdk.Parameter, *sdk.MultiError) {
	params := run.BuildParameters
	tmp := map[string]string{}

	tmp["cds.stage"] = stage.Name
	tmp["cds.job"] = j.Action.Name
	errm := &sdk.MultiError{}

	for k, v := range tmp {
		s, err := sdk.Interpolate(v, tmp)
		if err != nil {
			errm.Append(err)
			continue
		}
		sdk.AddParameter(&params, k, sdk.StringParameter, s)
	}

	if errm.IsEmpty() {
		return params, nil
	}
	return params, errm
}

// GetNodeBuildParameters returns build parameters with default values for cds.version, cds.run, cds.run.number, cds.run.subnumber
func GetNodeBuildParameters(proj *sdk.Project, w *sdk.Workflow, n *sdk.WorkflowNode, pipelineParameters []sdk.Parameter, payload interface{}) ([]sdk.Parameter, error) {
	vars := map[string]string{}
	tmpProj := sdk.ParametersFromProjectVariables(proj)
	for k, v := range tmpProj {
		vars[k] = v
	}

	// compute application variables
	if n.Context != nil && n.Context.Application != nil {
		vars["cds.application"] = n.Context.Application.Name
		tmp := sdk.ParametersFromApplicationVariables(n.Context.Application)
		for k, v := range tmp {
			vars[k] = v
		}
	}

	// compute environment variables
	if n.Context != nil && n.Context.Environment != nil {
		vars["cds.environment"] = n.Context.Environment.Name
		tmp := sdk.ParametersFromEnvironmentVariables(n.Context.Environment)
		for k, v := range tmp {
			vars[k] = v
		}
	}

	// compute pipeline parameters
	tmpPip := sdk.ParametersFromPipelineParameters(pipelineParameters)
	for k, v := range tmpPip {
		vars[k] = v
	}

	// compute payload
	errm := &sdk.MultiError{}
	e := dump.NewDefaultEncoder(new(bytes.Buffer))
	e.Formatters = []dump.KeyFormatterFunc{dump.WithDefaultLowerCaseFormatter()}
	e.ExtraFields.DetailedMap = false
	e.ExtraFields.DetailedStruct = false
	e.ExtraFields.Len = false
	e.ExtraFields.Type = false
	tmpVars, errdump := e.ToStringMap(payload)
	if errdump != nil {
		log.Error("GetNodeBuildParameters> do-dump error: %v", errdump)
		errm.Append(errdump)
	}

	//Merge the dumped payload with vars
	vars = sdk.ParametersMapMerge(vars, tmpVars)

	log.Debug("GetNodeBuildParameters> compute payload :%#v", payload)

	// TODO Update suggest.go  with new variable

	vars["cds.project"] = w.ProjectKey
	vars["cds.workflow"] = w.Name
	vars["cds.pipeline"] = n.Pipeline.Name

	params := []sdk.Parameter{}
	for k, v := range vars {
		sdk.AddParameter(&params, k, sdk.StringParameter, v)
	}

	if errm.IsEmpty() {
		return params, nil
	}

	return params, errm
}

func getParentParameters(db gorp.SqlExecutor, run *sdk.WorkflowNodeRun, nodeRunIds []int64, payload map[string]string) ([]sdk.Parameter, error) {
	//Load workflow run
	w, err := LoadRunByID(db, run.WorkflowRunID)
	if err != nil {
		return nil, sdk.WrapError(err, "getParentParameters> Unable to load workflow run")
	}

	params := []sdk.Parameter{}
	for _, nodeRunID := range nodeRunIds {
		parentNodeRun, errNR := LoadNodeRunByID(db, nodeRunID)
		if errNR != nil {
			return nil, sdk.WrapError(errNR, "getParentParameters> Cannot get parent node run")
		}

		node := w.Workflow.GetNode(parentNodeRun.WorkflowNodeID)
		if node == nil {
			return nil, sdk.WrapError(fmt.Errorf("Unable to find node %d in workflow", parentNodeRun.WorkflowNodeID), "getParentParameters>")
		}

		for i := range parentNodeRun.BuildParameters {
			p := &parentNodeRun.BuildParameters[i]

			if p.Name == "" || p.Name == "cds.semver" || p.Name == "cds.release.version" ||
				strings.HasPrefix(p.Name, "cds.proj") || strings.HasPrefix(p.Name, "workflow.") ||
				strings.HasPrefix(p.Name, "cds.version") || strings.HasPrefix(p.Name, "cds.run.number") ||
				strings.HasPrefix(p.Name, "cds.workflow") {
				continue
			}

			// Do not duplicate variable from payload
			if _, ok := payload[p.Name]; ok {
				continue
			}

			prefix := "workflow." + node.Name + "."
			if strings.HasPrefix(p.Name, "cds.") {
				p.Name = strings.Replace(p.Name, "cds.", prefix, 1)
			} else {
				p.Name = prefix + p.Name
			}
		}
		params = append(params, parentNodeRun.BuildParameters...)
	}
	return params, nil
}

func getNodeRunBuildParameters(db gorp.SqlExecutor, proj *sdk.Project, run *sdk.WorkflowNodeRun) ([]sdk.Parameter, error) {
	//Load workflow run
	w, err := LoadRunByID(db, run.WorkflowRunID)
	if err != nil {
		return nil, sdk.WrapError(err, "getNodeRunParameters> Unable to load workflow run")
	}

	//Load node definition
	n := w.Workflow.GetNode(run.WorkflowNodeID)
	if n == nil {
		return nil, sdk.WrapError(fmt.Errorf("Unable to find node %d in workflow", run.WorkflowNodeID), "getNodeRunParameters>")
	}

	//Get node build parameters
	errm := &sdk.MultiError{}
	params, errparam := GetNodeBuildParameters(proj, &w.Workflow, n, run.PipelineParameters, run.Payload)
	if errparam != nil {
		err, ok := errparam.(*sdk.MultiError)
		if ok {
			errm = err
		} else {
			return nil, sdk.WrapError(err, "getNodeRunParameters> Unable to compute node build parameters")
		}
	}

	//override default parameters value
	tmp := sdk.ParametersToMap(params)
	tmp["cds.version"] = fmt.Sprintf("%d", run.Number)
	tmp["cds.run"] = fmt.Sprintf("%d.%d", run.Number, run.SubNumber)
	tmp["cds.run.number"] = fmt.Sprintf("%d", run.Number)
	tmp["cds.run.subnumber"] = fmt.Sprintf("%d", run.SubNumber)

	params = []sdk.Parameter{}
	for k, v := range tmp {
		s, err := sdk.Interpolate(v, tmp)
		if err != nil {
			errm.Append(err)
			continue
		}
		sdk.AddParameter(&params, k, sdk.StringParameter, s)
	}

	if errm.IsEmpty() {
		return params, nil
	}

	return params, errm
}
<|endoftext|>