<commit_before>package cmd

import (
	"fmt"
	"log"
	"strings"

	"github.com/pkg/errors"
	"github.com/rsteube/carapace"
	"github.com/spf13/cobra"
	"github.com/zaquestion/lab/internal/action"
	lab "github.com/zaquestion/lab/internal/gitlab"
)

var labelListCmd = &cobra.Command{
	Use:     "list [remote] [search]",
	Aliases: []string{"ls", "search"},
	Short:   "List labels",
	Long:    ``,
	Example: `lab label list                       # list all labels
lab label list "search term"         # search labels for "search term"
lab label search "search term"       # same as above
lab label list remote "search term"  # search "remote" for labels with "search term"`,
	PersistentPreRun: LabPersistentPreRun,
	Run: func(cmd *cobra.Command, args []string) {
		rn, labelSearch, err := parseArgsRemoteAndProject(args)
		if err != nil {
			log.Fatal(err)
		}

		labelSearch = strings.ToLower(labelSearch)

		labels, err := lab.LabelList(rn)
		if err != nil {
			log.Fatal(err)
		}

		pager := NewPager(cmd.Flags())
		defer pager.Close()

		for _, label := range labels {
			// GitLab API has no search for labels, so we do it ourselves
			if labelSearch != "" &&
				!(strings.Contains(strings.ToLower(label.Name), labelSearch) || strings.Contains(strings.ToLower(label.Description), labelSearch)) {
				continue
			}

			description := ""
			if label.Description != "" {
				description = " - " + label.Description
			}

			fmt.Printf("%s%s\n", label.Name, description)
		}
	},
}

func MapLabels(rn string, labelTerms []string) ([]string, error) {
	labels, err := lab.LabelList(rn)
	if err != nil {
		return nil, err
	}

	matches := make([]string, len(labelTerms))
	for i, term := range labelTerms {
		lowerTerm := strings.ToLower(term)
		for _, label := range labels {
			lowerLabel := strings.ToLower(label.Name)

			// no match, or we already have an exact match
			if !strings.Contains(lowerLabel, lowerTerm) || matches[i] == lowerLabel {
				continue
			}

			// only allow ambiguity for exact matches
			if matches[i] != "" && lowerTerm != lowerLabel {
				return nil, errors.Errorf("Label '%s' is ambiguous", term)
			}

			matches[i] = label.Name
		}

		if matches[i] == "" {
			return nil, errors.Errorf("Label '%s' not found", term)
		}
	}

	return matches, nil
}

func init() {
	labelCmd.AddCommand(labelListCmd)
	carapace.Gen(labelCmd).PositionalCompletion(
		action.Remotes(),
	)
}
<commit_msg>label_list: fix exact match after substring matches<commit_after>package cmd

import (
	"fmt"
	"log"
	"strings"

	"github.com/pkg/errors"
	"github.com/rsteube/carapace"
	"github.com/spf13/cobra"
	"github.com/zaquestion/lab/internal/action"
	lab "github.com/zaquestion/lab/internal/gitlab"
)

var labelListCmd = &cobra.Command{
	Use:     "list [remote] [search]",
	Aliases: []string{"ls", "search"},
	Short:   "List labels",
	Long:    ``,
	Example: `lab label list                       # list all labels
lab label list "search term"         # search labels for "search term"
lab label search "search term"       # same as above
lab label list remote "search term"  # search "remote" for labels with "search term"`,
	PersistentPreRun: LabPersistentPreRun,
	Run: func(cmd *cobra.Command, args []string) {
		rn, labelSearch, err := parseArgsRemoteAndProject(args)
		if err != nil {
			log.Fatal(err)
		}

		labelSearch = strings.ToLower(labelSearch)

		labels, err := lab.LabelList(rn)
		if err != nil {
			log.Fatal(err)
		}

		pager := NewPager(cmd.Flags())
		defer pager.Close()

		for _, label := range labels {
			// GitLab API has no search for labels, so we do it ourselves
			if labelSearch != "" &&
				!(strings.Contains(strings.ToLower(label.Name), labelSearch) || strings.Contains(strings.ToLower(label.Description), labelSearch)) {
				continue
			}

			description := ""
			if label.Description != "" {
				description = " - " + label.Description
			}

			fmt.Printf("%s%s\n", label.Name, description)
		}
	},
}

func MapLabels(rn string, labelTerms []string) ([]string, error) {
	var ambiguous bool

	labels, err := lab.LabelList(rn)
	if err != nil {
		return nil, err
	}

	matches := make([]string, len(labelTerms))
	for i, term := range labelTerms {
		ambiguous = false
		lowerTerm := strings.ToLower(term)
		for _, label := range labels {
			lowerLabel := strings.ToLower(label.Name)

			// no match
			if !strings.Contains(lowerLabel, lowerTerm) {
				continue
			}

			// check for ambiguity on substring level
			if matches[i] != "" && lowerTerm != lowerLabel {
				ambiguous = true
				continue
			}

			matches[i] = label.Name

			// exact match
			// may happen after multiple substring matches
			if lowerLabel == lowerTerm {
				ambiguous = false
				break
			}
		}

		if matches[i] == "" {
			return nil, errors.Errorf("Label '%s' not found", term)
		}

		// Ambiguous matches should not be returned to avoid
		// manipulating the wrong label.
		if ambiguous {
			return nil, errors.Errorf("Label '%s' has no exact match and is ambiguous\n", term)
		}
	}

	return matches, nil
}

func init() {
	labelCmd.AddCommand(labelListCmd)
	carapace.Gen(labelCmd).PositionalCompletion(
		action.Remotes(),
	)
}
<|endoftext|>


<commit_before>package router

import (
	"io"
	"sync"

	"golang.org/x/net/context"

	"google.golang.org/grpc"

	"github.com/TheThingsNetwork/ttn/api"
	pb_broker "github.com/TheThingsNetwork/ttn/api/broker"
	pb_discovery "github.com/TheThingsNetwork/ttn/api/discovery"
	pb_gateway "github.com/TheThingsNetwork/ttn/api/gateway"
	pb "github.com/TheThingsNetwork/ttn/api/router"
	"github.com/TheThingsNetwork/ttn/core/discovery"
	"github.com/TheThingsNetwork/ttn/core/router/gateway"
	"github.com/TheThingsNetwork/ttn/core/types"
)

// Router component
type Router interface {
	// Handle a status message from a gateway
	HandleGatewayStatus(gatewayEUI types.GatewayEUI, status *pb_gateway.Status) error
	// Handle an uplink message from a gateway
	HandleUplink(gatewayEUI types.GatewayEUI, uplink *pb.UplinkMessage) error
	// Handle a downlink message
	HandleDownlink(message *pb_broker.DownlinkMessage) error
	// Subscribe to downlink messages
	SubscribeDownlink(gatewayEUI types.GatewayEUI) (<-chan *pb.DownlinkMessage, error)
	// Unsubscribe from downlink messages
	UnsubscribeDownlink(gatewayEUI types.GatewayEUI) error
	// Handle a device activation
	HandleActivation(gatewayEUI types.GatewayEUI, activation *pb.DeviceActivationRequest) (*pb.DeviceActivationResponse, error)
}

type broker struct {
	client      pb_broker.BrokerClient
	association pb_broker.Broker_AssociateClient
}

type router struct {
	identity        *pb_discovery.Announcement
	gateways        map[types.GatewayEUI]*gateway.Gateway
	gatewaysLock    sync.RWMutex
	brokerDiscovery discovery.BrokerDiscovery
	brokers         map[string]*broker
	brokersLock     sync.RWMutex
}

// getGateway gets or creates a Gateway
func (r *router) getGateway(eui types.GatewayEUI) *gateway.Gateway {
	r.gatewaysLock.Lock()
	defer r.gatewaysLock.Unlock()
	if _, ok := r.gateways[eui]; !ok {
		r.gateways[eui] = gateway.NewGateway(eui)
	}
	return r.gateways[eui]
}

// getBroker gets or creates a broker association and returns the broker
// the first time it also starts a goroutine that receives downlink from the broker
func (r *router) getBroker(req *pb_discovery.Announcement) (*broker, error) {
	r.brokersLock.Lock()
	defer r.brokersLock.Unlock()
	if _, ok := r.brokers[req.NetAddress]; !ok {
		// Connect to the server
		conn, err := grpc.Dial(req.NetAddress, api.DialOptions...)
		if err != nil {
			return nil, err
		}
		client := pb_broker.NewBrokerClient(conn)

		association, err := client.Associate(context.Background())
		if err != nil {
			return nil, err
		}
		// Start a goroutine that receives and processes downlink
		go func() {
			for {
				downlink, err := association.Recv()
				if err == io.EOF {
					association.CloseSend()
					break
				}
				if err != nil {
					break
				}
				go r.HandleDownlink(downlink)
			}
			// When the loop is broken: close connection and unregister broker.
			conn.Close()
			r.brokersLock.Lock()
			defer r.brokersLock.Unlock()
			delete(r.brokers, req.NetAddress)
		}()
		r.brokers[req.NetAddress] = &broker{
			client:      client,
			association: association,
		}
	}
	return r.brokers[req.NetAddress], nil
}
<commit_msg>[router] More efficient gateway and broker lookup<commit_after>package router

import (
	"io"
	"sync"

	"golang.org/x/net/context"

	"google.golang.org/grpc"

	"github.com/TheThingsNetwork/ttn/api"
	pb_broker "github.com/TheThingsNetwork/ttn/api/broker"
	pb_discovery "github.com/TheThingsNetwork/ttn/api/discovery"
	pb_gateway "github.com/TheThingsNetwork/ttn/api/gateway"
	pb "github.com/TheThingsNetwork/ttn/api/router"
	"github.com/TheThingsNetwork/ttn/core/discovery"
	"github.com/TheThingsNetwork/ttn/core/router/gateway"
	"github.com/TheThingsNetwork/ttn/core/types"
)

// Router component
type Router interface {
	// Handle a status message from a gateway
	HandleGatewayStatus(gatewayEUI types.GatewayEUI, status *pb_gateway.Status) error
	// Handle an uplink message from a gateway
	HandleUplink(gatewayEUI types.GatewayEUI, uplink *pb.UplinkMessage) error
	// Handle a downlink message
	HandleDownlink(message *pb_broker.DownlinkMessage) error
	// Subscribe to downlink messages
	SubscribeDownlink(gatewayEUI types.GatewayEUI) (<-chan *pb.DownlinkMessage, error)
	// Unsubscribe from downlink messages
	UnsubscribeDownlink(gatewayEUI types.GatewayEUI) error
	// Handle a device activation
	HandleActivation(gatewayEUI types.GatewayEUI, activation *pb.DeviceActivationRequest) (*pb.DeviceActivationResponse, error)
}

type broker struct {
	client      pb_broker.BrokerClient
	association pb_broker.Broker_AssociateClient
}

type router struct {
	identity        *pb_discovery.Announcement
	gateways        map[types.GatewayEUI]*gateway.Gateway
	gatewaysLock    sync.RWMutex
	brokerDiscovery discovery.BrokerDiscovery
	brokers         map[string]*broker
	brokersLock     sync.RWMutex
}

// getGateway gets or creates a Gateway
func (r *router) getGateway(eui types.GatewayEUI) *gateway.Gateway {
	// We're going to be optimistic and guess that the gateway is already active
	r.gatewaysLock.RLock()
	gtw, ok := r.gateways[eui]
	r.gatewaysLock.RUnlock()
	if ok {
		return gtw
	}
	// If it doesn't we still have to lock
	r.gatewaysLock.Lock()
	defer r.gatewaysLock.Unlock()
	if _, ok := r.gateways[eui]; !ok {
		r.gateways[eui] = gateway.NewGateway(eui)
	}
	return r.gateways[eui]
}

// getBroker gets or creates a broker association and returns the broker
// the first time it also starts a goroutine that receives downlink from the broker
func (r *router) getBroker(req *pb_discovery.Announcement) (*broker, error) {
	// We're going to be optimistic and guess that the broker is already active
	r.brokersLock.RLock()
	brk, ok := r.brokers[req.NetAddress]
	r.brokersLock.RUnlock()
	if ok {
		return brk, nil
	}
	// If it doesn't we still have to lock
	r.brokersLock.Lock()
	defer r.brokersLock.Unlock()
	if _, ok := r.brokers[req.NetAddress]; !ok {
		// Connect to the server
		conn, err := grpc.Dial(req.NetAddress, api.DialOptions...)
		if err != nil {
			return nil, err
		}
		client := pb_broker.NewBrokerClient(conn)

		association, err := client.Associate(context.Background())
		if err != nil {
			return nil, err
		}
		// Start a goroutine that receives and processes downlink
		go func() {
			for {
				downlink, err := association.Recv()
				if err == io.EOF {
					association.CloseSend()
					break
				}
				if err != nil {
					break
				}
				go r.HandleDownlink(downlink)
			}
			// When the loop is broken: close connection and unregister broker.
			conn.Close()
			r.brokersLock.Lock()
			defer r.brokersLock.Unlock()
			delete(r.brokers, req.NetAddress)
		}()
		r.brokers[req.NetAddress] = &broker{
			client:      client,
			association: association,
		}
	}
	return r.brokers[req.NetAddress], nil
}
<|endoftext|>


<commit_before>package qemu

import (
	"errors"
	"fmt"
	"os"
	"os/exec"
	"strconv"
	"strings"

	"github.com/golang/glog"
	"github.com/hyperhq/runv/hypervisor"
	"github.com/hyperhq/runv/hypervisor/types"
)

//implement the hypervisor.HypervisorDriver interface
type QemuDriver struct {
	executable string
}

//implement the hypervisor.DriverContext interface
type QemuContext struct {
	driver      *QemuDriver
	qmp         chan QmpInteraction
	waitQmp     chan int
	wdt         chan string
	qmpSockName string
	qemuPidFile string
	qemuLogFile string
	cpus        int
	process     *os.Process
}

func qemuContext(ctx *hypervisor.VmContext) *QemuContext {
	return ctx.DCtx.(*QemuContext)
}

func InitDriver() *QemuDriver {
	cmd, err := exec.LookPath("qemu-system-x86_64")
	if err != nil {
		return nil
	}

	return &QemuDriver{
		executable: cmd,
	}
}

func (qd *QemuDriver) InitContext(homeDir string) hypervisor.DriverContext {
	if _, err := os.Stat(QemuLogDir); os.IsNotExist(err) {
		os.Mkdir(QemuLogDir, 0755)
	}

	qemuLogFile := QemuLogDir + "/" + homeDir[strings.Index(homeDir, "vm-"):len(homeDir)-1] + ".log"
	if _, err := os.Create(qemuLogFile); err != nil {
		glog.Errorf("create qemu log file failed: %v", err)
	}

	return &QemuContext{
		driver:      qd,
		qmp:         make(chan QmpInteraction, 128),
		wdt:         make(chan string, 16),
		waitQmp:     make(chan int, 1),
		qmpSockName: homeDir + QmpSockName,
		qemuPidFile: homeDir + QemuPidFile,
		qemuLogFile: qemuLogFile,
		process:     nil,
	}
}

func (qd *QemuDriver) LoadContext(persisted map[string]interface{}) (hypervisor.DriverContext, error) {
	if t, ok := persisted["hypervisor"]; !ok || t != "qemu" {
		return nil, errors.New("wrong driver type in persist info")
	}

	var sock string
	var proc *os.Process = nil
	var err error

	s, ok := persisted["qmpSock"]
	if !ok {
		return nil, errors.New("cannot read the qmp socket info from persist info")
	} else {
		switch s.(type) {
		case string:
			sock = s.(string)
		default:
			return nil, errors.New("wrong sock name type in persist info")
		}
	}

	p, ok := persisted["pid"]
	if !ok {
		return nil, errors.New("cannot read the pid info from persist info")
	} else {
		switch p.(type) {
		case float64:
			proc, err = os.FindProcess(int(p.(float64)))
			if err != nil {
				return nil, err
			}
		default:
			return nil, errors.New("wrong pid field type in persist info")
		}
	}

	return &QemuContext{
		driver:      qd,
		qmp:         make(chan QmpInteraction, 128),
		wdt:         make(chan string, 16),
		waitQmp:     make(chan int, 1),
		qmpSockName: sock,
		process:     proc,
	}, nil
}

func (qc *QemuContext) Launch(ctx *hypervisor.VmContext) {
	go launchQemu(qc, ctx)
	go qmpHandler(ctx)
}

func (qc *QemuContext) Associate(ctx *hypervisor.VmContext) {
	go associateQemu(ctx)
	go qmpHandler(ctx)
}

func (qc *QemuContext) Dump() (map[string]interface{}, error) {
	if qc.process == nil {
		return nil, errors.New("can not serialize qemu context: no process running")
	}

	return map[string]interface{}{
		"hypervisor": "qemu",
		"qmpSock":    qc.qmpSockName,
		"pid":        qc.process.Pid,
	}, nil
}

func (qc *QemuContext) Shutdown(ctx *hypervisor.VmContext) {
	qmpQemuQuit(ctx, qc)
}

func (qc *QemuContext) Kill(ctx *hypervisor.VmContext) {
	defer func() {
		err := recover()
		if glog.V(1) && err != nil {
			glog.Info("kill qemu, but channel has already been closed")
		}
	}()
	qc.wdt <- "kill"
}

func (qc *QemuContext) Stats(ctx *hypervisor.VmContext) (*types.PodStats, error) {
	return nil, nil
}

func (qc *QemuContext) Close() {
	qc.wdt <- "quit"
	<-qc.waitQmp
	close(qc.qmp)
	close(qc.wdt)
}

func (qc *QemuContext) Pause(ctx *hypervisor.VmContext, pause bool, result chan<- error) {
	commands := make([]*QmpCommand, 1)

	if pause {
		commands[0] = &QmpCommand{
			Execute: "stop",
		}
	} else {
		commands[0] = &QmpCommand{
			Execute: "cont",
		}
	}

	qc.qmp <- &QmpSession{
		commands: commands,
		respond: func(err error) {
			result <- err
		},
	}
}

func (qc *QemuContext) AddDisk(ctx *hypervisor.VmContext, sourceType string, blockInfo *hypervisor.BlockDescriptor) {
	name := blockInfo.Name
	filename := blockInfo.Filename
	format := blockInfo.Format
	id := blockInfo.ScsiId

	if format == "rbd" {
		if blockInfo.Options != nil {
			keyring := blockInfo.Options["keyring"]
			user := blockInfo.Options["user"]
			if keyring != "" && user != "" {
				filename += ":id=" + user + ":key=" + keyring
			}

			monitors := blockInfo.Options["monitors"]
			for i, m := range strings.Split(monitors, ";") {
				monitor := strings.Replace(m, ":", "\\:", -1)
				if i == 0 {
					filename += ":mon_host=" + monitor
					continue
				}
				filename += ";" + monitor
			}
		}
	}

	newDiskAddSession(ctx, qc, name, sourceType, filename, format, id)
}

func (qc *QemuContext) RemoveDisk(ctx *hypervisor.VmContext, blockInfo *hypervisor.BlockDescriptor, callback hypervisor.VmEvent) {
	id := blockInfo.ScsiId

	newDiskDelSession(ctx, qc, id, callback)
}

func (qc *QemuContext) AddNic(ctx *hypervisor.VmContext, host *hypervisor.HostNicInfo, guest *hypervisor.GuestNicInfo, result chan<- hypervisor.VmEvent) {
	newNetworkAddSession(ctx, qc, host.Fd, guest.Device, host.Mac, guest.Index, guest.Busaddr, result)
}

func (qc *QemuContext) RemoveNic(ctx *hypervisor.VmContext, n *hypervisor.InterfaceCreated, callback hypervisor.VmEvent) {
	newNetworkDelSession(ctx, qc, n.DeviceName, callback)
}

func (qc *QemuContext) SetCpus(ctx *hypervisor.VmContext, cpus int, result chan<- error) {
	currcpus := qc.cpus

	if cpus < currcpus {
		result <- fmt.Errorf("can't reduce cpus number from %d to %d", currcpus, cpus)
		return
	} else if cpus == currcpus {
		result <- nil
		return
	}

	commands := make([]*QmpCommand, cpus-currcpus)
	for id := currcpus; id < cpus; id++ {
		commands[id-currcpus] = &QmpCommand{
			Execute: "cpu-add",
			Arguments: map[string]interface{}{
				"id": id,
			},
		}
	}

	qc.qmp <- &QmpSession{
		commands: commands,
		respond: func(err error) {
			if err == nil {
				qc.cpus = cpus
			}
			result <- err
		},
	}
}

func (qc *QemuContext) AddMem(ctx *hypervisor.VmContext, slot, size int, result chan<- error) {
	commands := make([]*QmpCommand, 2)
	commands[0] = &QmpCommand{
		Execute: "object-add",
		Arguments: map[string]interface{}{
			"qom-type": "memory-backend-ram",
			"id":       "mem" + strconv.Itoa(slot),
			"props":    map[string]interface{}{"size": int64(size) << 20},
		},
	}
	commands[1] = &QmpCommand{
		Execute: "device_add",
		Arguments: map[string]interface{}{
			"driver": "pc-dimm",
			"id":     "dimm" + strconv.Itoa(slot),
			"memdev": "mem" + strconv.Itoa(slot),
		},
	}
	qc.qmp <- &QmpSession{
		commands: commands,
		respond:  func(err error) { result <- err },
	}
}

func (qc *QemuContext) Save(ctx *hypervisor.VmContext, path string, result chan<- error) {
	commands := make([]*QmpCommand, 1)

	commands[0] = &QmpCommand{
		Execute: "migrate",
		Arguments: map[string]interface{}{
			"uri": fmt.Sprintf("exec:cat>%s", path),
		},
	}

	// TODO: use query-migrate to query until completed
	qc.qmp <- &QmpSession{
		commands: commands,
		respond:  func(err error) { result <- err },
	}
}

func (qc *QemuDriver) SupportLazyMode() bool {
	return false
}

func (qc *QemuContext) arguments(ctx *hypervisor.VmContext) []string {
	if ctx.Boot == nil {
		ctx.Boot = &hypervisor.BootConfig{
			CPU:    1,
			Memory: 128,
			Kernel: hypervisor.DefaultKernel,
			Initrd: hypervisor.DefaultInitrd,
		}
	}
	boot := ctx.Boot
	qc.cpus = boot.CPU

	var machineClass, memParams, cpuParams string
	if ctx.Boot.HotAddCpuMem {
		machineClass = "pc-i440fx-2.1"
		memParams = fmt.Sprintf("size=%d,slots=1,maxmem=%dM", ctx.Boot.Memory, hypervisor.DefaultMaxMem) // TODO set maxmem to the total memory of the system
		cpuParams = fmt.Sprintf("cpus=%d,maxcpus=%d", ctx.Boot.CPU, hypervisor.DefaultMaxCpus)           // TODO set it to the cpus of the system
	} else {
		machineClass = "pc-i440fx-2.0"
		memParams = strconv.Itoa(ctx.Boot.Memory)
		cpuParams = strconv.Itoa(ctx.Boot.CPU)
	}

	params := []string{
		"-machine", machineClass + ",accel=kvm,usb=off", "-global", "kvm-pit.lost_tick_policy=discard", "-cpu", "host"}
	if _, err := os.Stat("/dev/kvm"); os.IsNotExist(err) {
		glog.V(1).Info("kvm not exist change to no kvm mode")
		params = []string{"-machine", machineClass + ",usb=off", "-cpu", "core2duo"}
	}

	if boot.Bios != "" && boot.Cbfs != "" {
		params = append(params,
			"-drive", fmt.Sprintf("if=pflash,file=%s,readonly=on", boot.Bios),
			"-drive", fmt.Sprintf("if=pflash,file=%s,readonly=on", boot.Cbfs))
	} else if boot.Bios != "" {
		params = append(params,
			"-bios", boot.Bios,
			"-kernel", boot.Kernel, "-initrd", boot.Initrd, "-append", "console=ttyS0 panic=1 no_timer_check")
	} else if boot.Cbfs != "" {
		params = append(params,
			"-drive", fmt.Sprintf("if=pflash,file=%s,readonly=on", boot.Cbfs))
	} else {
		params = append(params,
			"-kernel", boot.Kernel, "-initrd", boot.Initrd, "-append", "console=ttyS0 panic=1 no_timer_check")
	}

	return append(params,
		"-realtime", "mlock=off", "-no-user-config", "-nodefaults", "-no-hpet",
		"-rtc", "base=utc,driftfix=slew", "-no-reboot", "-display", "none", "-boot", "strict=on",
		"-m", memParams, "-smp", cpuParams,
		"-qmp", fmt.Sprintf("unix:%s,server,nowait", qc.qmpSockName), "-serial", fmt.Sprintf("unix:%s,server,nowait", ctx.ConsoleSockName),
		"-device", "virtio-serial-pci,id=virtio-serial0,bus=pci.0,addr=0x2", "-device", "virtio-scsi-pci,id=scsi0,bus=pci.0,addr=0x3",
		"-chardev", fmt.Sprintf("socket,id=charch0,path=%s,server,nowait", ctx.HyperSockName),
		"-device", "virtserialport,bus=virtio-serial0.0,nr=1,chardev=charch0,id=channel0,name=sh.hyper.channel.0",
		"-chardev", fmt.Sprintf("socket,id=charch1,path=%s,server,nowait", ctx.TtySockName),
		"-device", "virtserialport,bus=virtio-serial0.0,nr=2,chardev=charch1,id=channel1,name=sh.hyper.channel.1",
		"-fsdev", fmt.Sprintf("local,id=virtio9p,path=%s,security_model=none", ctx.ShareDir),
		"-device", fmt.Sprintf("virtio-9p-pci,fsdev=virtio9p,mount_tag=%s", hypervisor.ShareDirTag),
	)
}
<commit_msg>support template on qemu driver<commit_after>package qemu

import (
	"errors"
	"fmt"
	"os"
	"os/exec"
	"strconv"
	"strings"

	"github.com/golang/glog"
	"github.com/hyperhq/runv/hypervisor"
	"github.com/hyperhq/runv/hypervisor/types"
)

//implement the hypervisor.HypervisorDriver interface
type QemuDriver struct {
	executable string
}

//implement the hypervisor.DriverContext interface
type QemuContext struct {
	driver      *QemuDriver
	qmp         chan QmpInteraction
	waitQmp     chan int
	wdt         chan string
	qmpSockName string
	qemuPidFile string
	qemuLogFile string
	cpus        int
	process     *os.Process
}

func qemuContext(ctx *hypervisor.VmContext) *QemuContext {
	return ctx.DCtx.(*QemuContext)
}

func InitDriver() *QemuDriver {
	cmd, err := exec.LookPath("qemu-system-x86_64")
	if err != nil {
		return nil
	}

	return &QemuDriver{
		executable: cmd,
	}
}

func (qd *QemuDriver) InitContext(homeDir string) hypervisor.DriverContext {
	if _, err := os.Stat(QemuLogDir); os.IsNotExist(err) {
		os.Mkdir(QemuLogDir, 0755)
	}

	qemuLogFile := QemuLogDir + "/" + homeDir[strings.Index(homeDir, "vm-"):len(homeDir)-1] + ".log"
	if _, err := os.Create(qemuLogFile); err != nil {
		glog.Errorf("create qemu log file failed: %v", err)
	}

	return &QemuContext{
		driver:      qd,
		qmp:         make(chan QmpInteraction, 128),
		wdt:         make(chan string, 16),
		waitQmp:     make(chan int, 1),
		qmpSockName: homeDir + QmpSockName,
		qemuPidFile: homeDir + QemuPidFile,
		qemuLogFile: qemuLogFile,
		process:     nil,
	}
}

func (qd *QemuDriver) LoadContext(persisted map[string]interface{}) (hypervisor.DriverContext, error) {
	if t, ok := persisted["hypervisor"]; !ok || t != "qemu" {
		return nil, errors.New("wrong driver type in persist info")
	}

	var sock string
	var proc *os.Process = nil
	var err error

	s, ok := persisted["qmpSock"]
	if !ok {
		return nil, errors.New("cannot read the qmp socket info from persist info")
	} else {
		switch s.(type) {
		case string:
			sock = s.(string)
		default:
			return nil, errors.New("wrong sock name type in persist info")
		}
	}

	p, ok := persisted["pid"]
	if !ok {
		return nil, errors.New("cannot read the pid info from persist info")
	} else {
		switch p.(type) {
		case float64:
			proc, err = os.FindProcess(int(p.(float64)))
			if err != nil {
				return nil, err
			}
		default:
			return nil, errors.New("wrong pid field type in persist info")
		}
	}

	return &QemuContext{
		driver:      qd,
		qmp:         make(chan QmpInteraction, 128),
		wdt:         make(chan string, 16),
		waitQmp:     make(chan int, 1),
		qmpSockName: sock,
		process:     proc,
	}, nil
}

func (qc *QemuContext) Launch(ctx *hypervisor.VmContext) {
	go launchQemu(qc, ctx)
	go qmpHandler(ctx)
}

func (qc *QemuContext) Associate(ctx *hypervisor.VmContext) {
	go associateQemu(ctx)
	go qmpHandler(ctx)
}

func (qc *QemuContext) Dump() (map[string]interface{}, error) {
	if qc.process == nil {
		return nil, errors.New("can not serialize qemu context: no process running")
	}

	return map[string]interface{}{
		"hypervisor": "qemu",
		"qmpSock":    qc.qmpSockName,
		"pid":        qc.process.Pid,
	}, nil
}

func (qc *QemuContext) Shutdown(ctx *hypervisor.VmContext) {
	qmpQemuQuit(ctx, qc)
}

func (qc *QemuContext) Kill(ctx *hypervisor.VmContext) {
	defer func() {
		err := recover()
		if glog.V(1) && err != nil {
			glog.Info("kill qemu, but channel has already been closed")
		}
	}()
	qc.wdt <- "kill"
}

func (qc *QemuContext) Stats(ctx *hypervisor.VmContext) (*types.PodStats, error) {
	return nil, nil
}

func (qc *QemuContext) Close() {
	qc.wdt <- "quit"
	<-qc.waitQmp
	close(qc.qmp)
	close(qc.wdt)
}

func (qc *QemuContext) Pause(ctx *hypervisor.VmContext, pause bool, result chan<- error) {
	commands := make([]*QmpCommand, 1)

	if pause {
		commands[0] = &QmpCommand{
			Execute: "stop",
		}
	} else {
		commands[0] = &QmpCommand{
			Execute: "cont",
		}
	}

	qc.qmp <- &QmpSession{
		commands: commands,
		respond: func(err error) {
			result <- err
		},
	}
}

func (qc *QemuContext) AddDisk(ctx *hypervisor.VmContext, sourceType string, blockInfo *hypervisor.BlockDescriptor) {
	name := blockInfo.Name
	filename := blockInfo.Filename
	format := blockInfo.Format
	id := blockInfo.ScsiId

	if format == "rbd" {
		if blockInfo.Options != nil {
			keyring := blockInfo.Options["keyring"]
			user := blockInfo.Options["user"]
			if keyring != "" && user != "" {
				filename += ":id=" + user + ":key=" + keyring
			}

			monitors := blockInfo.Options["monitors"]
			for i, m := range strings.Split(monitors, ";") {
				monitor := strings.Replace(m, ":", "\\:", -1)
				if i == 0 {
					filename += ":mon_host=" + monitor
					continue
				}
				filename += ";" + monitor
			}
		}
	}

	newDiskAddSession(ctx, qc, name, sourceType, filename, format, id)
}

func (qc *QemuContext) RemoveDisk(ctx *hypervisor.VmContext, blockInfo *hypervisor.BlockDescriptor, callback hypervisor.VmEvent) {
	id := blockInfo.ScsiId

	newDiskDelSession(ctx, qc, id, callback)
}

func (qc *QemuContext) AddNic(ctx *hypervisor.VmContext, host *hypervisor.HostNicInfo, guest *hypervisor.GuestNicInfo, result chan<- hypervisor.VmEvent) {
	newNetworkAddSession(ctx, qc, host.Fd, guest.Device, host.Mac, guest.Index, guest.Busaddr, result)
}

func (qc *QemuContext) RemoveNic(ctx *hypervisor.VmContext, n *hypervisor.InterfaceCreated, callback hypervisor.VmEvent) {
	newNetworkDelSession(ctx, qc, n.DeviceName, callback)
}

func (qc *QemuContext) SetCpus(ctx *hypervisor.VmContext, cpus int, result chan<- error) {
	currcpus := qc.cpus

	if cpus < currcpus {
		result <- fmt.Errorf("can't reduce cpus number from %d to %d", currcpus, cpus)
		return
	} else if cpus == currcpus {
		result <- nil
		return
	}

	commands := make([]*QmpCommand, cpus-currcpus)
	for id := currcpus; id < cpus; id++ {
		commands[id-currcpus] = &QmpCommand{
			Execute: "cpu-add",
			Arguments: map[string]interface{}{
				"id": id,
			},
		}
	}

	qc.qmp <- &QmpSession{
		commands: commands,
		respond: func(err error) {
			if err == nil {
				qc.cpus = cpus
			}
			result <- err
		},
	}
}

func (qc *QemuContext) AddMem(ctx *hypervisor.VmContext, slot, size int, result chan<- error) {
	commands := make([]*QmpCommand, 2)
	commands[0] = &QmpCommand{
		Execute: "object-add",
		Arguments: map[string]interface{}{
			"qom-type": "memory-backend-ram",
			"id":       "mem" + strconv.Itoa(slot),
			"props":    map[string]interface{}{"size": int64(size) << 20},
		},
	}
	commands[1] = &QmpCommand{
		Execute: "device_add",
		Arguments: map[string]interface{}{
			"driver": "pc-dimm",
			"id":     "dimm" + strconv.Itoa(slot),
			"memdev": "mem" + strconv.Itoa(slot),
		},
	}
	qc.qmp <- &QmpSession{
		commands: commands,
		respond:  func(err error) { result <- err },
	}
}

func (qc *QemuContext) Save(ctx *hypervisor.VmContext, path string, result chan<- error) {
	commands := make([]*QmpCommand, 1)

	commands[0] = &QmpCommand{
		Execute: "migrate",
		Arguments: map[string]interface{}{
			"uri": fmt.Sprintf("exec:cat>%s", path),
		},
	}

	// TODO: use query-migrate to query until completed
	qc.qmp <- &QmpSession{
		commands: commands,
		respond:  func(err error) { result <- err },
	}
}

func (qc *QemuDriver) SupportLazyMode() bool {
	return false
}

func (qc *QemuContext) arguments(ctx *hypervisor.VmContext) []string {
	if ctx.Boot == nil {
		ctx.Boot = &hypervisor.BootConfig{
			CPU:    1,
			Memory: 128,
			Kernel: hypervisor.DefaultKernel,
			Initrd: hypervisor.DefaultInitrd,
		}
	}
	boot := ctx.Boot
	qc.cpus = boot.CPU

	var machineClass, memParams, cpuParams string
	if boot.HotAddCpuMem || boot.BootToBeTemplate || boot.BootFromTemplate {
		machineClass = "pc-i440fx-2.1"
		memParams = fmt.Sprintf("size=%d,slots=1,maxmem=%dM", boot.Memory, hypervisor.DefaultMaxMem) // TODO set maxmem to the total memory of the system
		cpuParams = fmt.Sprintf("cpus=%d,maxcpus=%d", boot.CPU, hypervisor.DefaultMaxCpus)           // TODO set it to the cpus of the system
	} else {
		machineClass = "pc-i440fx-2.0"
		memParams = strconv.Itoa(boot.Memory)
		cpuParams = strconv.Itoa(boot.CPU)
	}

	params := []string{
		"-machine", machineClass + ",accel=kvm,usb=off", "-global", "kvm-pit.lost_tick_policy=discard", "-cpu", "host"}
	if _, err := os.Stat("/dev/kvm"); os.IsNotExist(err) {
		glog.V(1).Info("kvm not exist change to no kvm mode")
		params = []string{"-machine", machineClass + ",usb=off", "-cpu", "core2duo"}
	}

	if boot.Bios != "" && boot.Cbfs != "" {
		params = append(params,
			"-drive", fmt.Sprintf("if=pflash,file=%s,readonly=on", boot.Bios),
			"-drive", fmt.Sprintf("if=pflash,file=%s,readonly=on", boot.Cbfs))
	} else if boot.Bios != "" {
		params = append(params,
			"-bios", boot.Bios,
			"-kernel", boot.Kernel, "-initrd", boot.Initrd, "-append", "console=ttyS0 panic=1 no_timer_check")
	} else if boot.Cbfs != "" {
		params = append(params,
			"-drive", fmt.Sprintf("if=pflash,file=%s,readonly=on", boot.Cbfs))
	} else {
		params = append(params,
			"-kernel", boot.Kernel, "-initrd", boot.Initrd, "-append", "console=ttyS0 panic=1 no_timer_check")
	}

	params = append(params,
		"-realtime", "mlock=off", "-no-user-config", "-nodefaults", "-no-hpet",
		"-rtc", "base=utc,driftfix=slew", "-no-reboot", "-display", "none", "-boot", "strict=on",
		"-m", memParams, "-smp", cpuParams)

	if boot.BootToBeTemplate || boot.BootFromTemplate {
		memObject := fmt.Sprintf("memory-backend-file,id=hyper-template-memory,size=%dM,mem-path=%s", boot.Memory, boot.MemoryPath)
		if boot.BootToBeTemplate {
			memObject = memObject + ",share=on"
		}
		nodeConfig := fmt.Sprintf("node,nodeid=0,cpus=0-%d,memdev=hyper-template-memory", hypervisor.DefaultMaxCpus-1)
		params = append(params, "-object", memObject, "-numa", nodeConfig)
		if boot.BootFromTemplate {
			params = append(params, "-incoming", fmt.Sprintf("exec:cat %s", boot.DevicesStatePath))
		}
	} else if boot.HotAddCpuMem {
		nodeConfig := fmt.Sprintf("node,nodeid=0,cpus=0-%d,mem=%d", hypervisor.DefaultMaxCpus-1, boot.Memory)
		params = append(params, "-numa", nodeConfig)
	}

	return append(params, "-qmp", fmt.Sprintf("unix:%s,server,nowait", qc.qmpSockName), "-serial", fmt.Sprintf("unix:%s,server,nowait", ctx.ConsoleSockName),
		"-device", "virtio-serial-pci,id=virtio-serial0,bus=pci.0,addr=0x2", "-device", "virtio-scsi-pci,id=scsi0,bus=pci.0,addr=0x3",
		"-chardev", fmt.Sprintf("socket,id=charch0,path=%s,server,nowait", ctx.HyperSockName),
		"-device", "virtserialport,bus=virtio-serial0.0,nr=1,chardev=charch0,id=channel0,name=sh.hyper.channel.0",
		"-chardev", fmt.Sprintf("socket,id=charch1,path=%s,server,nowait", ctx.TtySockName),
		"-device", "virtserialport,bus=virtio-serial0.0,nr=2,chardev=charch1,id=channel1,name=sh.hyper.channel.1",
		"-fsdev", fmt.Sprintf("local,id=virtio9p,path=%s,security_model=none", ctx.ShareDir),
		"-device", fmt.Sprintf("virtio-9p-pci,fsdev=virtio9p,mount_tag=%s", hypervisor.ShareDirTag),
	)
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"github.com/MakeNowJust/heredoc/v2"
	"os"

	"github.com/rsteube/carapace"
	"github.com/spf13/cobra"
	"github.com/zaquestion/lab/internal/action"
	lab "github.com/zaquestion/lab/internal/gitlab"
)

var mrApproveCmd = &cobra.Command{
	Use:     "approve [remote] <id>",
	Aliases: []string{},
	Short:   "Approve merge request",
	Example: heredoc.Doc(`
		lab mr approve origin
		lab mr approve upstream -F test_file
		lab mr approve upstream -m "A helpfull comment"
		lab mr approve upstream --with-comment
		lab mr approve upstream -m "A helpfull\nComment" --force-linebreak`),
	PersistentPreRun: labPersistentPreRun,
	Run: func(cmd *cobra.Command, args []string) {
		rn, id, err := parseArgsWithGitBranchMR(args)
		if err != nil {
			log.Fatal(err)
		}

		p, err := lab.FindProject(rn)
		if err != nil {
			log.Fatal(err)
		}

		comment, err := cmd.Flags().GetBool("with-comment")
		if err != nil {
			log.Fatal(err)
		}

		msgs, err := cmd.Flags().GetStringArray("message")
		if err != nil {
			log.Fatal(err)
		}

		filename, err := cmd.Flags().GetString("file")
		if err != nil {
			log.Fatal(err)
		}

		err = lab.MRApprove(p.ID, int(id))
		if err != nil {
			if err == lab.ErrStatusForbidden {
				log.Fatal(err)
			}
			if err == lab.ErrActionRepeated {
				fmt.Printf("Merge Request !%d already approved\n", id)
				os.Exit(1)
			}
		}

		if comment || len(msgs) > 0 || filename != "" {
			linebreak, err := cmd.Flags().GetBool("force-linebreak")
			if err != nil {
				log.Fatal(err)
			}

			createNote(rn, true, int(id), msgs, filename, linebreak, "")
		}

		fmt.Printf("Merge Request !%d approved\n", id)
	},
}

func init() {
	mrApproveCmd.Flags().Bool("with-comment", false, "Add a comment with the approval")
	mrApproveCmd.Flags().StringArrayP("message", "m", []string{}, "use the given <msg>; multiple -m are concatenated as separate paragraphs")
	mrApproveCmd.Flags().StringP("file", "F", "", "use the given file as the message")
	mrApproveCmd.Flags().Bool("force-linebreak", false, "append 2 spaces to the end of each line to force markdown linebreaks")
	mrCmd.AddCommand(mrApproveCmd)
	carapace.Gen(mrApproveCmd).PositionalCompletion(
		action.Remotes(),
		action.MergeRequests(mrList),
	)
}
<commit_msg>Moved file function to break before approval<commit_after>package cmd

import (
	"fmt"
	"github.com/MakeNowJust/heredoc/v2"
	"os"

	"github.com/rsteube/carapace"
	"github.com/spf13/cobra"
	"github.com/zaquestion/lab/internal/action"
	lab "github.com/zaquestion/lab/internal/gitlab"
)

var mrApproveCmd = &cobra.Command{
	Use:     "approve [remote] <id>",
	Aliases: []string{},
	Short:   "Approve merge request",
	Example: heredoc.Doc(`
		lab mr approve origin
		lab mr approve upstream -F test_file
		lab mr approve upstream -m "A helpfull comment"
		lab mr approve upstream --with-comment
		lab mr approve upstream -m "A helpfull\nComment" --force-linebreak`),
	PersistentPreRun: labPersistentPreRun,
	Run: func(cmd *cobra.Command, args []string) {
		rn, id, err := parseArgsWithGitBranchMR(args)
		if err != nil {
			log.Fatal(err)
		}

		p, err := lab.FindProject(rn)
		if err != nil {
			log.Fatal(err)
		}

		comment, err := cmd.Flags().GetBool("with-comment")
		if err != nil {
			log.Fatal(err)
		}

		msgs, err := cmd.Flags().GetStringArray("message")
		if err != nil {
			log.Fatal(err)
		}

		filename, err := cmd.Flags().GetString("file")
		if err != nil {
			log.Fatal(err)
		}

		if comment || len(msgs) > 0 || filename != "" {
			linebreak, err := cmd.Flags().GetBool("force-linebreak")
			if err != nil {
				log.Fatal(err)
			}

			createNote(rn, true, int(id), msgs, filename, linebreak, "")
		}

		err = lab.MRApprove(p.ID, int(id))
		if err != nil {
			if err == lab.ErrStatusForbidden {
				log.Fatal(err)
			}
			if err == lab.ErrActionRepeated {
				fmt.Printf("Merge Request !%d already approved\n", id)
				os.Exit(1)
			}
		}

		fmt.Printf("Merge Request !%d approved\n", id)
	},
}

func init() {
	mrApproveCmd.Flags().Bool("with-comment", false, "Add a comment with the approval")
	mrApproveCmd.Flags().StringArrayP("message", "m", []string{}, "use the given <msg>; multiple -m are concatenated as separate paragraphs")
	mrApproveCmd.Flags().StringP("file", "F", "", "use the given file as the message")
	mrApproveCmd.Flags().Bool("force-linebreak", false, "append 2 spaces to the end of each line to force markdown linebreaks")
	mrCmd.AddCommand(mrApproveCmd)
	carapace.Gen(mrApproveCmd).PositionalCompletion(
		action.Remotes(),
		action.MergeRequests(mrList),
	)
}
<|endoftext|>


<commit_before>//go:generate go-bindata template/

package main

import (
	"context"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strconv"
	"syscall"
	"time"

	"google.golang.org/grpc"

	"github.com/Sirupsen/logrus"
	"github.com/cad/ovpm"
	"github.com/cad/ovpm/api"
	"github.com/urfave/cli"
)

var action string
var db *ovpm.DB

func main() {
	app := cli.NewApp()
	app.Name = "ovpmd"
	app.Usage = "OpenVPN Manager Daemon"
	app.Version = ovpm.Version
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "verbose",
			Usage: "verbose output",
		},
		cli.StringFlag{
			Name:  "port",
			Usage: "port number for gRPC API daemon",
		},
		cli.StringFlag{
			Name:  "web-port",
			Usage: "port number for the REST API daemon",
		},
	}
	app.Before = func(c *cli.Context) error {
		logrus.SetLevel(logrus.InfoLevel)
		if c.GlobalBool("verbose") {
			logrus.SetLevel(logrus.DebugLevel)
		}
		db = ovpm.CreateDB("sqlite3", "")
		return nil
	}
	app.After = func(c *cli.Context) error {
		db.Cease()
		return nil
	}
	app.Action = func(c *cli.Context) error {
		port := c.String("port")
		if port == "" {
			port = "9090"
		}

		webPort := c.String("web-port")
		if webPort == "" {
			webPort = "8080"
		}

		s := newServer(port, webPort)
		s.start()
		s.waitForInterrupt()
		s.stop()
		return nil
	}
	app.Run(os.Args)
}

type server struct {
	grpcPort   string
	lis        net.Listener
	grpcServer *grpc.Server
	restServer http.Handler
	restCancel context.CancelFunc
	restPort   string
	signal     chan os.Signal
	done       chan bool
}

func newServer(port, webPort string) *server {
	sigs := make(chan os.Signal, 1)
	done := make(chan bool, 1)

	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

	go func() {
		sig := <-sigs
		fmt.Println()
		fmt.Println(sig)
		done <- true
	}()
	if !ovpm.Testing {
		// NOTE(cad): gRPC endpoint listens on localhost. This is important
		// because we don't authanticate requests coming from localhost.
		// So gRPC endpoint should never listen on something else then
		// localhost.
		lis, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%s", port))
		if err != nil {
			logrus.Fatalf("could not listen to port %s: %v", port, err)
		}

		rpcServer := api.NewRPCServer()
		restServer, restCancel, err := api.NewRESTServer(port)
		if err != nil {
			logrus.Fatalf("could not get new rest server :%v", err)
		}

		return &server{
			lis:        lis,
			grpcServer: rpcServer,
			restServer: restServer,
			restCancel: context.CancelFunc(restCancel),
			restPort:   webPort,
			signal:     sigs,
			done:       done,
			grpcPort:   port,
		}
	}
	return &server{}

}

func (s *server) start() {
	logrus.Infof("OVPM is running gRPC:%s, REST:%s ...", s.grpcPort, s.restPort)
	go s.grpcServer.Serve(s.lis)
	go http.ListenAndServe(":"+s.restPort, s.restServer)
	ovpm.StartVPNProc()
}

func (s *server) stop() {
	logrus.Info("OVPM is shutting down ...")
	s.grpcServer.Stop()
	s.restCancel()
	ovpm.StopVPNProc()

}

func (s *server) waitForInterrupt() {
	<-s.done
	go timeout(8 * time.Second)
}

func timeout(interval time.Duration) {
	time.Sleep(interval)
	log.Println("Timeout! Killing the main thread...")
	os.Exit(-1)
}

func stringInSlice(a string, list []string) bool {
	for _, b := range list {
		if b == a {
			return true
		}
	}
	return false
}

func increasePort(p string) string {
	i, err := strconv.Atoi(p)
	if err != nil {
		logrus.Panicf(fmt.Sprintf("can't convert %s to int: %v", p, err))

	}
	i++
	return fmt.Sprintf("%d", i)
}
<commit_msg>style(webui): add version to ovpmd start prompt<commit_after>//go:generate go-bindata template/

package main

import (
	"context"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strconv"
	"syscall"
	"time"

	"google.golang.org/grpc"

	"github.com/Sirupsen/logrus"
	"github.com/cad/ovpm"
	"github.com/cad/ovpm/api"
	"github.com/urfave/cli"
)

var action string
var db *ovpm.DB

func main() {
	app := cli.NewApp()
	app.Name = "ovpmd"
	app.Usage = "OpenVPN Manager Daemon"
	app.Version = ovpm.Version
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "verbose",
			Usage: "verbose output",
		},
		cli.StringFlag{
			Name:  "port",
			Usage: "port number for gRPC API daemon",
		},
		cli.StringFlag{
			Name:  "web-port",
			Usage: "port number for the REST API daemon",
		},
	}
	app.Before = func(c *cli.Context) error {
		logrus.SetLevel(logrus.InfoLevel)
		if c.GlobalBool("verbose") {
			logrus.SetLevel(logrus.DebugLevel)
		}
		db = ovpm.CreateDB("sqlite3", "")
		return nil
	}
	app.After = func(c *cli.Context) error {
		db.Cease()
		return nil
	}
	app.Action = func(c *cli.Context) error {
		port := c.String("port")
		if port == "" {
			port = "9090"
		}

		webPort := c.String("web-port")
		if webPort == "" {
			webPort = "8080"
		}

		s := newServer(port, webPort)
		s.start()
		s.waitForInterrupt()
		s.stop()
		return nil
	}
	app.Run(os.Args)
}

type server struct {
	grpcPort   string
	lis        net.Listener
	grpcServer *grpc.Server
	restServer http.Handler
	restCancel context.CancelFunc
	restPort   string
	signal     chan os.Signal
	done       chan bool
}

func newServer(port, webPort string) *server {
	sigs := make(chan os.Signal, 1)
	done := make(chan bool, 1)

	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

	go func() {
		sig := <-sigs
		fmt.Println()
		fmt.Println(sig)
		done <- true
	}()
	if !ovpm.Testing {
		// NOTE(cad): gRPC endpoint listens on localhost. This is important
		// because we don't authanticate requests coming from localhost.
		// So gRPC endpoint should never listen on something else then
		// localhost.
		lis, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%s", port))
		if err != nil {
			logrus.Fatalf("could not listen to port %s: %v", port, err)
		}

		rpcServer := api.NewRPCServer()
		restServer, restCancel, err := api.NewRESTServer(port)
		if err != nil {
			logrus.Fatalf("could not get new rest server :%v", err)
		}

		return &server{
			lis:        lis,
			grpcServer: rpcServer,
			restServer: restServer,
			restCancel: context.CancelFunc(restCancel),
			restPort:   webPort,
			signal:     sigs,
			done:       done,
			grpcPort:   port,
		}
	}
	return &server{}

}

func (s *server) start() {
	logrus.Infof("OVPM %s is running gRPC:%s, REST:%s ...", ovpm.Version, s.grpcPort, s.restPort)
	go s.grpcServer.Serve(s.lis)
	go http.ListenAndServe(":"+s.restPort, s.restServer)
	ovpm.StartVPNProc()
}

func (s *server) stop() {
	logrus.Info("OVPM is shutting down ...")
	s.grpcServer.Stop()
	s.restCancel()
	ovpm.StopVPNProc()

}

func (s *server) waitForInterrupt() {
	<-s.done
	go timeout(8 * time.Second)
}

func timeout(interval time.Duration) {
	time.Sleep(interval)
	log.Println("Timeout! Killing the main thread...")
	os.Exit(-1)
}

func stringInSlice(a string, list []string) bool {
	for _, b := range list {
		if b == a {
			return true
		}
	}
	return false
}

func increasePort(p string) string {
	i, err := strconv.Atoi(p)
	if err != nil {
		logrus.Panicf(fmt.Sprintf("can't convert %s to int: %v", p, err))

	}
	i++
	return fmt.Sprintf("%d", i)
}
<|endoftext|>


<commit_before>// Copyright (c) 2016, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/mvdan/sh"
)

var (
	write  = flag.Bool("w", false, "write result to file instead of stdout")
	list   = flag.Bool("l", false, "list files whose formatting differs from shfmt's")
	indent = flag.Int("i", 0, "indent: 0 for tabs (default), >0 for number of spaces")
)

var config sh.PrintConfig

func main() {
	flag.Parse()
	config.Spaces = *indent
	if flag.NArg() == 0 {
		if err := formatStdin(); err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		return
	}
	anyErr := false
	onError := func(err error) {
		anyErr = true
		fmt.Fprintln(os.Stderr, err)
	}
	for _, path := range flag.Args() {
		if err := walk(path, onError); err != nil {
			onError(err)
		}
	}
	if anyErr {
		os.Exit(1)
	}
}

func formatStdin() error {
	if *write || *list {
		return fmt.Errorf("-w and -l can only be used on files")
	}
	prog, err := sh.Parse(os.Stdin, "", sh.ParseComments)
	if err != nil {
		return err
	}
	return config.Fprint(os.Stdout, prog)
}

var (
	hidden    = regexp.MustCompile(`^\.[^/.]`)
	shellFile = regexp.MustCompile(`^.*\.(sh|bash)$`)
	shebang   = regexp.MustCompile(`^#!/(usr/)?bin/(env *)?(sh|bash)`)
)

func walk(path string, onError func(error)) error {
	info, err := os.Stat(path)
	if err != nil {
		return err
	}
	if !info.IsDir() {
		return formatPath(path, 0, true)
	}
	return filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
		if hidden.MatchString(path) {
			return filepath.SkipDir
		}
		if info.IsDir() {
			return nil
		}
		if err := formatPath(path, info.Size(), false); err != nil {
			onError(err)
		}
		return nil
	})
}

func empty(f *os.File) error {
	if err := f.Truncate(0); err != nil {
		return err
	}
	_, err := f.Seek(0, 0)
	return err
}

func validShebang(bs []byte) bool {
	return shebang.Match(bs[:32])
}

func formatPath(path string, size int64, always bool) error {
	shellExt := always || shellFile.MatchString(path)
	if !shellExt && strings.Contains(path, ".") {
		// has an unwanted extension
		return nil
	}
	if !shellExt && size < 8 {
		// cannot possibly hold valid shebang
		return nil
	}
	mode := os.O_RDONLY
	if *write {
		mode = os.O_RDWR
	}
	f, err := os.OpenFile(path, mode, 0)
	if err != nil {
		return err
	}
	defer f.Close()
	src, err := ioutil.ReadAll(f)
	if err != nil {
		return err
	}
	if !shellExt && !validShebang(src) {
		return nil
	}
	prog, err := sh.Parse(src, path, sh.ParseComments)
	if err != nil {
		return err
	}
	var buf bytes.Buffer
	if err := config.Fprint(&buf, prog); err != nil {
		return err
	}
	res := buf.Bytes()
	if !bytes.Equal(src, res) {
		if *list {
			fmt.Println(path)
		}
		if *write {
			if err := empty(f); err != nil {
				return err
			}
			if _, err := f.Write(res); err != nil {
				return err
			}
		}
	}
	if !*list && !*write {
		if _, err := os.Stdout.Write(res); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>shfmt: reuse allocated buffer between runs<commit_after>// Copyright (c) 2016, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/mvdan/sh"
)

var (
	write  = flag.Bool("w", false, "write result to file instead of stdout")
	list   = flag.Bool("l", false, "list files whose formatting differs from shfmt's")
	indent = flag.Int("i", 0, "indent: 0 for tabs (default), >0 for number of spaces")
)

var (
	config sh.PrintConfig
	buf    bytes.Buffer
)

func main() {
	flag.Parse()
	config.Spaces = *indent
	if flag.NArg() == 0 {
		if err := formatStdin(); err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		return
	}
	anyErr := false
	onError := func(err error) {
		anyErr = true
		fmt.Fprintln(os.Stderr, err)
	}
	for _, path := range flag.Args() {
		if err := walk(path, onError); err != nil {
			onError(err)
		}
	}
	if anyErr {
		os.Exit(1)
	}
}

func formatStdin() error {
	if *write || *list {
		return fmt.Errorf("-w and -l can only be used on files")
	}
	prog, err := sh.Parse(os.Stdin, "", sh.ParseComments)
	if err != nil {
		return err
	}
	return config.Fprint(os.Stdout, prog)
}

var (
	hidden    = regexp.MustCompile(`^\.[^/.]`)
	shellFile = regexp.MustCompile(`^.*\.(sh|bash)$`)
	shebang   = regexp.MustCompile(`^#!/(usr/)?bin/(env *)?(sh|bash)`)
)

func walk(path string, onError func(error)) error {
	info, err := os.Stat(path)
	if err != nil {
		return err
	}
	if !info.IsDir() {
		return formatPath(path, 0, true)
	}
	return filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
		if hidden.MatchString(path) {
			return filepath.SkipDir
		}
		if info.IsDir() {
			return nil
		}
		if err := formatPath(path, info.Size(), false); err != nil {
			onError(err)
		}
		return nil
	})
}

func empty(f *os.File) error {
	if err := f.Truncate(0); err != nil {
		return err
	}
	_, err := f.Seek(0, 0)
	return err
}

func validShebang(bs []byte) bool {
	return shebang.Match(bs[:32])
}

func formatPath(path string, size int64, always bool) error {
	shellExt := always || shellFile.MatchString(path)
	if !shellExt && strings.Contains(path, ".") {
		// has an unwanted extension
		return nil
	}
	if !shellExt && size < 8 {
		// cannot possibly hold valid shebang
		return nil
	}
	mode := os.O_RDONLY
	if *write {
		mode = os.O_RDWR
	}
	f, err := os.OpenFile(path, mode, 0)
	if err != nil {
		return err
	}
	defer f.Close()
	src, err := ioutil.ReadAll(f)
	if err != nil {
		return err
	}
	if !shellExt && !validShebang(src) {
		return nil
	}
	prog, err := sh.Parse(src, path, sh.ParseComments)
	if err != nil {
		return err
	}
	buf.Reset()
	if err := config.Fprint(&buf, prog); err != nil {
		return err
	}
	res := buf.Bytes()
	if !bytes.Equal(src, res) {
		if *list {
			fmt.Println(path)
		}
		if *write {
			if err := empty(f); err != nil {
				return err
			}
			if _, err := f.Write(res); err != nil {
				return err
			}
		}
	}
	if !*list && !*write {
		if _, err := os.Stdout.Write(res); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/timeredbull/tsuru/cmd"
	"os"
)

const version = "1.0"

func buildManager(name string) *cmd.Manager {
	m := cmd.BuildBaseManager(name, version)
	m.Register(&AppRun{})
	m.Register(&AppCreate{})
	m.Register(&AppRemove{})
	m.Register(&AppList{})
	m.Register(&AppLog{})
	m.Register(&AppGrant{})
	m.Register(&AppRevoke{})
	m.Register(&AppRestart{})
	m.Register(&EnvGet{})
	m.Register(&EnvSet{})
	m.Register(&EnvUnset{})
	m.Register(&KeyAdd{})
	m.Register(&KeyRemove{})
	m.Register(&ServiceList{})
	m.Register(&ServiceAdd{})
	m.Register(&ServiceRemove{})
	m.Register(&ServiceBind{})
	m.Register(&ServiceUnbind{})
	m.Register(&ServiceDoc{})
	m.Register(&ServiceInfo{})
	m.Register(&ServiceInstanceStatus{})
	return m
}

func main() {
	name := cmd.ExtractProgramName(os.Args[0])
	manager := buildManager(name)
	args := os.Args[1:]
	manager.Run(args)
}
<commit_msg>cmd/tsuru: fix version<commit_after>package main

import (
	"github.com/timeredbull/tsuru/cmd"
	"os"
)

const version = "0.1"

func buildManager(name string) *cmd.Manager {
	m := cmd.BuildBaseManager(name, version)
	m.Register(&AppRun{})
	m.Register(&AppCreate{})
	m.Register(&AppRemove{})
	m.Register(&AppList{})
	m.Register(&AppLog{})
	m.Register(&AppGrant{})
	m.Register(&AppRevoke{})
	m.Register(&AppRestart{})
	m.Register(&EnvGet{})
	m.Register(&EnvSet{})
	m.Register(&EnvUnset{})
	m.Register(&KeyAdd{})
	m.Register(&KeyRemove{})
	m.Register(&ServiceList{})
	m.Register(&ServiceAdd{})
	m.Register(&ServiceRemove{})
	m.Register(&ServiceBind{})
	m.Register(&ServiceUnbind{})
	m.Register(&ServiceDoc{})
	m.Register(&ServiceInfo{})
	m.Register(&ServiceInstanceStatus{})
	return m
}

func main() {
	name := cmd.ExtractProgramName(os.Args[0])
	manager := buildManager(name)
	args := os.Args[1:]
	manager.Run(args)
}
<|endoftext|>


<commit_before>package analysis

import (
	"fmt"
	"reflect"
	"unicode"
)

// Validate reports an error if any of the analyzers are misconfigured.
// Checks include:
// that the name is a valid identifier;
// that analyzer names are unique;
// that the Requires graph is acylic;
// that analyzer fact types are unique;
// that each fact type is a pointer.
func Validate(analyzers []*Analyzer) error {
	names := make(map[string]bool)

	// Map each fact type to its sole generating analyzer.
	factTypes := make(map[reflect.Type]*Analyzer)

	// Traverse the Requires graph, depth first.
	color := make(map[*Analyzer]uint8) // 0=white 1=grey 2=black
	var visit func(a *Analyzer) error
	visit = func(a *Analyzer) error {
		if a == nil {
			return fmt.Errorf("nil *Analyzer")
		}
		if color[a] == 0 { // white
			color[a] = 1 // grey

			// names
			if !validIdent(a.Name) {
				return fmt.Errorf("invalid analyzer name %q", a)
			}
			if names[a.Name] {
				return fmt.Errorf("duplicate analyzer name %q", a)
			}
			names[a.Name] = true

			if a.Doc == "" {
				return fmt.Errorf("analyzer %q is undocumented", a)
			}

			// fact types
			for _, f := range a.FactTypes {
				if f == nil {
					return fmt.Errorf("analyzer %s has nil FactType", a)
				}
				t := reflect.TypeOf(f)
				if prev := factTypes[t]; prev != nil {
					return fmt.Errorf("fact type %s registered by two analyzers: %v, %v",
						t, a, prev)
				}
				if t.Kind() != reflect.Ptr {
					return fmt.Errorf("%s: fact type %s is not a pointer", a, t)
				}
				factTypes[t] = a
			}

			// recursion
			for i, req := range a.Requires {
				if err := visit(req); err != nil {
					return fmt.Errorf("%s.Requires[%d]: %v", a.Name, i, err)
				}
			}
			color[a] = 2 // black
		}

		return nil
	}
	for _, a := range analyzers {
		if err := visit(a); err != nil {
			return err
		}
	}

	return nil
}

func validIdent(name string) bool {
	for i, r := range name {
		if !(r == '_' || unicode.IsLetter(r) || i > 0 && unicode.IsDigit(r)) {
			return false
		}
	}
	return name != ""
}
<commit_msg>go/analysis: validate: report duplicates among analyzers (roots)<commit_after>package analysis

import (
	"fmt"
	"reflect"
	"unicode"
)

// Validate reports an error if any of the analyzers are misconfigured.
// Checks include:
// that the name is a valid identifier;
// that analyzer names are unique;
// that the Requires graph is acylic;
// that analyzer fact types are unique;
// that each fact type is a pointer.
func Validate(analyzers []*Analyzer) error {
	names := make(map[string]bool)

	// Map each fact type to its sole generating analyzer.
	factTypes := make(map[reflect.Type]*Analyzer)

	// Traverse the Requires graph, depth first.
	const (
		white = iota
		grey
		black
		finished
	)
	color := make(map[*Analyzer]uint8)
	var visit func(a *Analyzer) error
	visit = func(a *Analyzer) error {
		if a == nil {
			return fmt.Errorf("nil *Analyzer")
		}
		if color[a] == white {
			color[a] = grey

			// names
			if !validIdent(a.Name) {
				return fmt.Errorf("invalid analyzer name %q", a)
			}
			if names[a.Name] {
				return fmt.Errorf("duplicate analyzer name %q", a)
			}
			names[a.Name] = true

			if a.Doc == "" {
				return fmt.Errorf("analyzer %q is undocumented", a)
			}

			// fact types
			for _, f := range a.FactTypes {
				if f == nil {
					return fmt.Errorf("analyzer %s has nil FactType", a)
				}
				t := reflect.TypeOf(f)
				if prev := factTypes[t]; prev != nil {
					return fmt.Errorf("fact type %s registered by two analyzers: %v, %v",
						t, a, prev)
				}
				if t.Kind() != reflect.Ptr {
					return fmt.Errorf("%s: fact type %s is not a pointer", a, t)
				}
				factTypes[t] = a
			}

			// recursion
			for i, req := range a.Requires {
				if err := visit(req); err != nil {
					return fmt.Errorf("%s.Requires[%d]: %v", a.Name, i, err)
				}
			}
			color[a] = black
		}

		return nil
	}
	for _, a := range analyzers {
		if err := visit(a); err != nil {
			return err
		}
	}

	// Reject duplicates among analyzers.
	// Precondition:  color[a] == black.
	// Postcondition: color[a] == finished.
	for _, a := range analyzers {
		if color[a] == finished {
			return fmt.Errorf("duplicate analyzer: %s", a.Name)
		}
		color[a] = finished
	}

	return nil
}

func validIdent(name string) bool {
	for i, r := range name {
		if !(r == '_' || unicode.IsLetter(r) || i > 0 && unicode.IsDigit(r)) {
			return false
		}
	}
	return name != ""
}
<|endoftext|>


<commit_before>/*
   Copyright 2016 GitHub Inc.
	 See https://github.com/github/gh-ost/blob/master/LICENSE
*/

package base

import (
	"testing"
	"time"

	"github.com/outbrain/golib/log"
	test "github.com/outbrain/golib/tests"
)

func init() {
	log.SetLevel(log.ERROR)
}

func TestGetTableNames(t *testing.T) {
	context = newMigrationContext()
	{
		context.OriginalTableName = "some_table"
		test.S(t).ExpectEquals(context.GetOldTableName(), "_some_table_del")
		test.S(t).ExpectEquals(context.GetGhostTableName(), "_some_table_gho")
		test.S(t).ExpectEquals(context.GetChangelogTableName(), "_some_table_ghc")
	}
	{
		context.OriginalTableName = "a123456789012345678901234567890123456789012345678901234567890"
		test.S(t).ExpectEquals(context.GetOldTableName(), "_a1234567890123456789012345678901234567890123456789012345678_del")
		test.S(t).ExpectEquals(context.GetGhostTableName(), "_a1234567890123456789012345678901234567890123456789012345678_gho")
		test.S(t).ExpectEquals(context.GetChangelogTableName(), "_a1234567890123456789012345678901234567890123456789012345678_ghc")
	}
	{
		context.OriginalTableName = "a123456789012345678901234567890123456789012345678901234567890123"
		oldTableName := context.GetOldTableName()
		test.S(t).ExpectEquals(oldTableName, "_a1234567890123456789012345678901234567890123456789012345678_del")
	}
	{
		context.OriginalTableName = "a123456789012345678901234567890123456789012345678901234567890123"
		context.TimestampOldTable = true
		longForm := "Jan 2, 2006 at 3:04pm (MST)"
		context.StartTime, _ = time.Parse(longForm, "Feb 3, 2013 at 7:54pm (PST)")
		oldTableName := context.GetOldTableName()
		test.S(t).ExpectEquals(oldTableName, "_a1234567890123456789012345678901234567890123_20130203195400_del")
	}
	{
		context.OriginalTableName = "foo_bar_baz"
		context.ForceTmpTableName = "tmp"
		context.TimestampOldTable = false
		test.S(t).ExpectEquals(context.GetOldTableName(), "_tmp_del")
		test.S(t).ExpectEquals(context.GetGhostTableName(), "_tmp_gho")
		test.S(t).ExpectEquals(context.GetChangelogTableName(), "_tmp_ghc")
	}
}
<commit_msg>Dont share the same context in the table name tests<commit_after>/*
   Copyright 2016 GitHub Inc.
	 See https://github.com/github/gh-ost/blob/master/LICENSE
*/

package base

import (
	"testing"
	"time"

	"github.com/outbrain/golib/log"
	test "github.com/outbrain/golib/tests"
)

func init() {
	log.SetLevel(log.ERROR)
}

func TestGetTableNames(t *testing.T) {
	{
		context = newMigrationContext()
		context.OriginalTableName = "some_table"
		test.S(t).ExpectEquals(context.GetOldTableName(), "_some_table_del")
		test.S(t).ExpectEquals(context.GetGhostTableName(), "_some_table_gho")
		test.S(t).ExpectEquals(context.GetChangelogTableName(), "_some_table_ghc")
	}
	{
		context = newMigrationContext()
		context.OriginalTableName = "a123456789012345678901234567890123456789012345678901234567890"
		test.S(t).ExpectEquals(context.GetOldTableName(), "_a1234567890123456789012345678901234567890123456789012345678_del")
		test.S(t).ExpectEquals(context.GetGhostTableName(), "_a1234567890123456789012345678901234567890123456789012345678_gho")
		test.S(t).ExpectEquals(context.GetChangelogTableName(), "_a1234567890123456789012345678901234567890123456789012345678_ghc")
	}
	{
		context = newMigrationContext()
		context.OriginalTableName = "a123456789012345678901234567890123456789012345678901234567890123"
		oldTableName := context.GetOldTableName()
		test.S(t).ExpectEquals(oldTableName, "_a1234567890123456789012345678901234567890123456789012345678_del")
	}
	{
		context = newMigrationContext()
		context.OriginalTableName = "a123456789012345678901234567890123456789012345678901234567890123"
		context.TimestampOldTable = true
		longForm := "Jan 2, 2006 at 3:04pm (MST)"
		context.StartTime, _ = time.Parse(longForm, "Feb 3, 2013 at 7:54pm (PST)")
		oldTableName := context.GetOldTableName()
		test.S(t).ExpectEquals(oldTableName, "_a1234567890123456789012345678901234567890123_20130203195400_del")
	}
	{
		context = newMigrationContext()
		context.OriginalTableName = "foo_bar_baz"
		context.ForceTmpTableName = "tmp"
		test.S(t).ExpectEquals(context.GetOldTableName(), "_tmp_del")
		test.S(t).ExpectEquals(context.GetGhostTableName(), "_tmp_gho")
		test.S(t).ExpectEquals(context.GetChangelogTableName(), "_tmp_ghc")
	}
}
<|endoftext|>


<commit_before>// Copyright 2021 Google LLC
//
// 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 eventlog provides an interface to the Windows Event Log.
package eventlog

import (
	"errors"
	"fmt"
	"syscall"
	"time"
	"unsafe"

	"golang.org/x/sys/windows"
	"github.com/google/winops/winlog/wevtapi"
)

// Handle maps a handle to an event log resource (EVT_HANDLE). Close() must be called to release the handle.
//
// Note that the order in which handles are closed may matter. Parent handles should not be closed until all
// uses of the handles (queries, etc) are complete.
//
// Ref: https://docs.microsoft.com/en-us/windows/win32/api/winevt/nf-winevt-evtclose
type Handle struct {
	handle windows.Handle
}

// Close releases a Handle.
func (h *Handle) Close() {
	if h != nil {
		wevtapi.EvtClose(h.handle)
	}
}

// An Event is a Handle to an event.
type Event Handle

// Close releases an Event.
func (h *Event) Close() {
	if h != nil {
		wevtapi.EvtClose(h.handle)
	}
}

// A RenderContext is a Handle which tracks a Context as returned by EvtCreateRenderContext.
type RenderContext Handle

// Close releases a RenderContext.
func (h *RenderContext) Close() {
	if h != nil {
		wevtapi.EvtClose(h.handle)
	}
}

// A ResultSet is a Handle returned by a Query or Subscription
type ResultSet Handle

// Close releases a ResultSet.
func (h *ResultSet) Close() {
	if h != nil {
		wevtapi.EvtClose(h.handle)
	}
}

// A Session is a Handle returned by OpenSession
type Session Handle

// Close releases a Session.
func (h *Session) Close() {
	if h != nil {
		wevtapi.EvtClose(h.handle)
	}
}

// EvtRenderContextFlags specify which types of values to render from a given event.
//
// Ref: https://docs.microsoft.com/en-us/windows/win32/api/winevt/ne-winevt-evt_render_context_flags
type EvtRenderContextFlags uint32

const (
	// EvtRenderContextValues renders specific properties from the event.
	EvtRenderContextValues EvtRenderContextFlags = iota
	// EvtRenderContextSystem renders the system properties under the System element.
	EvtRenderContextSystem
	// EvtRenderContextUser renders all user-defined properties under the UserData or EventData element.
	EvtRenderContextUser
)

// CreateRenderContext creates a context that specifies the information in the event that you want to render.
//
// The RenderContext is used to obtain only a subset of event data when querying events.
// Without a RenderContext, the entirety of the log data will be returned.
//
// Passing one of EvtRenderContextSystem or EvtRenderContextUser (with valuePaths nil)
// will render all properties under the corresponding element (System or User). Passing
// EvtRenderContextValues along with a list of valuePaths allows the caller to obtain individual
// event elements. valuePaths must be well formed XPath expressions. See the documentation
// for EvtCreateRenderContext and EVT_RENDER_CONTEXT_FLAGS for more detail.
//
// Example, rendering all System values:
//		eventlog.CreateRenderContext(eventlog.EvtRenderContextSystem, nil)
//
// Example, rendering specific values:
//		eventlog.CreateRenderContext(eventlog.EvtRenderContextValues, &[]string{
//				"Event/System/TimeCreated/@SystemTime", "Event/System/Provider/@Name"})
//
// Ref: https://docs.microsoft.com/en-us/windows/win32/api/winevt/nf-winevt-evtcreaterendercontext
func CreateRenderContext(flags EvtRenderContextFlags, valuePaths *[]string) (RenderContext, error) {
	rc := RenderContext{}

	pathsPtr := uintptr(0)
	p := []*uint16{}
	if valuePaths != nil {
		for _, v := range *valuePaths {
			ptr, err := syscall.UTF16PtrFromString(v)
			if err != nil {
				return rc, fmt.Errorf("syscall.UTF16PtrFromString(%s): %w", v, err)
			}
			p = append(p, ptr)
		}
		pathsPtr = uintptr(unsafe.Pointer(&p[0]))
	}

	var err error
	rc.handle, err = wevtapi.EvtCreateRenderContext(uint32(len(p)), uintptr(pathsPtr), uint32(flags))
	return rc, err
}

// An EventSet holds one or more event handles.
//
// Close() must be called to release the event handles when finished.
type EventSet struct {
	Events []Event
	Count  uint32
}

// Close releases all events in the EventSet.
func (e *EventSet) Close() {
	for _, evt := range e.Events {
		evt.Close()
	}
}

// Next gets the next event(s) returned by a query or subscription.
//
// Ref: https://docs.microsoft.com/en-us/windows/win32/api/winevt/nf-winevt-evtnext
func Next(handle ResultSet, count uint32, timeout *time.Duration) (EventSet, error) {
	es := EventSet{}

	defaultTimeout := 2000 * time.Millisecond
	if timeout == nil {
		timeout = &defaultTimeout
	}

	// Get handles to events from the result set.
	evts := make([]windows.Handle, count)
	err := wevtapi.EvtNext(
		handle.handle,                  // Handle to query or subscription result set.
		count,                          // The number of events to attempt to retrieve.
		&evts[0],                       // Pointer to the array of event handles.
		uint32(timeout.Milliseconds()), // Timeout in milliseconds to wait.
		0,                              // Reserved. Must be zero.
		&es.Count)                      // The number of handles in the array that are set by the API.
	if err == windows.ERROR_NO_MORE_ITEMS {
		return es, err
	} else if err != nil {
		return es, fmt.Errorf("wevtapi.EvtNext: %w", err)
	}

	for i := 0; i < int(es.Count); i++ {
		es.Events = append(es.Events, Event{handle: evts[i]})
	}

	return es, nil
}

// Query runs a query to retrieve events from a channel or log file that match the specified query criteria.
//
// Session is only required for remote connections; leave as nil for the local log. Flags can be any of
// wevtapi.EVT_QUERY_FLAGS.
//
// The session handle must remain open until all subsequent processing on the query results have completed. Call
// Close() once complete.
//
// Example:
// 	 conn, err := eventlog.Query(nil, "Windows Powershell", "*", wevtapi.EvtQueryReverseDirection)
// 	 if err != nil {
//     return err
//	 }
//	 defer conn.Close()
//
// Ref: https://docs.microsoft.com/en-us/windows/win32/api/winevt/nf-winevt-evtquery
func Query(session *Session, path string, query string, flags uint32) (ResultSet, error) {
	var rs ResultSet
	var err error

	var s windows.Handle
	if session != nil {
		s = session.handle
	}
	rs.handle, err = wevtapi.EvtQuery(s, windows.StringToUTF16Ptr(path), windows.StringToUTF16Ptr(query), flags)
	if err != nil {
		return rs, fmt.Errorf("EvtQuery: %w", err)
	}
	if rs.handle == windows.InvalidHandle {
		return rs, errors.New("invalid query")
	}
	return rs, nil
}

// EvtVariantData models the union inside of the EVT_VARIANT structure.
//
// Ref: https://docs.microsoft.com/en-us/windows/win32/api/winevt/ns-winevt-evt_variant
type EvtVariantData struct {
	BooleanVal    bool
	SByteVal      int8
	Int16Val      int16
	Int32Val      int32
	Int64Val      int64
	ByteVal       uint8
	UInt16Val     uint16
	UInt32Val     uint32
	UInt64Val     uint64
	SingleVal     float32
	DoubleVal     float64
	FileTimeVal   windows.Filetime
	SysTimeVal    windows.Systemtime
	GuidVal       windows.GUID
	StringVal     string
	AnsiStringVal string
	BinaryVal     byte
	SidVal        windows.SID
	SizeTVal      uint32
	BooleanArr    *[]bool
	SByteArr      *[]int8
	Int16Arr      *[]int16
	Int32Arr      *[]int32
	Int64Arr      *[]int64
	ByteArr       *[]uint16
	UInt16Arr     *[]uint16
	UInt32Arr     *[]uint32
	UInt64Arr     *[]uint64
	SingleArr     *[]float32
	DoubleArr     *[]float64
	FileTimeArr   *[]windows.Filetime
	SysTimeArr    *[]windows.Systemtime
	GuidArr       *[]windows.GUID
	StringArr     *[]string
	AnsiStringArr *[]string
	SidArr        *[]windows.SID
	SizeTArr      *[]uint32
	EvtHandleVal  windows.Handle
	XmlVal        string
	XmlValArr     *[]string
}

// EvtVariantType(EVT_VARIANT_TYPE) defines the possible data types of a EVT_VARIANT data item.
//
// Ref: https://docs.microsoft.com/en-us/windows/win32/api/winevt/ne-winevt-evt_variant_type
type EvtVariantType uint32

const (
	EvtVarTypeNull EvtVariantType = iota
	EvtVarTypeString
	EvtVarTypeAnsiString
	EvtVarTypeSByte
	EvtVarTypeByte
	EvtVarTypeInt16
	EvtVarTypeUInt16
	EvtVarTypeInt32
	EvtVarTypeUInt32
	EvtVarTypeInt64
	EvtVarTypeUInt64
	EvtVarTypeSingle
	EvtVarTypeDouble
	EvtVarTypeBoolean
	EvtVarTypeBinary
	EvtVarTypeGuid
	EvtVarTypeSizeT
	EvtVarTypeFileTime
	EvtVarTypeSysTime
	EvtVarTypeSid
	EvtVarTypeHexInt32
	EvtVarTypeHexInt64
	EvtVarTypeEvtHandle
	EvtVarTypeEvtXml
)

// EvtVariant (EVT_VARIANT) contains event data or property values.
//
// Ref: https://docs.microsoft.com/en-us/windows/win32/api/winevt/ns-winevt-evt_variant
type EvtVariant struct {
	Count uint32
	Type  EvtVariantType
	Data  EvtVariantData
}
<commit_msg>Add Render<commit_after>// Copyright 2021 Google LLC
//
// 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 eventlog provides an interface to the Windows Event Log.
package eventlog

import (
	"errors"
	"fmt"
	"syscall"
	"time"
	"unsafe"

	"golang.org/x/sys/windows"
	"github.com/google/winops/winlog/wevtapi"
)

// Handle maps a handle to an event log resource (EVT_HANDLE). Close() must be called to release the handle.
//
// Note that the order in which handles are closed may matter. Parent handles should not be closed until all
// uses of the handles (queries, etc) are complete.
//
// Ref: https://docs.microsoft.com/en-us/windows/win32/api/winevt/nf-winevt-evtclose
type Handle struct {
	handle windows.Handle
}

// Close releases a Handle.
func (h *Handle) Close() {
	if h != nil {
		wevtapi.EvtClose(h.handle)
	}
}

// An Event is a Handle to an event.
type Event Handle

// Close releases an Event.
func (h *Event) Close() {
	if h != nil {
		wevtapi.EvtClose(h.handle)
	}
}

// A RenderContext is a Handle which tracks a Context as returned by EvtCreateRenderContext.
type RenderContext Handle

// Close releases a RenderContext.
func (h *RenderContext) Close() {
	if h != nil {
		wevtapi.EvtClose(h.handle)
	}
}

// A ResultSet is a Handle returned by a Query or Subscription
type ResultSet Handle

// Close releases a ResultSet.
func (h *ResultSet) Close() {
	if h != nil {
		wevtapi.EvtClose(h.handle)
	}
}

// A Session is a Handle returned by OpenSession
type Session Handle

// Close releases a Session.
func (h *Session) Close() {
	if h != nil {
		wevtapi.EvtClose(h.handle)
	}
}

// EvtRenderContextFlags specify which types of values to render from a given event.
//
// Ref: https://docs.microsoft.com/en-us/windows/win32/api/winevt/ne-winevt-evt_render_context_flags
type EvtRenderContextFlags uint32

const (
	// EvtRenderContextValues renders specific properties from the event.
	EvtRenderContextValues EvtRenderContextFlags = iota
	// EvtRenderContextSystem renders the system properties under the System element.
	EvtRenderContextSystem
	// EvtRenderContextUser renders all user-defined properties under the UserData or EventData element.
	EvtRenderContextUser
)

// CreateRenderContext creates a context that specifies the information in the event that you want to render.
//
// The RenderContext is used to obtain only a subset of event data when querying events.
// Without a RenderContext, the entirety of the log data will be returned.
//
// Passing one of EvtRenderContextSystem or EvtRenderContextUser (with valuePaths nil)
// will render all properties under the corresponding element (System or User). Passing
// EvtRenderContextValues along with a list of valuePaths allows the caller to obtain individual
// event elements. valuePaths must be well formed XPath expressions. See the documentation
// for EvtCreateRenderContext and EVT_RENDER_CONTEXT_FLAGS for more detail.
//
// Example, rendering all System values:
//		eventlog.CreateRenderContext(eventlog.EvtRenderContextSystem, nil)
//
// Example, rendering specific values:
//		eventlog.CreateRenderContext(eventlog.EvtRenderContextValues, &[]string{
//				"Event/System/TimeCreated/@SystemTime", "Event/System/Provider/@Name"})
//
// Ref: https://docs.microsoft.com/en-us/windows/win32/api/winevt/nf-winevt-evtcreaterendercontext
func CreateRenderContext(flags EvtRenderContextFlags, valuePaths *[]string) (RenderContext, error) {
	rc := RenderContext{}

	pathsPtr := uintptr(0)
	p := []*uint16{}
	if valuePaths != nil {
		for _, v := range *valuePaths {
			ptr, err := syscall.UTF16PtrFromString(v)
			if err != nil {
				return rc, fmt.Errorf("syscall.UTF16PtrFromString(%s): %w", v, err)
			}
			p = append(p, ptr)
		}
		pathsPtr = uintptr(unsafe.Pointer(&p[0]))
	}

	var err error
	rc.handle, err = wevtapi.EvtCreateRenderContext(uint32(len(p)), uintptr(pathsPtr), uint32(flags))
	return rc, err
}

// An EventSet holds one or more event handles.
//
// Close() must be called to release the event handles when finished.
type EventSet struct {
	Events []Event
	Count  uint32
}

// Close releases all events in the EventSet.
func (e *EventSet) Close() {
	for _, evt := range e.Events {
		evt.Close()
	}
}

// Next gets the next event(s) returned by a query or subscription.
//
// Ref: https://docs.microsoft.com/en-us/windows/win32/api/winevt/nf-winevt-evtnext
func Next(handle ResultSet, count uint32, timeout *time.Duration) (EventSet, error) {
	es := EventSet{}

	defaultTimeout := 2000 * time.Millisecond
	if timeout == nil {
		timeout = &defaultTimeout
	}

	// Get handles to events from the result set.
	evts := make([]windows.Handle, count)
	err := wevtapi.EvtNext(
		handle.handle,                  // Handle to query or subscription result set.
		count,                          // The number of events to attempt to retrieve.
		&evts[0],                       // Pointer to the array of event handles.
		uint32(timeout.Milliseconds()), // Timeout in milliseconds to wait.
		0,                              // Reserved. Must be zero.
		&es.Count)                      // The number of handles in the array that are set by the API.
	if err == windows.ERROR_NO_MORE_ITEMS {
		return es, err
	} else if err != nil {
		return es, fmt.Errorf("wevtapi.EvtNext: %w", err)
	}

	for i := 0; i < int(es.Count); i++ {
		es.Events = append(es.Events, Event{handle: evts[i]})
	}

	return es, nil
}

// Query runs a query to retrieve events from a channel or log file that match the specified query criteria.
//
// Session is only required for remote connections; leave as nil for the local log. Flags can be any of
// wevtapi.EVT_QUERY_FLAGS.
//
// The session handle must remain open until all subsequent processing on the query results have completed. Call
// Close() once complete.
//
// Example:
// 	 conn, err := eventlog.Query(nil, "Windows Powershell", "*", wevtapi.EvtQueryReverseDirection)
// 	 if err != nil {
//     return err
//	 }
//	 defer conn.Close()
//
// Ref: https://docs.microsoft.com/en-us/windows/win32/api/winevt/nf-winevt-evtquery
func Query(session *Session, path string, query string, flags uint32) (ResultSet, error) {
	var rs ResultSet
	var err error

	var s windows.Handle
	if session != nil {
		s = session.handle
	}
	rs.handle, err = wevtapi.EvtQuery(s, windows.StringToUTF16Ptr(path), windows.StringToUTF16Ptr(query), flags)
	if err != nil {
		return rs, fmt.Errorf("EvtQuery: %w", err)
	}
	if rs.handle == windows.InvalidHandle {
		return rs, errors.New("invalid query")
	}
	return rs, nil
}

// EvtVariantData models the union inside of the EVT_VARIANT structure.
//
// Ref: https://docs.microsoft.com/en-us/windows/win32/api/winevt/ns-winevt-evt_variant
type EvtVariantData struct {
	BooleanVal    bool
	SByteVal      int8
	Int16Val      int16
	Int32Val      int32
	Int64Val      int64
	ByteVal       uint8
	UInt16Val     uint16
	UInt32Val     uint32
	UInt64Val     uint64
	SingleVal     float32
	DoubleVal     float64
	FileTimeVal   windows.Filetime
	SysTimeVal    windows.Systemtime
	GuidVal       windows.GUID
	StringVal     string
	AnsiStringVal string
	BinaryVal     byte
	SidVal        windows.SID
	SizeTVal      uint32
	BooleanArr    *[]bool
	SByteArr      *[]int8
	Int16Arr      *[]int16
	Int32Arr      *[]int32
	Int64Arr      *[]int64
	ByteArr       *[]uint16
	UInt16Arr     *[]uint16
	UInt32Arr     *[]uint32
	UInt64Arr     *[]uint64
	SingleArr     *[]float32
	DoubleArr     *[]float64
	FileTimeArr   *[]windows.Filetime
	SysTimeArr    *[]windows.Systemtime
	GuidArr       *[]windows.GUID
	StringArr     *[]string
	AnsiStringArr *[]string
	SidArr        *[]windows.SID
	SizeTArr      *[]uint32
	EvtHandleVal  windows.Handle
	XmlVal        string
	XmlValArr     *[]string
}

// EvtVariantType(EVT_VARIANT_TYPE) defines the possible data types of a EVT_VARIANT data item.
//
// Ref: https://docs.microsoft.com/en-us/windows/win32/api/winevt/ne-winevt-evt_variant_type
type EvtVariantType uint32

const (
	EvtVarTypeNull EvtVariantType = iota
	EvtVarTypeString
	EvtVarTypeAnsiString
	EvtVarTypeSByte
	EvtVarTypeByte
	EvtVarTypeInt16
	EvtVarTypeUInt16
	EvtVarTypeInt32
	EvtVarTypeUInt32
	EvtVarTypeInt64
	EvtVarTypeUInt64
	EvtVarTypeSingle
	EvtVarTypeDouble
	EvtVarTypeBoolean
	EvtVarTypeBinary
	EvtVarTypeGuid
	EvtVarTypeSizeT
	EvtVarTypeFileTime
	EvtVarTypeSysTime
	EvtVarTypeSid
	EvtVarTypeHexInt32
	EvtVarTypeHexInt64
	EvtVarTypeEvtHandle
	EvtVarTypeEvtXml
)

// EvtVariant (EVT_VARIANT) contains event data or property values.
//
// Ref: https://docs.microsoft.com/en-us/windows/win32/api/winevt/ns-winevt-evt_variant
type EvtVariant struct {
	Count uint32
	Type  EvtVariantType
	Data  EvtVariantData
}

// Fragment describes a renderable fragment; an event or to a bookmark.
type Fragment interface {
	Handle() windows.Handle
}

// Render renders a fragment (bookmark or event) as an XML string.
//
// This function renders the entire fragment as XML. To render only specific elements of the event, use RenderValues.
//
// Flags can be either EvtRenderEventValues or EvtRenderEventXml.
//
// Ref: https://docs.microsoft.com/en-us/windows/win32/api/winevt/nf-winevt-evtrender
func Render(fragment Fragment, flag uint32) (string, error) {
	var bufferUsed uint32
	var propertyCount uint32

	if flag == wevtapi.EvtRenderEventValues {
		return "", fmt.Errorf("EvtRenderEventValues requires the RenderValues function")
	}

	// Call EvtRender with a null buffer to get the required buffer size.
	err := wevtapi.EvtRender(
		0,
		fragment.Handle(),
		flag,
		0,
		nil,
		&bufferUsed,
		&propertyCount)
	if err != syscall.ERROR_INSUFFICIENT_BUFFER {
		return "", fmt.Errorf("wevtapi.EvtRender: %w", err)
	}

	// Create a buffer based on the buffer size required.
	buf := make([]uint16, bufferUsed/2)

	// Render the fragment according to the flag.
	if err = wevtapi.EvtRender(
		0,
		fragment.Handle(),
		flag,
		bufferUsed,
		unsafe.Pointer(&buf[0]),
		&bufferUsed,
		&propertyCount); err != nil {
		return "", fmt.Errorf("wevtapi.EvtRender: %w", err)
	}

	return syscall.UTF16ToString(buf), nil
}
<|endoftext|>


<commit_before>/*
 Copyright 2010 Jeremy Wall (jeremy@marzhillstudios.com)
 Use of this source code is governed by the Artistic License 2.0.
 That License is included in the LICENSE file.
*/
package transform

import (
	. "html"
	v "container/vector"
	s "strings"
)

type SelectorQuery struct {
	*v.Vector
}

type Selector struct {
	Type    byte
	TagType string
	Key     string
	Val     string
}

const (
	TAGNAME byte = iota // zero value so the default
	CLASS   byte = '.'
	ID      byte = '#'
	PSEUDO  byte = ':'
	ANY     byte = '*'
	ATTR    byte = '['
)

func newAnyTagClassOrIdSelector(str string) *Selector {
	return &Selector{
		Type:    str[0],
		TagType: "*",
		Val:     str[1:],
	}
}

func newAnyTagSelector(str string) *Selector {
	return &Selector{
		Type:    str[0],
		TagType: "*",
	}
}

func splitAttrs(str string) []string {
	attrs := s.FieldsFunc(str[1:len(str)-1], func(c int) bool {
		if c == '=' {
			return true
		}
		return false
	})
	return attrs
}

func newAnyTagAttrSelector(str string) *Selector {
	attrs := splitAttrs(str)
	return &Selector{
		TagType: "*",
		Type:    str[0],
		Key:     attrs[0],
		Val:     attrs[1],
	}
}

func newTagNameSelector(str string) *Selector {
	return &Selector{
		Type:    TAGNAME,
		TagType: str,
	}
}

func newTagNameWithConstraints(str string, i int) *Selector {
	// TODO(jwall): indexAny use [CLASS,...]
	var selector = new(Selector)
	switch str[i] {
	case CLASS, ID, PSEUDO: // with class or id
		selector = newAnyTagClassOrIdSelector(str[i:])
	case ATTR: // with attribute
		selector = newAnyTagAttrSelector(str[i:])
	default:
		panic("Invalid constraint type for the tagname selector")
	}
	selector.TagType = str[0:i]
	//selector.Type = TAGNAME
	return selector
}

func NewSelector(str string) *Selector {
	str = s.TrimSpace(str) // trim whitespace
	var selector *Selector
	switch str[0] {
	case CLASS, ID: // Any tagname with class or id
		selector = newAnyTagClassOrIdSelector(str)
	case ANY: // Any tagname
		selector = newAnyTagSelector(str)
	case ATTR: // any tagname with attribute
		selector = newAnyTagAttrSelector(str)
	default: // TAGNAME
		// TODO(jwall): indexAny use [CLASS,...]
		if i := s.IndexAny(str, ".:#["); i != -1 {
			selector = newTagNameWithConstraints(str, i)
		} else { // just a tagname
			selector = newTagNameSelector(str)
		}
	}
	return selector
}

func NewSelectorQuery(sel ...string) *SelectorQuery {
	q := SelectorQuery{}
	for _, str := range sel {
		q.Insert(0, *NewSelector(str))
	}
	return &q
}

func testNode(node *Node, sel Selector) bool {
	/*
	if sel.TagType == "*" {
		attrs := node.Attr
		// TODO(jwall): abstract this out
		switch sel.Type {
		case ID:
			if attrs["id"] == sel.Val {
				return true
			}
		case CLASS:
			if attrs["class"] == sel.Val {
				return true
			}
		case ATTR:
			if attrs[sel.Key] == sel.Val {
				return true
			}
			//case PSEUDO:
			//TODO(jwall): implement these
		}
	} else {
		if node.nodeValue == sel.TagType {
			attrs := node.nodeAttributes
			switch sel.Type {
			case ID:
				if attrs["id"] == sel.Val {
					return true
				}
			case CLASS:
				if attrs["class"] == sel.Val {
					return true
				}
			case ATTR:
				if attrs[sel.Key] == sel.Val {
					return true
				}
			//case PSEUDO:
			//TODO(jwall): implement these
			default:
				return true
			}
		}
	}
	*/
	return false
}

/*
 Apply the css selector to a document.

 Returns a Vector of nodes that the selector matched.
*/
func (sel *SelectorQuery) Apply(doc *Document) *v.Vector {
	interesting := new(v.Vector)
	return interesting
}

/*
 Replace each node the selector matches with the passed in node.

 Applies the selector against the doc and replaces the returned
 Nodes with the passed in n HtmlNode.
*/
func (sel *SelectorQuery) Replace(doc *Document, n *Node) {
	nv := sel.Apply(doc)
	for i := 0; i <= nv.Len(); i++ {
		// Change to take into account new usage of *Node
		//nv.At(i).(*Node).Copy(n)
	}
	return
}
<commit_msg>Fixed testNode and added testAttr for the new usage of Node from html package<commit_after>/*
 Copyright 2010 Jeremy Wall (jeremy@marzhillstudios.com)
 Use of this source code is governed by the Artistic License 2.0.
 That License is included in the LICENSE file.
*/
package transform

import (
	. "html"
	v "container/vector"
	s "strings"
)

type SelectorQuery struct {
	*v.Vector
}

type Selector struct {
	Type    byte
	TagType string
	Key     string
	Val     string
}

const (
	TAGNAME byte = iota // zero value so the default
	CLASS   byte = '.'
	ID      byte = '#'
	PSEUDO  byte = ':'
	ANY     byte = '*'
	ATTR    byte = '['
)

func newAnyTagClassOrIdSelector(str string) *Selector {
	return &Selector{
		Type:    str[0],
		TagType: "*",
		Val:     str[1:],
	}
}

func newAnyTagSelector(str string) *Selector {
	return &Selector{
		Type:    str[0],
		TagType: "*",
	}
}

func splitAttrs(str string) []string {
	attrs := s.FieldsFunc(str[1:len(str)-1], func(c int) bool {
		if c == '=' {
			return true
		}
		return false
	})
	return attrs
}

func newAnyTagAttrSelector(str string) *Selector {
	attrs := splitAttrs(str)
	return &Selector{
		TagType: "*",
		Type:    str[0],
		Key:     attrs[0],
		Val:     attrs[1],
	}
}

func newTagNameSelector(str string) *Selector {
	return &Selector{
		Type:    TAGNAME,
		TagType: str,
	}
}

func newTagNameWithConstraints(str string, i int) *Selector {
	// TODO(jwall): indexAny use [CLASS,...]
	var selector = new(Selector)
	switch str[i] {
	case CLASS, ID, PSEUDO: // with class or id
		selector = newAnyTagClassOrIdSelector(str[i:])
	case ATTR: // with attribute
		selector = newAnyTagAttrSelector(str[i:])
	default:
		panic("Invalid constraint type for the tagname selector")
	}
	selector.TagType = str[0:i]
	//selector.Type = TAGNAME
	return selector
}

func NewSelector(str string) *Selector {
	str = s.TrimSpace(str) // trim whitespace
	var selector *Selector
	switch str[0] {
	case CLASS, ID: // Any tagname with class or id
		selector = newAnyTagClassOrIdSelector(str)
	case ANY: // Any tagname
		selector = newAnyTagSelector(str)
	case ATTR: // any tagname with attribute
		selector = newAnyTagAttrSelector(str)
	default: // TAGNAME
		// TODO(jwall): indexAny use [CLASS,...]
		if i := s.IndexAny(str, ".:#["); i != -1 {
			selector = newTagNameWithConstraints(str, i)
		} else { // just a tagname
			selector = newTagNameSelector(str)
		}
	}
	return selector
}

func NewSelectorQuery(sel ...string) *SelectorQuery {
	q := SelectorQuery{}
	for _, str := range sel {
		q.Insert(0, *NewSelector(str))
	}
	return &q
}

func testAttr(attrs []Attribute, key string, val string) bool {
	for _, attr := range attrs {
		if attr.Key == key && attr.Val == val {
			return true
		}
	}
	return false
}

func testNode(node *Node, sel Selector) bool {
	if sel.TagType == "*" {
		attrs := node.Attr
		// TODO(jwall): abstract this out
		switch sel.Type {
		case ID:
			if testAttr(attrs, "id",  sel.Val) {
				return true
			}
		case CLASS:
			if testAttr(attrs, "class", sel.Val) {
				return true
			}
		case ATTR:
			if testAttr(attrs, sel.Key, sel.Val) {
				return true
			}
			//case PSEUDO:
			//TODO(jwall): implement these
		}
	} else {
		if node.Data == sel.TagType {
			attrs := node.Attr
			switch sel.Type {
			case ID:
				if testAttr(attrs, "id", sel.Val) {
					return true
				}
			case CLASS:
				if testAttr(attrs, "class", sel.Val) {
					return true
				}
			case ATTR:
				if testAttr(attrs, sel.Key, sel.Val) {
					return true
				}
			//case PSEUDO:
			//TODO(jwall): implement these
			default:
				return true
			}
		}
	}
	return false
}

/*
 Apply the css selector to a document.

 Returns a Vector of nodes that the selector matched.
*/
func (sel *SelectorQuery) Apply(doc *Document) *v.Vector {
	interesting := new(v.Vector)
	return interesting
}

/*
 Replace each node the selector matches with the passed in node.

 Applies the selector against the doc and replaces the returned
 Nodes with the passed in n HtmlNode.
*/
func (sel *SelectorQuery) Replace(doc *Document, n *Node) {
	nv := sel.Apply(doc)
	for i := 0; i <= nv.Len(); i++ {
		// Change to take into account new usage of *Node
		//nv.At(i).(*Node).Copy(n)
	}
	return
}
<|endoftext|>


<commit_before>package rule

import (
	"fmt"
	"io/ioutil"
)

// DefaultRuleSet is the list of rules that are built into the inspector
const DefaultRuleSet = `---
- kind: PackageAvailable
  when: ["centos"]
  packageName: somePackage
  packageVersion: 1.0

- kind: PackageAvailable
  when: ["ubuntu"]
  packageName: otherPackage
  packageVersion: 1.2

- kind: PackageInstalled
  when: []
  packageName: docker
  packageVersion: 1.11
`

// DefaultRules returns the list of rules that are built into the inspector
func DefaultRules() []Rule {
	rules, err := unmarshalRules([]byte(DefaultRuleSet))
	if err != nil {
		// The default rules should not contain errors
		// If they do, panic so that we catch them during tests
		panic(err)
	}
	return rules
}

// DumpDefaultRules writes the default rule set to a file
func DumpDefaultRules(file string) error {
	err := ioutil.WriteFile(file, []byte(DefaultRuleSet), 0644)
	if err != nil {
		return fmt.Errorf("error writing default rule set to %q: %v", file, err)
	}
	return nil
}
<commit_msg>KIS-71: Don't export default rule set constant<commit_after>package rule

import (
	"fmt"
	"io/ioutil"
)

// DefaultRuleSet is the list of rules that are built into the inspector
const defaultRuleSet = `---
- kind: PackageAvailable
  when: ["centos"]
  packageName: somePackage
  packageVersion: 1.0

- kind: PackageAvailable
  when: ["ubuntu"]
  packageName: otherPackage
  packageVersion: 1.2

- kind: PackageInstalled
  when: []
  packageName: docker
  packageVersion: 1.11
`

// DefaultRules returns the list of rules that are built into the inspector
func DefaultRules() []Rule {
	rules, err := unmarshalRules([]byte(defaultRuleSet))
	if err != nil {
		// The default rules should not contain errors
		// If they do, panic so that we catch them during tests
		panic(err)
	}
	return rules
}

// DumpDefaultRules writes the default rule set to a file
func DumpDefaultRules(file string) error {
	err := ioutil.WriteFile(file, []byte(defaultRuleSet), 0644)
	if err != nil {
		return fmt.Errorf("error writing default rule set to %q: %v", file, err)
	}
	return nil
}
<|endoftext|>


<commit_before>package api

import (
	"github.com/Venafi/vcert/pkg/certificate"
)

// CustomField defines a custom field to be passed to Venafi
type CustomField struct {
	Type  certificate.CustomFieldType `json:"type,omitempty"`
	Name  string                      `json:"name"`
	Value string                      `json:"value"`
}
<commit_msg>Add copyright<commit_after>/*
Copyright 2020 The Jetstack cert-manager contributors.

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 api

import (
	"github.com/Venafi/vcert/pkg/certificate"
)

// CustomField defines a custom field to be passed to Venafi
type CustomField struct {
	Type  certificate.CustomFieldType `json:"type,omitempty"`
	Name  string                      `json:"name"`
	Value string                      `json:"value"`
}
<|endoftext|>