<commit_before>// +build windows

package process

import (
	"errors"
	"fmt"
	"strings"
	"time"
	"unsafe"

	"github.com/StackExchange/wmi"
	"github.com/shirou/w32"

	cpu "github.com/shirou/gopsutil/cpu"
	"github.com/shirou/gopsutil/internal/common"
	net "github.com/shirou/gopsutil/net"
	"golang.org/x/sys/windows"
)

const (
	NoMoreFiles   = 0x12
	MaxPathLength = 260
)

var (
	modpsapi                 = windows.NewLazyDLL("psapi.dll")
	procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo")
)

type SystemProcessInformation struct {
	NextEntryOffset   uint64
	NumberOfThreads   uint64
	Reserved1         [48]byte
	Reserved2         [3]byte
	UniqueProcessID   uintptr
	Reserved3         uintptr
	HandleCount       uint64
	Reserved4         [4]byte
	Reserved5         [11]byte
	PeakPagefileUsage uint64
	PrivatePageCount  uint64
	Reserved6         [6]uint64
}

// Memory_info_ex is different between OSes
type MemoryInfoExStat struct {
}

type MemoryMapsStat struct {
}

type Win32_Process struct {
	Name                string
	ExecutablePath      *string
	CommandLine         *string
	Priority            uint32
	CreationDate        *time.Time
	ProcessID           uint32
	ThreadCount         uint32
	Status              *string
	ReadOperationCount  uint64
	ReadTransferCount   uint64
	WriteOperationCount uint64
	WriteTransferCount  uint64

	/*
		CSCreationClassName   string
		CSName                string
		Caption               *string
		CreationClassName     string
		Description           *string
		ExecutionState        *uint16
		HandleCount           uint32
		KernelModeTime        uint64
		MaximumWorkingSetSize *uint32
		MinimumWorkingSetSize *uint32
		OSCreationClassName   string
		OSName                string
		OtherOperationCount   uint64
		OtherTransferCount    uint64
		PageFaults            uint32
		PageFileUsage         uint32
		ParentProcessID       uint32
		PeakPageFileUsage     uint32
		PeakVirtualSize       uint64
		PeakWorkingSetSize    uint32
		PrivatePageCount      uint64
		TerminationDate       *time.Time
		UserModeTime          uint64
		WorkingSetSize        uint64
	*/
}

func Pids() ([]int32, error) {
	var ret []int32

	procs, err := processes()
	if err != nil {
		return ret, nil
	}

	for _, proc := range procs {
		ret = append(ret, proc.Pid)
	}

	return ret, nil
}

func (p *Process) Ppid() (int32, error) {
	ret, _, _, err := p.getFromSnapProcess(p.Pid)
	if err != nil {
		return 0, err
	}
	return ret, nil
}

func GetWin32Proc(pid int32) ([]Win32_Process, error) {
	var dst []Win32_Process
	query := fmt.Sprintf("WHERE ProcessId = %d", pid)
	q := wmi.CreateQuery(&dst, query)
	err := wmi.Query(q, &dst)
	if err != nil {
		return []Win32_Process{}, fmt.Errorf("could not get win32Proc: %s", err)
	}
	if len(dst) != 1 {
		return []Win32_Process{}, fmt.Errorf("could not get win32Proc: empty")
	}
	return dst, nil
}

func (p *Process) Name() (string, error) {
	dst, err := GetWin32Proc(p.Pid)
	if err != nil {
		return "", fmt.Errorf("could not get Name: %s", err)
	}
	return dst[0].Name, nil
}
func (p *Process) Exe() (string, error) {
	dst, err := GetWin32Proc(p.Pid)
	if err != nil {
		return "", fmt.Errorf("could not get ExecutablePath: %s", err)
	}
	return *dst[0].ExecutablePath, nil
}
func (p *Process) Cmdline() (string, error) {
	dst, err := GetWin32Proc(p.Pid)
	if err != nil {
		return "", fmt.Errorf("could not get CommandLine: %s", err)
	}
	return *dst[0].CommandLine, nil
}

// CmdlineSlice returns the command line arguments of the process as a slice with each
// element being an argument. This merely returns the CommandLine informations passed
// to the process split on the 0x20 ASCII character.
func (p *Process) CmdlineSlice() ([]string, error) {
	cmdline, err := p.Cmdline()
	if err != nil {
		return nil, err
	}
	return strings.Split(cmdline, " "), nil
}

func (p *Process) CreateTime() (int64, error) {
	ru, err := getRusage(p.Pid)
	if err != nil {
		return 0, fmt.Errorf("could not get CreationDate: %s", err)
	}

	return ru.CreationTime.Nanoseconds() / 1000000, nil
}

func (p *Process) Cwd() (string, error) {
	return "", common.ErrNotImplementedError
}
func (p *Process) Parent() (*Process, error) {
	return p, common.ErrNotImplementedError
}
func (p *Process) Status() (string, error) {
	return "", common.ErrNotImplementedError
}
func (p *Process) Username() (string, error) {
	return "", common.ErrNotImplementedError
}
func (p *Process) Uids() ([]int32, error) {
	var uids []int32

	return uids, common.ErrNotImplementedError
}
func (p *Process) Gids() ([]int32, error) {
	var gids []int32
	return gids, common.ErrNotImplementedError
}
func (p *Process) Terminal() (string, error) {
	return "", common.ErrNotImplementedError
}

// Nice returnes priority in Windows
func (p *Process) Nice() (int32, error) {
	dst, err := GetWin32Proc(p.Pid)
	if err != nil {
		return 0, fmt.Errorf("could not get Priority: %s", err)
	}
	return int32(dst[0].Priority), nil
}
func (p *Process) IOnice() (int32, error) {
	return 0, common.ErrNotImplementedError
}
func (p *Process) Rlimit() ([]RlimitStat, error) {
	var rlimit []RlimitStat

	return rlimit, common.ErrNotImplementedError
}

func (p *Process) IOCounters() (*IOCountersStat, error) {
	dst, err := GetWin32Proc(p.Pid)
	if err != nil || len(dst) == 0 {
		return nil, fmt.Errorf("could not get Win32Proc: %s", err)
	}
	ret := &IOCountersStat{
		ReadCount:  uint64(dst[0].ReadOperationCount),
		ReadBytes:  uint64(dst[0].ReadTransferCount),
		WriteCount: uint64(dst[0].WriteOperationCount),
		WriteBytes: uint64(dst[0].WriteTransferCount),
	}

	return ret, nil
}
func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
	return nil, common.ErrNotImplementedError
}
func (p *Process) NumFDs() (int32, error) {
	return 0, common.ErrNotImplementedError
}
func (p *Process) NumThreads() (int32, error) {
	dst, err := GetWin32Proc(p.Pid)
	if err != nil {
		return 0, fmt.Errorf("could not get ThreadCount: %s", err)
	}
	return int32(dst[0].ThreadCount), nil
}
func (p *Process) Threads() (map[string]string, error) {
	ret := make(map[string]string, 0)
	return ret, common.ErrNotImplementedError
}
func (p *Process) Times() (*cpu.TimesStat, error) {
	return nil, common.ErrNotImplementedError
}
func (p *Process) CPUAffinity() ([]int32, error) {
	return nil, common.ErrNotImplementedError
}
func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
	mem, err := getMemoryInfo(p.Pid)
	if err != nil {
		return nil, err
	}

	ret := &MemoryInfoStat{
		RSS: uint64(mem.WorkingSetSize),
		VMS: uint64(mem.PagefileUsage),
	}

	return ret, nil
}
func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
	return nil, common.ErrNotImplementedError
}

func (p *Process) Children() ([]*Process, error) {
	return nil, common.ErrNotImplementedError
}

func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
	return nil, common.ErrNotImplementedError
}

func (p *Process) Connections() ([]net.ConnectionStat, error) {
	return nil, common.ErrNotImplementedError
}

func (p *Process) NetIOCounters(pernic bool) ([]net.IOCountersStat, error) {
	return nil, common.ErrNotImplementedError
}

func (p *Process) IsRunning() (bool, error) {
	return true, common.ErrNotImplementedError
}

func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
	var ret []MemoryMapsStat
	return &ret, common.ErrNotImplementedError
}

func NewProcess(pid int32) (*Process, error) {
	p := &Process{Pid: pid}

	return p, nil
}

func (p *Process) SendSignal(sig windows.Signal) error {
	return common.ErrNotImplementedError
}

func (p *Process) Suspend() error {
	return common.ErrNotImplementedError
}
func (p *Process) Resume() error {
	return common.ErrNotImplementedError
}

func (p *Process) Terminate() error {
	// PROCESS_TERMINATE = 0x0001
	proc := w32.OpenProcess(0x0001, false, uint32(p.Pid))
	ret := w32.TerminateProcess(proc, 0)
	w32.CloseHandle(proc)

	if ret == false {
		return windows.GetLastError()
	} else {
		return nil
	}
}

func (p *Process) Kill() error {
	return common.ErrNotImplementedError
}

func (p *Process) getFromSnapProcess(pid int32) (int32, int32, string, error) {
	snap := w32.CreateToolhelp32Snapshot(w32.TH32CS_SNAPPROCESS, uint32(pid))
	if snap == 0 {
		return 0, 0, "", windows.GetLastError()
	}
	defer w32.CloseHandle(snap)
	var pe32 w32.PROCESSENTRY32
	pe32.DwSize = uint32(unsafe.Sizeof(pe32))
	if w32.Process32First(snap, &pe32) == false {
		return 0, 0, "", windows.GetLastError()
	}

	if pe32.Th32ProcessID == uint32(pid) {
		szexe := windows.UTF16ToString(pe32.SzExeFile[:])
		return int32(pe32.Th32ParentProcessID), int32(pe32.CntThreads), szexe, nil
	}

	for w32.Process32Next(snap, &pe32) {
		if pe32.Th32ProcessID == uint32(pid) {
			szexe := windows.UTF16ToString(pe32.SzExeFile[:])
			return int32(pe32.Th32ParentProcessID), int32(pe32.CntThreads), szexe, nil
		}
	}
	return 0, 0, "", errors.New("Couldn't find pid:" + string(pid))
}

// Get processes
func processes() ([]*Process, error) {

	var dst []Win32_Process
	q := wmi.CreateQuery(&dst, "")
	err := wmi.Query(q, &dst)
	if err != nil {
		return []*Process{}, err
	}
	if len(dst) == 0 {
		return []*Process{}, fmt.Errorf("could not get Process")
	}
	results := make([]*Process, 0, len(dst))
	for _, proc := range dst {
		p, err := NewProcess(int32(proc.ProcessID))
		if err != nil {
			continue
		}
		results = append(results, p)
	}

	return results, nil
}

func getProcInfo(pid int32) (*SystemProcessInformation, error) {
	initialBufferSize := uint64(0x4000)
	bufferSize := initialBufferSize
	buffer := make([]byte, bufferSize)

	var sysProcInfo SystemProcessInformation
	ret, _, _ := common.ProcNtQuerySystemInformation.Call(
		uintptr(unsafe.Pointer(&sysProcInfo)),
		uintptr(unsafe.Pointer(&buffer[0])),
		uintptr(unsafe.Pointer(&bufferSize)),
		uintptr(unsafe.Pointer(&bufferSize)))
	if ret != 0 {
		return nil, windows.GetLastError()
	}

	return &sysProcInfo, nil
}

func getRusage(pid int32) (*windows.Rusage, error) {
	var CPU windows.Rusage

	c, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION, false, uint32(pid))
	if err != nil {
		return nil, err
	}
	defer windows.CloseHandle(c)

	if err := windows.GetProcessTimes(c, &CPU.CreationTime, &CPU.ExitTime, &CPU.KernelTime, &CPU.UserTime); err != nil {
		return nil, err
	}

	return &CPU, nil
}

func getMemoryInfo(pid int32) (PROCESS_MEMORY_COUNTERS, error) {
	var mem PROCESS_MEMORY_COUNTERS
	c, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION, false, uint32(pid))
	if err != nil {
		return mem, err
	}
	defer windows.CloseHandle(c)
	if err := getProcessMemoryInfo(c, &mem); err != nil {
		return mem, err
	}

	return mem, err
}

func getProcessMemoryInfo(h windows.Handle, mem *PROCESS_MEMORY_COUNTERS) (err error) {
	r1, _, e1 := windows.Syscall(procGetProcessMemoryInfo.Addr(), 3, uintptr(h), uintptr(unsafe.Pointer(mem)), uintptr(unsafe.Sizeof(*mem)))
	if r1 == 0 {
		if e1 != 0 {
			err = error(e1)
		} else {
			err = windows.EINVAL
		}
	}
	return
}
<commit_msg>windows.EINVAL doesn't exist, only syscall.EINVAL.<commit_after>// +build windows

package process

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

	"github.com/StackExchange/wmi"
	cpu "github.com/shirou/gopsutil/cpu"
	"github.com/shirou/gopsutil/internal/common"
	net "github.com/shirou/gopsutil/net"
	"github.com/shirou/w32"
	"golang.org/x/sys/windows"
)

const (
	NoMoreFiles   = 0x12
	MaxPathLength = 260
)

var (
	modpsapi                 = windows.NewLazyDLL("psapi.dll")
	procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo")
)

type SystemProcessInformation struct {
	NextEntryOffset   uint64
	NumberOfThreads   uint64
	Reserved1         [48]byte
	Reserved2         [3]byte
	UniqueProcessID   uintptr
	Reserved3         uintptr
	HandleCount       uint64
	Reserved4         [4]byte
	Reserved5         [11]byte
	PeakPagefileUsage uint64
	PrivatePageCount  uint64
	Reserved6         [6]uint64
}

// Memory_info_ex is different between OSes
type MemoryInfoExStat struct {
}

type MemoryMapsStat struct {
}

type Win32_Process struct {
	Name                string
	ExecutablePath      *string
	CommandLine         *string
	Priority            uint32
	CreationDate        *time.Time
	ProcessID           uint32
	ThreadCount         uint32
	Status              *string
	ReadOperationCount  uint64
	ReadTransferCount   uint64
	WriteOperationCount uint64
	WriteTransferCount  uint64

	/*
		CSCreationClassName   string
		CSName                string
		Caption               *string
		CreationClassName     string
		Description           *string
		ExecutionState        *uint16
		HandleCount           uint32
		KernelModeTime        uint64
		MaximumWorkingSetSize *uint32
		MinimumWorkingSetSize *uint32
		OSCreationClassName   string
		OSName                string
		OtherOperationCount   uint64
		OtherTransferCount    uint64
		PageFaults            uint32
		PageFileUsage         uint32
		ParentProcessID       uint32
		PeakPageFileUsage     uint32
		PeakVirtualSize       uint64
		PeakWorkingSetSize    uint32
		PrivatePageCount      uint64
		TerminationDate       *time.Time
		UserModeTime          uint64
		WorkingSetSize        uint64
	*/
}

func Pids() ([]int32, error) {
	var ret []int32

	procs, err := processes()
	if err != nil {
		return ret, nil
	}

	for _, proc := range procs {
		ret = append(ret, proc.Pid)
	}

	return ret, nil
}

func (p *Process) Ppid() (int32, error) {
	ret, _, _, err := p.getFromSnapProcess(p.Pid)
	if err != nil {
		return 0, err
	}
	return ret, nil
}

func GetWin32Proc(pid int32) ([]Win32_Process, error) {
	var dst []Win32_Process
	query := fmt.Sprintf("WHERE ProcessId = %d", pid)
	q := wmi.CreateQuery(&dst, query)
	err := wmi.Query(q, &dst)
	if err != nil {
		return []Win32_Process{}, fmt.Errorf("could not get win32Proc: %s", err)
	}
	if len(dst) != 1 {
		return []Win32_Process{}, fmt.Errorf("could not get win32Proc: empty")
	}
	return dst, nil
}

func (p *Process) Name() (string, error) {
	dst, err := GetWin32Proc(p.Pid)
	if err != nil {
		return "", fmt.Errorf("could not get Name: %s", err)
	}
	return dst[0].Name, nil
}
func (p *Process) Exe() (string, error) {
	dst, err := GetWin32Proc(p.Pid)
	if err != nil {
		return "", fmt.Errorf("could not get ExecutablePath: %s", err)
	}
	return *dst[0].ExecutablePath, nil
}
func (p *Process) Cmdline() (string, error) {
	dst, err := GetWin32Proc(p.Pid)
	if err != nil {
		return "", fmt.Errorf("could not get CommandLine: %s", err)
	}
	return *dst[0].CommandLine, nil
}

// CmdlineSlice returns the command line arguments of the process as a slice with each
// element being an argument. This merely returns the CommandLine informations passed
// to the process split on the 0x20 ASCII character.
func (p *Process) CmdlineSlice() ([]string, error) {
	cmdline, err := p.Cmdline()
	if err != nil {
		return nil, err
	}
	return strings.Split(cmdline, " "), nil
}

func (p *Process) CreateTime() (int64, error) {
	ru, err := getRusage(p.Pid)
	if err != nil {
		return 0, fmt.Errorf("could not get CreationDate: %s", err)
	}

	return ru.CreationTime.Nanoseconds() / 1000000, nil
}

func (p *Process) Cwd() (string, error) {
	return "", common.ErrNotImplementedError
}
func (p *Process) Parent() (*Process, error) {
	return p, common.ErrNotImplementedError
}
func (p *Process) Status() (string, error) {
	return "", common.ErrNotImplementedError
}
func (p *Process) Username() (string, error) {
	return "", common.ErrNotImplementedError
}
func (p *Process) Uids() ([]int32, error) {
	var uids []int32

	return uids, common.ErrNotImplementedError
}
func (p *Process) Gids() ([]int32, error) {
	var gids []int32
	return gids, common.ErrNotImplementedError
}
func (p *Process) Terminal() (string, error) {
	return "", common.ErrNotImplementedError
}

// Nice returnes priority in Windows
func (p *Process) Nice() (int32, error) {
	dst, err := GetWin32Proc(p.Pid)
	if err != nil {
		return 0, fmt.Errorf("could not get Priority: %s", err)
	}
	return int32(dst[0].Priority), nil
}
func (p *Process) IOnice() (int32, error) {
	return 0, common.ErrNotImplementedError
}
func (p *Process) Rlimit() ([]RlimitStat, error) {
	var rlimit []RlimitStat

	return rlimit, common.ErrNotImplementedError
}

func (p *Process) IOCounters() (*IOCountersStat, error) {
	dst, err := GetWin32Proc(p.Pid)
	if err != nil || len(dst) == 0 {
		return nil, fmt.Errorf("could not get Win32Proc: %s", err)
	}
	ret := &IOCountersStat{
		ReadCount:  uint64(dst[0].ReadOperationCount),
		ReadBytes:  uint64(dst[0].ReadTransferCount),
		WriteCount: uint64(dst[0].WriteOperationCount),
		WriteBytes: uint64(dst[0].WriteTransferCount),
	}

	return ret, nil
}
func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
	return nil, common.ErrNotImplementedError
}
func (p *Process) NumFDs() (int32, error) {
	return 0, common.ErrNotImplementedError
}
func (p *Process) NumThreads() (int32, error) {
	dst, err := GetWin32Proc(p.Pid)
	if err != nil {
		return 0, fmt.Errorf("could not get ThreadCount: %s", err)
	}
	return int32(dst[0].ThreadCount), nil
}
func (p *Process) Threads() (map[string]string, error) {
	ret := make(map[string]string, 0)
	return ret, common.ErrNotImplementedError
}
func (p *Process) Times() (*cpu.TimesStat, error) {
	return nil, common.ErrNotImplementedError
}
func (p *Process) CPUAffinity() ([]int32, error) {
	return nil, common.ErrNotImplementedError
}
func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
	mem, err := getMemoryInfo(p.Pid)
	if err != nil {
		return nil, err
	}

	ret := &MemoryInfoStat{
		RSS: uint64(mem.WorkingSetSize),
		VMS: uint64(mem.PagefileUsage),
	}

	return ret, nil
}
func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
	return nil, common.ErrNotImplementedError
}

func (p *Process) Children() ([]*Process, error) {
	return nil, common.ErrNotImplementedError
}

func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
	return nil, common.ErrNotImplementedError
}

func (p *Process) Connections() ([]net.ConnectionStat, error) {
	return nil, common.ErrNotImplementedError
}

func (p *Process) NetIOCounters(pernic bool) ([]net.IOCountersStat, error) {
	return nil, common.ErrNotImplementedError
}

func (p *Process) IsRunning() (bool, error) {
	return true, common.ErrNotImplementedError
}

func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
	var ret []MemoryMapsStat
	return &ret, common.ErrNotImplementedError
}

func NewProcess(pid int32) (*Process, error) {
	p := &Process{Pid: pid}

	return p, nil
}

func (p *Process) SendSignal(sig windows.Signal) error {
	return common.ErrNotImplementedError
}

func (p *Process) Suspend() error {
	return common.ErrNotImplementedError
}
func (p *Process) Resume() error {
	return common.ErrNotImplementedError
}

func (p *Process) Terminate() error {
	// PROCESS_TERMINATE = 0x0001
	proc := w32.OpenProcess(0x0001, false, uint32(p.Pid))
	ret := w32.TerminateProcess(proc, 0)
	w32.CloseHandle(proc)

	if ret == false {
		return windows.GetLastError()
	} else {
		return nil
	}
}

func (p *Process) Kill() error {
	return common.ErrNotImplementedError
}

func (p *Process) getFromSnapProcess(pid int32) (int32, int32, string, error) {
	snap := w32.CreateToolhelp32Snapshot(w32.TH32CS_SNAPPROCESS, uint32(pid))
	if snap == 0 {
		return 0, 0, "", windows.GetLastError()
	}
	defer w32.CloseHandle(snap)
	var pe32 w32.PROCESSENTRY32
	pe32.DwSize = uint32(unsafe.Sizeof(pe32))
	if w32.Process32First(snap, &pe32) == false {
		return 0, 0, "", windows.GetLastError()
	}

	if pe32.Th32ProcessID == uint32(pid) {
		szexe := windows.UTF16ToString(pe32.SzExeFile[:])
		return int32(pe32.Th32ParentProcessID), int32(pe32.CntThreads), szexe, nil
	}

	for w32.Process32Next(snap, &pe32) {
		if pe32.Th32ProcessID == uint32(pid) {
			szexe := windows.UTF16ToString(pe32.SzExeFile[:])
			return int32(pe32.Th32ParentProcessID), int32(pe32.CntThreads), szexe, nil
		}
	}
	return 0, 0, "", errors.New("Couldn't find pid:" + string(pid))
}

// Get processes
func processes() ([]*Process, error) {

	var dst []Win32_Process
	q := wmi.CreateQuery(&dst, "")
	err := wmi.Query(q, &dst)
	if err != nil {
		return []*Process{}, err
	}
	if len(dst) == 0 {
		return []*Process{}, fmt.Errorf("could not get Process")
	}
	results := make([]*Process, 0, len(dst))
	for _, proc := range dst {
		p, err := NewProcess(int32(proc.ProcessID))
		if err != nil {
			continue
		}
		results = append(results, p)
	}

	return results, nil
}

func getProcInfo(pid int32) (*SystemProcessInformation, error) {
	initialBufferSize := uint64(0x4000)
	bufferSize := initialBufferSize
	buffer := make([]byte, bufferSize)

	var sysProcInfo SystemProcessInformation
	ret, _, _ := common.ProcNtQuerySystemInformation.Call(
		uintptr(unsafe.Pointer(&sysProcInfo)),
		uintptr(unsafe.Pointer(&buffer[0])),
		uintptr(unsafe.Pointer(&bufferSize)),
		uintptr(unsafe.Pointer(&bufferSize)))
	if ret != 0 {
		return nil, windows.GetLastError()
	}

	return &sysProcInfo, nil
}

func getRusage(pid int32) (*windows.Rusage, error) {
	var CPU windows.Rusage

	c, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION, false, uint32(pid))
	if err != nil {
		return nil, err
	}
	defer windows.CloseHandle(c)

	if err := windows.GetProcessTimes(c, &CPU.CreationTime, &CPU.ExitTime, &CPU.KernelTime, &CPU.UserTime); err != nil {
		return nil, err
	}

	return &CPU, nil
}

func getMemoryInfo(pid int32) (PROCESS_MEMORY_COUNTERS, error) {
	var mem PROCESS_MEMORY_COUNTERS
	c, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION, false, uint32(pid))
	if err != nil {
		return mem, err
	}
	defer windows.CloseHandle(c)
	if err := getProcessMemoryInfo(c, &mem); err != nil {
		return mem, err
	}

	return mem, err
}

func getProcessMemoryInfo(h windows.Handle, mem *PROCESS_MEMORY_COUNTERS) (err error) {
	r1, _, e1 := windows.Syscall(procGetProcessMemoryInfo.Addr(), 3, uintptr(h), uintptr(unsafe.Pointer(mem)), uintptr(unsafe.Sizeof(*mem)))
	if r1 == 0 {
		if e1 != 0 {
			err = error(e1)
		} else {
			err = syscall.EINVAL
		}
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"flag"
	"encoding/json"
	"os"
	"regexp"
	"sync/atomic"
	"log"
	"time"
	"path/filepath"
	"github.com/APTrust/bagman"
	"launchpad.net/goamz/aws"
	"launchpad.net/goamz/s3"
	"github.com/bitly/go-nsq"
)

type Channels struct {
	FetchChannel     chan bagman.ProcessResult
	UnpackChannel    chan bagman.ProcessResult
	CleanUpChannel   chan bagman.ProcessResult
	ResultsChannel   chan bagman.ProcessResult
}

// Global vars.
var channels *Channels
var config bagman.Config
var jsonLog *log.Logger
var messageLog *log.Logger
var taskCounter = int64(0)
var volume *bagman.Volume
var succeeded = int64(0)
var failed = int64(0)
var bytesInS3 = int64(0)
var bytesProcessed = int64(0)

// bag_processor receives messages from nsqd describing
// items in the S3 receiving buckets. Each item/message
// follows this flow:
//
// 1. Fetch channel: fetches the file from S3.
// 2. Unpack channel: untars the bag files, parses and validates
//    the bag, reads tags, generates checksums and generic file
//    UUIDs.
// 3. **** TODO **** Copy files to S3 permanent storage.
// 4. Results channel: tells the queue whether processing
//    succeeded, and if not, whether the item should be requeued.
//    Also logs results to json and message logs.
// 5. Cleanup channe: cleans up the files after processing
//    completes.
//
// If a failure occurs anywhere in the first three steps,
// processing goes directly to the Results Channel, which
// records the error and the disposition (retry/give up).
//
// As long as the message from nsq contains valid JSON,
// steps 4 and 5 ALWAYS run.
//
// The bag processor has so many responsibilities because
// downloading, untarring and running checksums on
// multi-gigabyte files takes a lot of time. We want to
// avoid having separate processes repeatedly download and
// untar the files, so bag_processor performs all operations
// that require local access to the raw contents of the bags.
func main() {

	loadConfig()
	initVolume()
	initChannels()
	initGoRoutines(channels)

	reader, err := nsq.NewReader(config.BagProcessorTopic, config.BagProcessorChannel)
	if err != nil {
		messageLog.Fatalf(err.Error())
	}

	handler := &BagProcessor{}
	reader.SetMaxInFlight(100)
	reader.AddAsyncHandler(handler)
	reader.ConnectToLookupd(config.NsqLookupd)

	// This reader blocks until we get an interrupt, so our program does not exit.
	<-reader.ExitChan

	//waitForAllTasks()
}

func loadConfig() {
	// Load the config or die.
	requestedConfig := flag.String("config", "", "configuration to run")
	flag.Parse()
	config = bagman.LoadRequestedConfig(requestedConfig)
	jsonLog, messageLog = bagman.InitLoggers(config.LogDirectory, "bag_processor")
}

// Set up the volume to keep track of how much disk space is
// available. We want to avoid downloading large files when
// we know ahead of time that the volume containing the tar
// directory doesn't have enough space to accomodate them.
func initVolume() {
	var err error
	volume, err = bagman.NewVolume(config.TarDirectory)
	if err != nil {
		panic(err.Error())
	}
}

// Set up the channels. It's essential that that the fetchChannel
// be limited to a relatively low number. If we are downloading
// 1GB tar files, we need space to store the tar file AND the
// untarred version. That's about 2 x 1GB. We do not want to pull
// down 1000 files at once, or we'll run out of disk space!
// If config sets fetchers to 10, we can pull down 10 files at a
// time. The fetch queue could hold 10 * 4 = 40 items, so we'd
// have max 40 tar files + untarred directories on disk at once.
// The number of workers should be close to the number of CPU
// cores.
func initChannels() {
	fetcherBufferSize := config.Fetchers * 4
	workerBufferSize := config.Workers * 10

	channels = &Channels{}
	channels.FetchChannel = make(chan bagman.ProcessResult, fetcherBufferSize)
	channels.UnpackChannel = make(chan bagman.ProcessResult, workerBufferSize)
	channels.CleanUpChannel = make(chan bagman.ProcessResult, workerBufferSize)
	channels.ResultsChannel = make(chan bagman.ProcessResult, workerBufferSize)
}

// Set up our go routines. We do NOT want one go routine per
// S3 file. If we do that, the system will run out of file handles,
// as we'll have tens of thousands of open connections to S3
// trying to write data into tens of thousands of local files.
func initGoRoutines(channels *Channels) {
	for i := 0; i < config.Fetchers; i++ {
		go doFetch()
	}

	for i := 0; i < config.Workers; i++ {
		go doUnpack()
		go logResult()
		go doCleanUp()
	}
}

type BagProcessor struct {

}

// MessageHandler handles messages from the queue, putting each
// item into the pipleline.
func (*BagProcessor) HandleMessage(message *nsq.Message, outputChannel chan *nsq.FinishedMessage) {

	fmt.Println(string(message.Body))
	message.Attempts++
	atomic.AddInt64(&taskCounter, 1)

	var s3File bagman.S3File
	err := json.Unmarshal(message.Body, &s3File)
	if err != nil {
		messageLog.Println("[ERROR] Could not unmarshal JSON data from nsq:",
			string(message.Body))
		finishedMessage := &nsq.FinishedMessage{message.Id, 0, true}
		outputChannel <- finishedMessage
		return
	}

	// Create the result struct and pass it down the pipeline
	result := bagman.ProcessResult{
		message,
		outputChannel,
		&s3File,
		nil,
		nil,
		nil,
		nil,
		true}
	channels.FetchChannel <- result
	messageLog.Println("[INFO]", "Put", s3File.Key.Key, "into fetch queue")
}

// This function blocks until all tasks are complete.
// sync.WaitGroup is the standard way of doing this, but
// WaitGroup is really for counting go routines. We have only a handful
// of go routines, and a huge number of tasks. We're counting the tasks.
func waitForAllTasks() {
	for {
		if atomic.LoadInt64(&taskCounter) == 0 {
			break
		}
		time.Sleep(5 * time.Second)
	}
}

// This runs as a go routine to fetch files from S3.
func doFetch() {
	for result := range channels.FetchChannel {
		s3Key := result.S3File.Key
		// Disk needs filesize * 2 disk space to accomodate tar file & untarred files
		err := volume.Reserve(uint64(s3Key.Size * 2))
		if err != nil {
			// Not enough room on disk
			messageLog.Println("[WARNING]", "Requeueing",
				s3Key.Key, "- not enough disk space")
			result.Error = err
			result.Retry = true
			channels.ResultsChannel <- result
		} else {
			messageLog.Println("[INFO]", "Fetching", s3Key)
			fetchResult := Fetch(result.S3File.BucketName, s3Key)
			result.FetchResult = fetchResult
			result.Retry = fetchResult.Retry
			if fetchResult.Error != nil {
				// Fetch from S3 failed. Requeue.
				result.Error = fetchResult.Error
				channels.ResultsChannel <- result
			} else {
				// Got S3 file. Untar it.
				// And touch the message, so nsqd knows we're making progress.
				result.NsqMessage.Touch()
				channels.UnpackChannel <- result
			}
		}
	}
}

// This runs as a go routine to untar files downloaded from S3.
func doUnpack() {
	for result := range channels.UnpackChannel {
		if result.Error != nil {
			// Unpack failed. Go to end.
			messageLog.Println("[INFO]", "Nothing to unpack for",
				result.S3File.Key.Key)
			channels.ResultsChannel <- result
		} else {
			// Unpacked! Now process the bag and touch message
			// so nsqd knows we're making progress.
			messageLog.Println("[INFO]", "Unpacking", result.S3File.Key.Key)
			result.NsqMessage.Touch()
			ProcessBagFile(&result)
			channels.ResultsChannel <- result
		}
	}
}

// This runs as a go routine to remove the files we downloaded
// and untarred.
func doCleanUp() {
	for result := range channels.CleanUpChannel {
		messageLog.Println("[INFO]", "Cleaning up", result.S3File.Key.Key)
		if result.S3File.Key.Key != "" && result.FetchResult.LocalTarFile != "" {
			// Clean up any files we downloaded and unpacked
			errors := CleanUp(result.FetchResult.LocalTarFile)
			if errors != nil && len(errors) > 0 {
				messageLog.Println("[WARNING]", "Errors cleaning up",
					result.FetchResult.LocalTarFile)
				for _, e := range errors {
					messageLog.Println("[ERROR]", e)
				}
			}
		}
		// Let our volumn tracker know we just freed up some disk space.
		volume.Release(uint64(result.S3File.Key.Size * 2))
		// Reduce outstanding task count.
		atomic.AddInt64(&taskCounter, -1)

		// Build and send message back to NSQ, indicating whether
		// processing succeeded.
		succeeded := true
		requeueDelayMs := 0
		if result.Error != nil {
			succeeded = false
			requeueDelayMs = 60000
		}
		finishedMessage := &nsq.FinishedMessage{
			result.NsqMessage.Id,
			requeueDelayMs,
			succeeded}
		result.NsqOutputChannel <- finishedMessage
		//cmd := nsq.Finish(result.NsqMessage.Id)
	}
}

// This prints to the log the result of the program's attempt to fetch,
// untar, unbag and verify an individual S3 tar file.
func logResult() {
	for result := range channels.ResultsChannel {
		json, err := json.Marshal(result)
		if err != nil {
			messageLog.Println("[ERROR]", err)
		}
		jsonLog.Println(string(json))
		atomic.AddInt64(&bytesInS3, int64(result.S3File.Key.Size))
		if(result.Error != nil) {
			atomic.AddInt64(&failed, 1)
			messageLog.Println("[ERROR]",
				result.S3File.BucketName,
				result.S3File.Key.Key,
				"->", result.Error)
		} else {
			atomic.AddInt64(&succeeded, 1)
			atomic.AddInt64(&bytesProcessed, int64(result.S3File.Key.Size))
			messageLog.Println("[INFO]", result.S3File.Key.Key, "-> finished OK")
		}
		channels.CleanUpChannel <- result
	}
}

// This fetches a file from S3 and stores it locally.
func Fetch(bucketName string, key s3.Key) (result *bagman.FetchResult) {
	client, err := bagman.GetClient(aws.USEast)
	if err != nil {
		fetchResult := new(bagman.FetchResult)
		fetchResult.Error = err
		return fetchResult
	}
	// TODO: We fetched this bucket before. Do we need to fetch it again?
	bucket := client.Bucket(bucketName)
	tarFilePath := filepath.Join(config.TarDirectory, key.Key)
	return bagman.FetchToFile(bucket, key, tarFilePath)
}

// This deletes the tar file and all of the files that were
// unpacked from it. Param file is the path the tar file.
func CleanUp(file string) (errors []error) {
	errors = make([]error, 0)
	err := os.Remove(file)
	if err != nil {
		errors = append(errors, err)
	}
	// TODO: Don't assume the untarred dir name is the same as
	// the tar file. We have its actual name in the TarResult.
	re := regexp.MustCompile("\\.tar$")
	untarredDir := re.ReplaceAllString(file, "")
	err = os.RemoveAll(untarredDir)
	if err != nil {
		messageLog.Printf("Error deleting dir %s: %s\n", untarredDir, err.Error())
		errors = append(errors, err)
	}
	return errors
}

// Runs tests on the bag file at path and returns information about
// whether it was successfully unpacked, valid and complete.
func ProcessBagFile(result *bagman.ProcessResult) {
	result.TarResult = bagman.Untar(result.FetchResult.LocalTarFile)
	if result.TarResult.Error != nil {
		result.Error = result.TarResult.Error
		// If we can't untar this, there's no reason to retry...
		// but we'll have to revisit this. There may be cases
		// where we do want to retry, such as if disk was full.
		result.Retry = false
	} else {
		result.BagReadResult = bagman.ReadBag(result.TarResult.OutputDir)
		if result.BagReadResult.Error != nil {
			result.Error = result.BagReadResult.Error
			// Something was wrong with this bag. Bad checksum,
			// missing file, etc. Don't reprocess it.
			result.Retry = false
		}
	}
}
<commit_msg>Removed comment, added TODO<commit_after>package main

import (
	"fmt"
	"flag"
	"encoding/json"
	"os"
	"regexp"
	"sync/atomic"
	"log"
	"time"
	"path/filepath"
	"github.com/APTrust/bagman"
	"launchpad.net/goamz/aws"
	"launchpad.net/goamz/s3"
	"github.com/bitly/go-nsq"
)

type Channels struct {
	FetchChannel     chan bagman.ProcessResult
	UnpackChannel    chan bagman.ProcessResult
	CleanUpChannel   chan bagman.ProcessResult
	ResultsChannel   chan bagman.ProcessResult
}

// Global vars.
var channels *Channels
var config bagman.Config
var jsonLog *log.Logger
var messageLog *log.Logger
var taskCounter = int64(0)
var volume *bagman.Volume
var succeeded = int64(0)
var failed = int64(0)
var bytesInS3 = int64(0)
var bytesProcessed = int64(0)

// bag_processor receives messages from nsqd describing
// items in the S3 receiving buckets. Each item/message
// follows this flow:
//
// 1. Fetch channel: fetches the file from S3.
// 2. Unpack channel: untars the bag files, parses and validates
//    the bag, reads tags, generates checksums and generic file
//    UUIDs.
// 3. **** TODO **** Copy files to S3 permanent storage.
// 4. Results channel: tells the queue whether processing
//    succeeded, and if not, whether the item should be requeued.
//    Also logs results to json and message logs.
// 5. Cleanup channe: cleans up the files after processing
//    completes.
//
// If a failure occurs anywhere in the first three steps,
// processing goes directly to the Results Channel, which
// records the error and the disposition (retry/give up).
//
// As long as the message from nsq contains valid JSON,
// steps 4 and 5 ALWAYS run.
//
// The bag processor has so many responsibilities because
// downloading, untarring and running checksums on
// multi-gigabyte files takes a lot of time. We want to
// avoid having separate processes repeatedly download and
// untar the files, so bag_processor performs all operations
// that require local access to the raw contents of the bags.
func main() {

	loadConfig()
	initVolume()
	initChannels()
	initGoRoutines(channels)

	reader, err := nsq.NewReader(config.BagProcessorTopic, config.BagProcessorChannel)
	if err != nil {
		messageLog.Fatalf(err.Error())
	}

	handler := &BagProcessor{}
	reader.SetMaxInFlight(100)
	reader.AddAsyncHandler(handler)
	reader.ConnectToLookupd(config.NsqLookupd)

	// This reader blocks until we get an interrupt, so our program does not exit.
	<-reader.ExitChan

	//waitForAllTasks()
}

func loadConfig() {
	// Load the config or die.
	requestedConfig := flag.String("config", "", "configuration to run")
	flag.Parse()
	config = bagman.LoadRequestedConfig(requestedConfig)
	jsonLog, messageLog = bagman.InitLoggers(config.LogDirectory, "bag_processor")
}

// Set up the volume to keep track of how much disk space is
// available. We want to avoid downloading large files when
// we know ahead of time that the volume containing the tar
// directory doesn't have enough space to accomodate them.
func initVolume() {
	var err error
	volume, err = bagman.NewVolume(config.TarDirectory)
	if err != nil {
		panic(err.Error())
	}
}

// Set up the channels. It's essential that that the fetchChannel
// be limited to a relatively low number. If we are downloading
// 1GB tar files, we need space to store the tar file AND the
// untarred version. That's about 2 x 1GB. We do not want to pull
// down 1000 files at once, or we'll run out of disk space!
// If config sets fetchers to 10, we can pull down 10 files at a
// time. The fetch queue could hold 10 * 4 = 40 items, so we'd
// have max 40 tar files + untarred directories on disk at once.
// The number of workers should be close to the number of CPU
// cores.
func initChannels() {
	fetcherBufferSize := config.Fetchers * 4
	workerBufferSize := config.Workers * 10

	channels = &Channels{}
	channels.FetchChannel = make(chan bagman.ProcessResult, fetcherBufferSize)
	channels.UnpackChannel = make(chan bagman.ProcessResult, workerBufferSize)
	channels.CleanUpChannel = make(chan bagman.ProcessResult, workerBufferSize)
	channels.ResultsChannel = make(chan bagman.ProcessResult, workerBufferSize)
}

// Set up our go routines. We do NOT want one go routine per
// S3 file. If we do that, the system will run out of file handles,
// as we'll have tens of thousands of open connections to S3
// trying to write data into tens of thousands of local files.
func initGoRoutines(channels *Channels) {
	for i := 0; i < config.Fetchers; i++ {
		go doFetch()
	}

	for i := 0; i < config.Workers; i++ {
		go doUnpack()
		go logResult()
		go doCleanUp()
	}
}

type BagProcessor struct {

}

// MessageHandler handles messages from the queue, putting each
// item into the pipleline.
func (*BagProcessor) HandleMessage(message *nsq.Message, outputChannel chan *nsq.FinishedMessage) {

	fmt.Println(string(message.Body))
	message.Attempts++
	atomic.AddInt64(&taskCounter, 1)

	var s3File bagman.S3File
	err := json.Unmarshal(message.Body, &s3File)
	if err != nil {
		messageLog.Println("[ERROR] Could not unmarshal JSON data from nsq:",
			string(message.Body))
		finishedMessage := &nsq.FinishedMessage{message.Id, 0, true}
		outputChannel <- finishedMessage
		return
	}

	// Create the result struct and pass it down the pipeline
	result := bagman.ProcessResult{
		message,
		outputChannel,
		&s3File,
		nil,
		nil,
		nil,
		nil,
		true}
	channels.FetchChannel <- result
	messageLog.Println("[INFO]", "Put", s3File.Key.Key, "into fetch queue")
}

// This function blocks until all tasks are complete.
// sync.WaitGroup is the standard way of doing this, but
// WaitGroup is really for counting go routines. We have only a handful
// of go routines, and a huge number of tasks. We're counting the tasks.
func waitForAllTasks() {
	for {
		if atomic.LoadInt64(&taskCounter) == 0 {
			break
		}
		time.Sleep(5 * time.Second)
	}
}

// This runs as a go routine to fetch files from S3.
func doFetch() {
	for result := range channels.FetchChannel {
		s3Key := result.S3File.Key
		// Disk needs filesize * 2 disk space to accomodate tar file & untarred files
		err := volume.Reserve(uint64(s3Key.Size * 2))
		if err != nil {
			// Not enough room on disk
			messageLog.Println("[WARNING]", "Requeueing",
				s3Key.Key, "- not enough disk space")
			result.Error = err
			result.Retry = true
			channels.ResultsChannel <- result
		} else {
			messageLog.Println("[INFO]", "Fetching", s3Key)
			fetchResult := Fetch(result.S3File.BucketName, s3Key)
			result.FetchResult = fetchResult
			result.Retry = fetchResult.Retry
			if fetchResult.Error != nil {
				// Fetch from S3 failed. Requeue.
				result.Error = fetchResult.Error
				channels.ResultsChannel <- result
			} else {
				// Got S3 file. Untar it.
				// And touch the message, so nsqd knows we're making progress.
				result.NsqMessage.Touch()
				channels.UnpackChannel <- result
			}
		}
	}
}

// This runs as a go routine to untar files downloaded from S3.
func doUnpack() {
	for result := range channels.UnpackChannel {
		if result.Error != nil {
			// Unpack failed. Go to end.
			messageLog.Println("[INFO]", "Nothing to unpack for",
				result.S3File.Key.Key)
			channels.ResultsChannel <- result
		} else {
			// Unpacked! Now process the bag and touch message
			// so nsqd knows we're making progress.
			messageLog.Println("[INFO]", "Unpacking", result.S3File.Key.Key)
			result.NsqMessage.Touch()
			ProcessBagFile(&result)
			channels.ResultsChannel <- result
		}
	}
}

// This runs as a go routine to remove the files we downloaded
// and untarred.
func doCleanUp() {
	for result := range channels.CleanUpChannel {
		messageLog.Println("[INFO]", "Cleaning up", result.S3File.Key.Key)
		if result.S3File.Key.Key != "" && result.FetchResult.LocalTarFile != "" {
			// Clean up any files we downloaded and unpacked
			errors := CleanUp(result.FetchResult.LocalTarFile)
			if errors != nil && len(errors) > 0 {
				messageLog.Println("[WARNING]", "Errors cleaning up",
					result.FetchResult.LocalTarFile)
				for _, e := range errors {
					messageLog.Println("[ERROR]", e)
				}
			}
		}
		// Let our volumn tracker know we just freed up some disk space.
		volume.Release(uint64(result.S3File.Key.Size * 2))
		// Reduce outstanding task count.
		atomic.AddInt64(&taskCounter, -1)

		// Build and send message back to NSQ, indicating whether
		// processing succeeded.
		succeeded := true
		requeueDelayMs := 0
		if result.Error != nil {
			succeeded = false
			requeueDelayMs = 60000
		}
		finishedMessage := &nsq.FinishedMessage{
			result.NsqMessage.Id,
			requeueDelayMs,
			succeeded}
		result.NsqOutputChannel <- finishedMessage

		// TODO: Send ProcessResult to nsq metadata topic
	}
}

// This prints to the log the result of the program's attempt to fetch,
// untar, unbag and verify an individual S3 tar file.
func logResult() {
	for result := range channels.ResultsChannel {
		json, err := json.Marshal(result)
		if err != nil {
			messageLog.Println("[ERROR]", err)
		}
		jsonLog.Println(string(json))
		atomic.AddInt64(&bytesInS3, int64(result.S3File.Key.Size))
		if(result.Error != nil) {
			atomic.AddInt64(&failed, 1)
			messageLog.Println("[ERROR]",
				result.S3File.BucketName,
				result.S3File.Key.Key,
				"->", result.Error)
		} else {
			atomic.AddInt64(&succeeded, 1)
			atomic.AddInt64(&bytesProcessed, int64(result.S3File.Key.Size))
			messageLog.Println("[INFO]", result.S3File.Key.Key, "-> finished OK")
		}
		channels.CleanUpChannel <- result
	}
}

// This fetches a file from S3 and stores it locally.
func Fetch(bucketName string, key s3.Key) (result *bagman.FetchResult) {
	client, err := bagman.GetClient(aws.USEast)
	if err != nil {
		fetchResult := new(bagman.FetchResult)
		fetchResult.Error = err
		return fetchResult
	}
	// TODO: We fetched this bucket before. Do we need to fetch it again?
	bucket := client.Bucket(bucketName)
	tarFilePath := filepath.Join(config.TarDirectory, key.Key)
	return bagman.FetchToFile(bucket, key, tarFilePath)
}

// This deletes the tar file and all of the files that were
// unpacked from it. Param file is the path the tar file.
func CleanUp(file string) (errors []error) {
	errors = make([]error, 0)
	err := os.Remove(file)
	if err != nil {
		errors = append(errors, err)
	}
	// TODO: Don't assume the untarred dir name is the same as
	// the tar file. We have its actual name in the TarResult.
	re := regexp.MustCompile("\\.tar$")
	untarredDir := re.ReplaceAllString(file, "")
	err = os.RemoveAll(untarredDir)
	if err != nil {
		messageLog.Printf("Error deleting dir %s: %s\n", untarredDir, err.Error())
		errors = append(errors, err)
	}
	return errors
}

// Runs tests on the bag file at path and returns information about
// whether it was successfully unpacked, valid and complete.
func ProcessBagFile(result *bagman.ProcessResult) {
	result.TarResult = bagman.Untar(result.FetchResult.LocalTarFile)
	if result.TarResult.Error != nil {
		result.Error = result.TarResult.Error
		// If we can't untar this, there's no reason to retry...
		// but we'll have to revisit this. There may be cases
		// where we do want to retry, such as if disk was full.
		result.Retry = false
	} else {
		result.BagReadResult = bagman.ReadBag(result.TarResult.OutputDir)
		if result.BagReadResult.Error != nil {
			result.Error = result.BagReadResult.Error
			// Something was wrong with this bag. Bad checksum,
			// missing file, etc. Don't reprocess it.
			result.Retry = false
		}
	}
}
<|endoftext|>


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

package linux

// Netlink message types for NETLINK_ROUTE sockets, from uapi/linux/rtnetlink.h.
const (
	RTM_NEWLINK = 16
	RTM_DELLINK = 17
	RTM_GETLINK = 18
	RTM_SETLINK = 19

	RTM_NEWADDR = 20
	RTM_DELADDR = 21
	RTM_GETADDR = 22

	RTM_NEWROUTE = 24
	RTM_DELROUTE = 25
	RTM_GETROUTE = 26

	RTM_NEWNEIGH = 28
	RTM_DELNEIGH = 29
	RTM_GETNEIGH = 30

	RTM_NEWRULE = 32
	RTM_DELRULE = 33
	RTM_GETRULE = 34

	RTM_NEWQDISC = 36
	RTM_DELQDISC = 37
	RTM_GETQDISC = 38

	RTM_NEWTCLASS = 40
	RTM_DELTCLASS = 41
	RTM_GETTCLASS = 42

	RTM_NEWTFILTER = 44
	RTM_DELTFILTER = 45
	RTM_GETTFILTER = 46

	RTM_NEWACTION = 48
	RTM_DELACTION = 49
	RTM_GETACTION = 50

	RTM_NEWPREFIX = 52

	RTM_GETMULTICAST = 58

	RTM_GETANYCAST = 62

	RTM_NEWNEIGHTBL = 64
	RTM_GETNEIGHTBL = 66
	RTM_SETNEIGHTBL = 67

	RTM_NEWNDUSEROPT = 68

	RTM_NEWADDRLABEL = 72
	RTM_DELADDRLABEL = 73
	RTM_GETADDRLABEL = 74

	RTM_GETDCB = 78
	RTM_SETDCB = 79

	RTM_NEWNETCONF = 80
	RTM_GETNETCONF = 82

	RTM_NEWMDB = 84
	RTM_DELMDB = 85
	RTM_GETMDB = 86

	RTM_NEWNSID = 88
	RTM_DELNSID = 89
	RTM_GETNSID = 90
)

// InterfaceInfoMessage is struct ifinfomsg, from uapi/linux/rtnetlink.h.
type InterfaceInfoMessage struct {
	Family uint8
	_      uint8
	Type   uint16
	Index  int32
	Flags  uint32
	Change uint32
}

// Interface flags, from uapi/linux/if.h.
const (
	IFF_UP          = 1 << 0
	IFF_BROADCAST   = 1 << 1
	IFF_DEBUG       = 1 << 2
	IFF_LOOPBACK    = 1 << 3
	IFF_POINTOPOINT = 1 << 4
	IFF_NOTRAILERS  = 1 << 5
	IFF_RUNNING     = 1 << 6
	IFF_NOARP       = 1 << 7
	IFF_PROMISC     = 1 << 8
	IFF_ALLMULTI    = 1 << 9
	IFF_MASTER      = 1 << 10
	IFF_SLAVE       = 1 << 11
	IFF_MULTICAST   = 1 << 12
	IFF_PORTSEL     = 1 << 13
	IFF_AUTOMEDIA   = 1 << 14
	IFF_DYNAMIC     = 1 << 15
	IFF_LOWER_UP    = 1 << 16
	IFF_DORMANT     = 1 << 17
	IFF_ECHO        = 1 << 18
)

// Interface link attributes, from uapi/linux/if_link.h.
const (
	IFLA_UNSPEC          = 0
	IFLA_ADDRESS         = 1
	IFLA_BROADCAST       = 2
	IFLA_IFNAME          = 3
	IFLA_MTU             = 4
	IFLA_LINK            = 5
	IFLA_QDISC           = 6
	IFLA_STATS           = 7
	IFLA_COST            = 8
	IFLA_PRIORITY        = 9
	IFLA_MASTER          = 10
	IFLA_WIRELESS        = 11
	IFLA_PROTINFO        = 12
	IFLA_TXQLEN          = 13
	IFLA_MAP             = 14
	IFLA_WEIGHT          = 15
	IFLA_OPERSTATE       = 16
	IFLA_LINKMODE        = 17
	IFLA_LINKINFO        = 18
	IFLA_NET_NS_PID      = 19
	IFLA_IFALIAS         = 20
	IFLA_NUM_VF          = 21
	IFLA_VFINFO_LIST     = 22
	IFLA_STATS64         = 23
	IFLA_VF_PORTS        = 24
	IFLA_PORT_SELF       = 25
	IFLA_AF_SPEC         = 26
	IFLA_GROUP           = 27
	IFLA_NET_NS_FD       = 28
	IFLA_EXT_MASK        = 29
	IFLA_PROMISCUITY     = 30
	IFLA_NUM_TX_QUEUES   = 31
	IFLA_NUM_RX_QUEUES   = 32
	IFLA_CARRIER         = 33
	IFLA_PHYS_PORT_ID    = 34
	IFLA_CARRIER_CHANGES = 35
	IFLA_PHYS_SWITCH_ID  = 36
	IFLA_LINK_NETNSID    = 37
	IFLA_PHYS_PORT_NAME  = 38
	IFLA_PROTO_DOWN      = 39
	IFLA_GSO_MAX_SEGS    = 40
	IFLA_GSO_MAX_SIZE    = 41
)

// InterfaceAddrMessage is struct ifaddrmsg, from uapi/linux/if_addr.h.
type InterfaceAddrMessage struct {
	Family    uint8
	PrefixLen uint8
	Flags     uint8
	Scope     uint8
	Index     uint32
}

// Interface attributes, from uapi/linux/if_addr.h.
const (
	IFA_UNSPEC    = 0
	IFA_ADDRESS   = 1
	IFA_LOCAL     = 2
	IFA_LABEL     = 3
	IFA_BROADCAST = 4
	IFA_ANYCAST   = 5
	IFA_CACHEINFO = 6
	IFA_MULTICAST = 7
	IFA_FLAGS     = 8
)

// Device types, from uapi/linux/if_arp.h.
const (
	ARPHRD_LOOPBACK = 772
)

// RouteMessage struct rtmsg, from uapi/linux/rtnetlink.h.
type RouteMessage struct {
	Family uint8
	DstLen uint8
	SrcLen uint8
	TOS    uint8

	Table    uint8
	Protocol uint8
	Scope    uint8
	Type     uint8

	Flags uint32
}

// Route types, from uapi/linux/rtnetlink.h.
const (
	// RTN_UNSPEC represents an unspecified route type.
	RTN_UNSPEC = 0

	// RTN_UNICAST represents a unicast route.
	RTN_UNICAST = 1

	// RTN_LOCAL represents a route that is accepted locally.
	RTN_LOCAL = 2

	// RTN_BROADCAST represents a broadcast route (Traffic is accepted locally
	// as broadcast, and sent as broadcast).
	RTN_BROADCAST = 3

	// RTN_ANYCAST represents a anycast route (Traffic is accepted locally as
	// broadcast but sent as unicast).
	RTN_ANYCAST = 6

	// RTN_MULTICAST represents a multicast route.
	RTN_MULTICAST = 5

	// RTN_BLACKHOLE represents a route where all traffic is dropped.
	RTN_BLACKHOLE = 6

	// RTN_UNREACHABLE represents a route where the destination is unreachable.
	RTN_UNREACHABLE = 7

	RTN_PROHIBIT = 8
	RTN_THROW    = 9
	RTN_NAT      = 10
	RTN_XRESOLVE = 11
)

// Route protocols/origins, from uapi/linux/rtnetlink.h.
const (
	RTPROT_UNSPEC   = 0
	RTPROT_REDIRECT = 1
	RTPROT_KERNEL   = 2
	RTPROT_BOOT     = 3
	RTPROT_STATIC   = 4
	RTPROT_GATED    = 8
	RTPROT_RA       = 9
	RTPROT_MRT      = 10
	RTPROT_ZEBRA    = 11
	RTPROT_BIRD     = 12
	RTPROT_DNROUTED = 13
	RTPROT_XORP     = 14
	RTPROT_NTK      = 15
	RTPROT_DHCP     = 16
	RTPROT_MROUTED  = 17
	RTPROT_BABEL    = 42
	RTPROT_BGP      = 186
	RTPROT_ISIS     = 187
	RTPROT_OSPF     = 188
	RTPROT_RIP      = 189
	RTPROT_EIGRP    = 192
)

// Route scopes, from uapi/linux/rtnetlink.h.
const (
	RT_SCOPE_UNIVERSE = 0
	RT_SCOPE_SITE     = 200
	RT_SCOPE_LINK     = 253
	RT_SCOPE_HOST     = 254
	RT_SCOPE_NOWHERE  = 255
)

// Route flags, from uapi/linux/rtnetlink.h.
const (
	RTM_F_NOTIFY       = 0x100
	RTM_F_CLONED       = 0x200
	RTM_F_EQUALIZE     = 0x400
	RTM_F_PREFIX       = 0x800
	RTM_F_LOOKUP_TABLE = 0x1000
	RTM_F_FIB_MATCH    = 0x2000
)

// Route tables, from uapi/linux/rtnetlink.h.
const (
	RT_TABLE_UNSPEC  = 0
	RT_TABLE_COMPAT  = 252
	RT_TABLE_DEFAULT = 253
	RT_TABLE_MAIN    = 254
	RT_TABLE_LOCAL   = 255
)

// Route attributes, from uapi/linux/rtnetlink.h.
const (
	RTA_UNSPEC        = 0
	RTA_DST           = 1
	RTA_SRC           = 2
	RTA_IIF           = 3
	RTA_OIF           = 4
	RTA_GATEWAY       = 5
	RTA_PRIORITY      = 6
	RTA_PREFSRC       = 7
	RTA_METRICS       = 8
	RTA_MULTIPATH     = 9
	RTA_PROTOINFO     = 10
	RTA_FLOW          = 11
	RTA_CACHEINFO     = 12
	RTA_SESSION       = 13
	RTA_MP_ALGO       = 14
	RTA_TABLE         = 15
	RTA_MARK          = 16
	RTA_MFC_STATS     = 17
	RTA_VIA           = 18
	RTA_NEWDST        = 19
	RTA_PREF          = 20
	RTA_ENCAP_TYPE    = 21
	RTA_ENCAP         = 22
	RTA_EXPIRES       = 23
	RTA_PAD           = 24
	RTA_UID           = 25
	RTA_TTL_PROPAGATE = 26
	RTA_IP_PROTO      = 27
	RTA_SPORT         = 28
	RTA_DPORT         = 29
)

// Route flags, from include/uapi/linux/route.h.
const (
	RTF_GATEWAY = 0x2
	RTF_UP      = 0x1
)
<commit_msg>Add missing verb<commit_after>// Copyright 2018 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package linux

// Netlink message types for NETLINK_ROUTE sockets, from uapi/linux/rtnetlink.h.
const (
	RTM_NEWLINK = 16
	RTM_DELLINK = 17
	RTM_GETLINK = 18
	RTM_SETLINK = 19

	RTM_NEWADDR = 20
	RTM_DELADDR = 21
	RTM_GETADDR = 22

	RTM_NEWROUTE = 24
	RTM_DELROUTE = 25
	RTM_GETROUTE = 26

	RTM_NEWNEIGH = 28
	RTM_DELNEIGH = 29
	RTM_GETNEIGH = 30

	RTM_NEWRULE = 32
	RTM_DELRULE = 33
	RTM_GETRULE = 34

	RTM_NEWQDISC = 36
	RTM_DELQDISC = 37
	RTM_GETQDISC = 38

	RTM_NEWTCLASS = 40
	RTM_DELTCLASS = 41
	RTM_GETTCLASS = 42

	RTM_NEWTFILTER = 44
	RTM_DELTFILTER = 45
	RTM_GETTFILTER = 46

	RTM_NEWACTION = 48
	RTM_DELACTION = 49
	RTM_GETACTION = 50

	RTM_NEWPREFIX = 52

	RTM_GETMULTICAST = 58

	RTM_GETANYCAST = 62

	RTM_NEWNEIGHTBL = 64
	RTM_GETNEIGHTBL = 66
	RTM_SETNEIGHTBL = 67

	RTM_NEWNDUSEROPT = 68

	RTM_NEWADDRLABEL = 72
	RTM_DELADDRLABEL = 73
	RTM_GETADDRLABEL = 74

	RTM_GETDCB = 78
	RTM_SETDCB = 79

	RTM_NEWNETCONF = 80
	RTM_GETNETCONF = 82

	RTM_NEWMDB = 84
	RTM_DELMDB = 85
	RTM_GETMDB = 86

	RTM_NEWNSID = 88
	RTM_DELNSID = 89
	RTM_GETNSID = 90
)

// InterfaceInfoMessage is struct ifinfomsg, from uapi/linux/rtnetlink.h.
type InterfaceInfoMessage struct {
	Family uint8
	_      uint8
	Type   uint16
	Index  int32
	Flags  uint32
	Change uint32
}

// Interface flags, from uapi/linux/if.h.
const (
	IFF_UP          = 1 << 0
	IFF_BROADCAST   = 1 << 1
	IFF_DEBUG       = 1 << 2
	IFF_LOOPBACK    = 1 << 3
	IFF_POINTOPOINT = 1 << 4
	IFF_NOTRAILERS  = 1 << 5
	IFF_RUNNING     = 1 << 6
	IFF_NOARP       = 1 << 7
	IFF_PROMISC     = 1 << 8
	IFF_ALLMULTI    = 1 << 9
	IFF_MASTER      = 1 << 10
	IFF_SLAVE       = 1 << 11
	IFF_MULTICAST   = 1 << 12
	IFF_PORTSEL     = 1 << 13
	IFF_AUTOMEDIA   = 1 << 14
	IFF_DYNAMIC     = 1 << 15
	IFF_LOWER_UP    = 1 << 16
	IFF_DORMANT     = 1 << 17
	IFF_ECHO        = 1 << 18
)

// Interface link attributes, from uapi/linux/if_link.h.
const (
	IFLA_UNSPEC          = 0
	IFLA_ADDRESS         = 1
	IFLA_BROADCAST       = 2
	IFLA_IFNAME          = 3
	IFLA_MTU             = 4
	IFLA_LINK            = 5
	IFLA_QDISC           = 6
	IFLA_STATS           = 7
	IFLA_COST            = 8
	IFLA_PRIORITY        = 9
	IFLA_MASTER          = 10
	IFLA_WIRELESS        = 11
	IFLA_PROTINFO        = 12
	IFLA_TXQLEN          = 13
	IFLA_MAP             = 14
	IFLA_WEIGHT          = 15
	IFLA_OPERSTATE       = 16
	IFLA_LINKMODE        = 17
	IFLA_LINKINFO        = 18
	IFLA_NET_NS_PID      = 19
	IFLA_IFALIAS         = 20
	IFLA_NUM_VF          = 21
	IFLA_VFINFO_LIST     = 22
	IFLA_STATS64         = 23
	IFLA_VF_PORTS        = 24
	IFLA_PORT_SELF       = 25
	IFLA_AF_SPEC         = 26
	IFLA_GROUP           = 27
	IFLA_NET_NS_FD       = 28
	IFLA_EXT_MASK        = 29
	IFLA_PROMISCUITY     = 30
	IFLA_NUM_TX_QUEUES   = 31
	IFLA_NUM_RX_QUEUES   = 32
	IFLA_CARRIER         = 33
	IFLA_PHYS_PORT_ID    = 34
	IFLA_CARRIER_CHANGES = 35
	IFLA_PHYS_SWITCH_ID  = 36
	IFLA_LINK_NETNSID    = 37
	IFLA_PHYS_PORT_NAME  = 38
	IFLA_PROTO_DOWN      = 39
	IFLA_GSO_MAX_SEGS    = 40
	IFLA_GSO_MAX_SIZE    = 41
)

// InterfaceAddrMessage is struct ifaddrmsg, from uapi/linux/if_addr.h.
type InterfaceAddrMessage struct {
	Family    uint8
	PrefixLen uint8
	Flags     uint8
	Scope     uint8
	Index     uint32
}

// Interface attributes, from uapi/linux/if_addr.h.
const (
	IFA_UNSPEC    = 0
	IFA_ADDRESS   = 1
	IFA_LOCAL     = 2
	IFA_LABEL     = 3
	IFA_BROADCAST = 4
	IFA_ANYCAST   = 5
	IFA_CACHEINFO = 6
	IFA_MULTICAST = 7
	IFA_FLAGS     = 8
)

// Device types, from uapi/linux/if_arp.h.
const (
	ARPHRD_LOOPBACK = 772
)

// RouteMessage is struct rtmsg, from uapi/linux/rtnetlink.h.
type RouteMessage struct {
	Family uint8
	DstLen uint8
	SrcLen uint8
	TOS    uint8

	Table    uint8
	Protocol uint8
	Scope    uint8
	Type     uint8

	Flags uint32
}

// Route types, from uapi/linux/rtnetlink.h.
const (
	// RTN_UNSPEC represents an unspecified route type.
	RTN_UNSPEC = 0

	// RTN_UNICAST represents a unicast route.
	RTN_UNICAST = 1

	// RTN_LOCAL represents a route that is accepted locally.
	RTN_LOCAL = 2

	// RTN_BROADCAST represents a broadcast route (Traffic is accepted locally
	// as broadcast, and sent as broadcast).
	RTN_BROADCAST = 3

	// RTN_ANYCAST represents a anycast route (Traffic is accepted locally as
	// broadcast but sent as unicast).
	RTN_ANYCAST = 6

	// RTN_MULTICAST represents a multicast route.
	RTN_MULTICAST = 5

	// RTN_BLACKHOLE represents a route where all traffic is dropped.
	RTN_BLACKHOLE = 6

	// RTN_UNREACHABLE represents a route where the destination is unreachable.
	RTN_UNREACHABLE = 7

	RTN_PROHIBIT = 8
	RTN_THROW    = 9
	RTN_NAT      = 10
	RTN_XRESOLVE = 11
)

// Route protocols/origins, from uapi/linux/rtnetlink.h.
const (
	RTPROT_UNSPEC   = 0
	RTPROT_REDIRECT = 1
	RTPROT_KERNEL   = 2
	RTPROT_BOOT     = 3
	RTPROT_STATIC   = 4
	RTPROT_GATED    = 8
	RTPROT_RA       = 9
	RTPROT_MRT      = 10
	RTPROT_ZEBRA    = 11
	RTPROT_BIRD     = 12
	RTPROT_DNROUTED = 13
	RTPROT_XORP     = 14
	RTPROT_NTK      = 15
	RTPROT_DHCP     = 16
	RTPROT_MROUTED  = 17
	RTPROT_BABEL    = 42
	RTPROT_BGP      = 186
	RTPROT_ISIS     = 187
	RTPROT_OSPF     = 188
	RTPROT_RIP      = 189
	RTPROT_EIGRP    = 192
)

// Route scopes, from uapi/linux/rtnetlink.h.
const (
	RT_SCOPE_UNIVERSE = 0
	RT_SCOPE_SITE     = 200
	RT_SCOPE_LINK     = 253
	RT_SCOPE_HOST     = 254
	RT_SCOPE_NOWHERE  = 255
)

// Route flags, from uapi/linux/rtnetlink.h.
const (
	RTM_F_NOTIFY       = 0x100
	RTM_F_CLONED       = 0x200
	RTM_F_EQUALIZE     = 0x400
	RTM_F_PREFIX       = 0x800
	RTM_F_LOOKUP_TABLE = 0x1000
	RTM_F_FIB_MATCH    = 0x2000
)

// Route tables, from uapi/linux/rtnetlink.h.
const (
	RT_TABLE_UNSPEC  = 0
	RT_TABLE_COMPAT  = 252
	RT_TABLE_DEFAULT = 253
	RT_TABLE_MAIN    = 254
	RT_TABLE_LOCAL   = 255
)

// Route attributes, from uapi/linux/rtnetlink.h.
const (
	RTA_UNSPEC        = 0
	RTA_DST           = 1
	RTA_SRC           = 2
	RTA_IIF           = 3
	RTA_OIF           = 4
	RTA_GATEWAY       = 5
	RTA_PRIORITY      = 6
	RTA_PREFSRC       = 7
	RTA_METRICS       = 8
	RTA_MULTIPATH     = 9
	RTA_PROTOINFO     = 10
	RTA_FLOW          = 11
	RTA_CACHEINFO     = 12
	RTA_SESSION       = 13
	RTA_MP_ALGO       = 14
	RTA_TABLE         = 15
	RTA_MARK          = 16
	RTA_MFC_STATS     = 17
	RTA_VIA           = 18
	RTA_NEWDST        = 19
	RTA_PREF          = 20
	RTA_ENCAP_TYPE    = 21
	RTA_ENCAP         = 22
	RTA_EXPIRES       = 23
	RTA_PAD           = 24
	RTA_UID           = 25
	RTA_TTL_PROPAGATE = 26
	RTA_IP_PROTO      = 27
	RTA_SPORT         = 28
	RTA_DPORT         = 29
)

// Route flags, from include/uapi/linux/route.h.
const (
	RTF_GATEWAY = 0x2
	RTF_UP      = 0x1
)
<|endoftext|>


<commit_before>package jiraui

import (
	"fmt"

	ui "github.com/gizak/termui"
)

type Query struct {
	Name     string
	JQL      string
	Template string
}

type QueryPage struct {
	BaseListPage
	CommandBarFragment
	StatusBarFragment
	cachedResults []Query
}

var baseQueries = []Query{
	Query{"My Assigned Tickets", "assignee = currentUser() AND resolution = Unresolved", ""},
	Query{"My Reported Tickets", "reporter = currentUser() AND resolution = Unresolved", ""},
	Query{"My Watched Tickets", "watcher = currentUser() AND resolution = Unresolved", ""},
	Query{"My Voted Tickets", "voter = currentUser() AND resolution = Unresolved", ""},
	Query{"---", "", ""}, // no-op line in UI
}

func getQueries() (queries []Query) {
	opts := getJiraOpts()
	if q := opts["queries"]; q != nil {
		qList := q.([]interface{})
		for _, v := range qList {
			q1 := v.(map[interface{}]interface{})
			q2 := make(map[string]string)
			for k, v := range q1 {
				switch k := k.(type) {
				case string:
					switch v := v.(type) {
					case string:
						q2[k] = v
					}
				}
			}
			queries = append(queries, Query{q2["name"], q2["jql"], q2["template"]})
		}
	}
	return append(baseQueries, queries...)
}

func (p *QueryPage) Search() {
	s := p.ActiveSearch
	log.Debugf("QueryPage: search! %q", s.command)
	n := len(p.cachedResults)
	if s.command == "" {
		return
	}
	increment := 1
	if s.directionUp {
		increment = -1
	}
	// we use modulo here so we can loop through every line.
	// adding 'n' means we never have '-1 % n'.
	startLine := (p.uiList.Cursor + n + increment) % n
	for i := startLine; i != p.uiList.Cursor; i = (i + increment + n) % n {
		if s.re.MatchString(p.cachedResults[i].Name) {
			log.Debugf("Match found, line %d", i)
			p.uiList.SetCursorLine(i)
			p.Update()
			break
		}
	}
}

func (p *QueryPage) IsPopulated() bool {
	if len(p.cachedResults) > 0 {
		return true
	} else {
		return false
	}
}

func (p *QueryPage) itemizeResults() []string {
	items := make([]string, len(p.cachedResults))
	for i, v := range p.cachedResults {
		items[i] = fmt.Sprintf("%-50s [|](fg-blue) [%s](fg-green)", v.Name, v.JQL)
	}
	return items
}

func (p *QueryPage) PreviousPara() {
	newDisplayLine := 0
	sl := p.uiList.Cursor
	if sl == 0 {
		return
	}
	for i := sl - 1; i > 0; i-- {
		if p.cachedResults[i].JQL == "" {
			newDisplayLine = i
			break
		}
	}
	p.PreviousLine(sl - newDisplayLine)
}

func (p *QueryPage) NextPara() {
	newDisplayLine := len(p.cachedResults) - 1
	sl := p.uiList.Cursor
	if sl == newDisplayLine {
		return
	}
	for i := sl + 1; i < len(p.cachedResults); i++ {
		if p.cachedResults[i].JQL == "" {
			newDisplayLine = i
			break
		}
	}
	p.NextLine(newDisplayLine - sl)
}

func (p *QueryPage) SelectedQuery() Query {
	return p.cachedResults[p.uiList.Cursor]
}

func (p *QueryPage) SelectItem() {
	if p.SelectedQuery().JQL == "" {
		return
	}
	q := new(TicketListPage)
	q.ActiveQuery = p.SelectedQuery()
	previousPages = append(previousPages, currentPage)
	currentPage = q
	changePage()
}

func (p *QueryPage) Update() {
	ls := p.uiList
	log.Debugf("QueryPage.Update(): self:        %s (%p), ls: (%p)", p.Id(), p, ls)
	ui.Render(ls)
	p.statusBar.Update()
	p.commandBar.Update()
}

func (p *QueryPage) Refresh() {
	pDeref := &p
	q := *pDeref
	q.cachedResults = make([]Query, 0)
	changePage()
	q.Create()
}

func (p *QueryPage) Create() {
	log.Debugf("QueryPage.Create(): self:        %s (%p)", p.Id(), p)
	log.Debugf("QueryPage.Create(): currentPage: %s (%p)", currentPage.Id(), currentPage)
	ui.Clear()
	if p.uiList == nil {
		p.uiList = NewScrollableList()
	}
	if p.statusBar == nil {
		p.statusBar = new(StatusBar)
	}
	if p.commandBar == nil {
		p.commandBar = commandBar
	}
	if p.statusBar == nil {
		p.statusBar = new(StatusBar)
	}
	if p.commandBar == nil {
		p.commandBar = commandBar
	}
	p.cachedResults = getQueries()
	p.uiList.Items = p.itemizeResults()
	p.uiList.ItemFgColor = ui.ColorYellow
	p.uiList.BorderLabel = "Queries"
	p.uiList.Height = ui.TermHeight() - 2
	p.uiList.Width = ui.TermWidth()
	p.uiList.Y = 0
	p.statusBar.Create()
	p.commandBar.Create()
	p.Update()
}
<commit_msg>[#26] sort custom queries higher in main query selection page<commit_after>package jiraui

import (
	"fmt"

	ui "github.com/gizak/termui"
)

type Query struct {
	Name     string
	JQL      string
	Template string
}

type QueryPage struct {
	BaseListPage
	CommandBarFragment
	StatusBarFragment
	cachedResults []Query
}

var baseQueries = []Query{
	Query{"My Assigned Tickets", "assignee = currentUser() AND resolution = Unresolved", ""},
	Query{"My Reported Tickets", "reporter = currentUser() AND resolution = Unresolved", ""},
	Query{"My Watched Tickets", "watcher = currentUser() AND resolution = Unresolved", ""},
	Query{"My Voted Tickets", "voter = currentUser() AND resolution = Unresolved", ""},
}

func getQueries() (queries []Query) {
	opts := getJiraOpts()
	if q := opts["queries"]; q != nil {
		qList := q.([]interface{})
		for _, v := range qList {
			q1 := v.(map[interface{}]interface{})
			q2 := make(map[string]string)
			for k, v := range q1 {
				switch k := k.(type) {
				case string:
					switch v := v.(type) {
					case string:
						q2[k] = v
					}
				}
			}
			queries = append(queries, Query{q2["name"], q2["jql"], q2["template"]})
		}
	}
	if len(queries) > 0 {
		queries = append(
			queries,
			Query{"---", "", ""}, // no-op line in UI
		)
		return append(
			queries,
			baseQueries...
		);
	}
	return baseQueries
}

func (p *QueryPage) Search() {
	s := p.ActiveSearch
	log.Debugf("QueryPage: search! %q", s.command)
	n := len(p.cachedResults)
	if s.command == "" {
		return
	}
	increment := 1
	if s.directionUp {
		increment = -1
	}
	// we use modulo here so we can loop through every line.
	// adding 'n' means we never have '-1 % n'.
	startLine := (p.uiList.Cursor + n + increment) % n
	for i := startLine; i != p.uiList.Cursor; i = (i + increment + n) % n {
		if s.re.MatchString(p.cachedResults[i].Name) {
			log.Debugf("Match found, line %d", i)
			p.uiList.SetCursorLine(i)
			p.Update()
			break
		}
	}
}

func (p *QueryPage) IsPopulated() bool {
	if len(p.cachedResults) > 0 {
		return true
	} else {
		return false
	}
}

func (p *QueryPage) itemizeResults() []string {
	items := make([]string, len(p.cachedResults))
	for i, v := range p.cachedResults {
		items[i] = fmt.Sprintf("%-50s [|](fg-blue) [%s](fg-green)", v.Name, v.JQL)
	}
	return items
}

func (p *QueryPage) PreviousPara() {
	newDisplayLine := 0
	sl := p.uiList.Cursor
	if sl == 0 {
		return
	}
	for i := sl - 1; i > 0; i-- {
		if p.cachedResults[i].JQL == "" {
			newDisplayLine = i
			break
		}
	}
	p.PreviousLine(sl - newDisplayLine)
}

func (p *QueryPage) NextPara() {
	newDisplayLine := len(p.cachedResults) - 1
	sl := p.uiList.Cursor
	if sl == newDisplayLine {
		return
	}
	for i := sl + 1; i < len(p.cachedResults); i++ {
		if p.cachedResults[i].JQL == "" {
			newDisplayLine = i
			break
		}
	}
	p.NextLine(newDisplayLine - sl)
}

func (p *QueryPage) SelectedQuery() Query {
	return p.cachedResults[p.uiList.Cursor]
}

func (p *QueryPage) SelectItem() {
	if p.SelectedQuery().JQL == "" {
		return
	}
	q := new(TicketListPage)
	q.ActiveQuery = p.SelectedQuery()
	previousPages = append(previousPages, currentPage)
	currentPage = q
	changePage()
}

func (p *QueryPage) Update() {
	ls := p.uiList
	log.Debugf("QueryPage.Update(): self:        %s (%p), ls: (%p)", p.Id(), p, ls)
	ui.Render(ls)
	p.statusBar.Update()
	p.commandBar.Update()
}

func (p *QueryPage) Refresh() {
	pDeref := &p
	q := *pDeref
	q.cachedResults = make([]Query, 0)
	changePage()
	q.Create()
}

func (p *QueryPage) Create() {
	log.Debugf("QueryPage.Create(): self:        %s (%p)", p.Id(), p)
	log.Debugf("QueryPage.Create(): currentPage: %s (%p)", currentPage.Id(), currentPage)
	ui.Clear()
	if p.uiList == nil {
		p.uiList = NewScrollableList()
	}
	if p.statusBar == nil {
		p.statusBar = new(StatusBar)
	}
	if p.commandBar == nil {
		p.commandBar = commandBar
	}
	if p.statusBar == nil {
		p.statusBar = new(StatusBar)
	}
	if p.commandBar == nil {
		p.commandBar = commandBar
	}
	p.cachedResults = getQueries()
	p.uiList.Items = p.itemizeResults()
	p.uiList.ItemFgColor = ui.ColorYellow
	p.uiList.BorderLabel = "Queries"
	p.uiList.Height = ui.TermHeight() - 2
	p.uiList.Width = ui.TermWidth()
	p.uiList.Y = 0
	p.statusBar.Create()
	p.commandBar.Create()
	p.Update()
}
<|endoftext|>


<commit_before>package fs

import (
	"context"
	"os"
	"path/filepath"
	"syscall"

	"github.com/gopasspw/gopass/pkg/ctxutil"
	"github.com/gopasspw/gopass/pkg/fsutil"
	"github.com/gopasspw/gopass/pkg/out"
)

// Fsck checks the storage integrity
func (s *Store) Fsck(ctx context.Context) error {
	pcb := ctxutil.GetProgressCallback(ctx)

	entries, err := s.List(ctx, "")
	if err != nil {
		return err
	}
	dirs := make(map[string]struct{}, len(entries))
	for _, entry := range entries {
		pcb()
		filename := filepath.Join(s.path, entry)
		dirs[filepath.Dir(filename)] = struct{}{}

		if err := s.fsckCheckFile(ctx, filename); err != nil {
			return err
		}
	}

	for dir := range dirs {
		if err := s.fsckCheckDir(ctx, dir); err != nil {
			return err
		}
	}
	return nil
}

func (s *Store) fsckCheckFile(ctx context.Context, filename string) error {
	fi, err := os.Stat(filename)
	if err != nil {
		return err
	}

	if fi.Mode().Perm()&0177 == 0 {
		return nil
	}

	out.Yellow(ctx, "Permissions too wide: %s (%s)", filename, fi.Mode().String())

	np := uint32(fi.Mode().Perm() & 0600)
	out.Green(ctx, "  Fixing permissions from %s to %s", fi.Mode().Perm().String(), os.FileMode(np).Perm().String())
	if err := syscall.Chmod(filename, np); err != nil {
		out.Error(ctx, "  Failed to set permissions for %s to rw-------: %s", filename, err)
	}
	return nil
}

func (s *Store) fsckCheckDir(ctx context.Context, dirname string) error {
	fi, err := os.Stat(dirname)
	if err != nil {
		return err
	}

	// check if any group or other perms are set,
	// i.e. check for perms other than rwx------
	if fi.Mode().Perm()&077 != 0 {
		out.Yellow(ctx, "Permissions too wide %s on dir %s", fi.Mode().Perm().String(), dirname)

		np := uint32(fi.Mode().Perm() & 0700)
		out.Green(ctx, "  Fixing permissions from %s to %s", fi.Mode().Perm().String(), os.FileMode(np).Perm().String())
		if err := syscall.Chmod(dirname, np); err != nil {
			out.Error(ctx, "  Failed to set permissions for %s to rwx------: %s", dirname, err)
		}
	}

	// check for empty folders
	isEmpty, err := fsutil.IsEmptyDir(dirname)
	if err != nil {
		return err
	}
	if isEmpty {
		out.Error(ctx, "Folder %s is empty. Removing", dirname)
		return os.Remove(dirname)
	}
	return nil
}
<commit_msg>Add debug log to file fsck (#949)<commit_after>package fs

import (
	"context"
	"os"
	"path/filepath"
	"syscall"

	"github.com/gopasspw/gopass/pkg/ctxutil"
	"github.com/gopasspw/gopass/pkg/fsutil"
	"github.com/gopasspw/gopass/pkg/out"
)

// Fsck checks the storage integrity
func (s *Store) Fsck(ctx context.Context) error {
	pcb := ctxutil.GetProgressCallback(ctx)

	entries, err := s.List(ctx, "")
	if err != nil {
		return err
	}
	dirs := make(map[string]struct{}, len(entries))
	for _, entry := range entries {
		pcb()
		out.Debug(ctx, "file.Fsck() - Checking %s", entry)

		filename := filepath.Join(s.path, entry)
		dirs[filepath.Dir(filename)] = struct{}{}

		if err := s.fsckCheckFile(ctx, filename); err != nil {
			return err
		}
	}

	for dir := range dirs {
		if err := s.fsckCheckDir(ctx, dir); err != nil {
			return err
		}
	}
	return nil
}

func (s *Store) fsckCheckFile(ctx context.Context, filename string) error {
	fi, err := os.Stat(filename)
	if err != nil {
		return err
	}

	if fi.Mode().Perm()&0177 == 0 {
		return nil
	}

	out.Yellow(ctx, "Permissions too wide: %s (%s)", filename, fi.Mode().String())

	np := uint32(fi.Mode().Perm() & 0600)
	out.Green(ctx, "  Fixing permissions from %s to %s", fi.Mode().Perm().String(), os.FileMode(np).Perm().String())
	if err := syscall.Chmod(filename, np); err != nil {
		out.Error(ctx, "  Failed to set permissions for %s to rw-------: %s", filename, err)
	}
	return nil
}

func (s *Store) fsckCheckDir(ctx context.Context, dirname string) error {
	fi, err := os.Stat(dirname)
	if err != nil {
		return err
	}

	// check if any group or other perms are set,
	// i.e. check for perms other than rwx------
	if fi.Mode().Perm()&077 != 0 {
		out.Yellow(ctx, "Permissions too wide %s on dir %s", fi.Mode().Perm().String(), dirname)

		np := uint32(fi.Mode().Perm() & 0700)
		out.Green(ctx, "  Fixing permissions from %s to %s", fi.Mode().Perm().String(), os.FileMode(np).Perm().String())
		if err := syscall.Chmod(dirname, np); err != nil {
			out.Error(ctx, "  Failed to set permissions for %s to rwx------: %s", dirname, err)
		}
	}

	// check for empty folders
	isEmpty, err := fsutil.IsEmptyDir(dirname)
	if err != nil {
		return err
	}
	if isEmpty {
		out.Error(ctx, "Folder %s is empty. Removing", dirname)
		return os.Remove(dirname)
	}
	return nil
}
<|endoftext|>


<commit_before>package main

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

func main() {
	c := make(chan result, len(os.Args[1:]))
	for _, arg := range os.Args[1:] {
		go func(url string) { c <- get(url) }(arg)
	}
	for i := 0; i < cap(c); i++ {
		r := <-c
		fmt.Printf("%s: took %s, code %d, err %v\n", r.url, r.took, r.code, r.err)
	}
}

type result struct {
	url  string
	took time.Duration
	code int
	err  error
}

func get(url string) result {
	begin := time.Now()
	resp, err := http.Get(url)
	code := 0
	if err == nil {
		code = resp.StatusCode
	}
	return result{
		url:  url,
		took: time.Since(begin),
		code: code,
		err:  err,
	}
}
<commit_msg>Whoopsy doodle<commit_after>package main

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

func main() {
	c := make(chan result, len(os.Args[1:]))
	for _, arg := range os.Args[1:] {
		go func(url string) { c <- get(url) }(arg)
	}
	for i := 0; i < cap(c); i++ {
		r := <-c
		fmt.Printf("%s: took %s, code %d, err %v\n", r.url, r.took, r.code, r.err)
	}
}

type result struct {
	url  string
	took time.Duration
	code int
	err  error
}

func get(url string) result {
	begin := time.Now()
	resp, err := http.Get(url)
	code := 0
	if err == nil {
		code = resp.StatusCode
		resp.Body.Close()
	}
	return result{
		url:  url,
		took: time.Since(begin),
		code: code,
		err:  err,
	}
}
<|endoftext|>


<commit_before>package config

import (
	"io"
	"time"

	"code.google.com/p/gcfg"
)

const (
	DefaultOfferTTL                           = 5 * time.Second    // duration an offer is viable, prior to being expired
	DefaultOfferLingerTTL                     = 120  * time.Second // duration an expired offer lingers in history
	DefaultListenerDelay                      = 1 * time.Second    // duration between offer listener notifications
	DefaultUpdatesBacklog                     = 2048               // size of the pod updates channel
	DefaultFrameworkIdRefreshInterval         = 30 * time.Second   // interval we update the frameworkId stored in etcd
	DefaultInitialImplicitReconciliationDelay = 15 * time.Second   // wait this amount of time after initial registration before attempting implicit reconciliation
	DefaultExplicitReconciliationMaxBackoff   = 2 * time.Minute    // interval in between internal task status checks/updates
	DefaultExplicitReconciliationAbortTimeout = 30 * time.Second   // waiting period after attempting to cancel an ongoing reconciliation
	DefaultInitialPodBackoff                  = 1 * time.Second
	DefaultMaxPodBackoff                      = 60 * time.Second
	DefaultHttpHandlerTimeout                 = 10 * time.Second
)

// Example scheduler configuration file:
//
// [scheduler]
//  info-name        = Kubernetes
//	offer-ttl        = 5s
//  offer-linger-ttl = 2m

type ConfigWrapper struct {
	Scheduler Config
}

type Config struct {
	OfferTTL                           WrappedDuration `gcfg:"offer-ttl"`
	OfferLingerTTL                     WrappedDuration `gcfg:"offer-linger-ttl"`
	ListenerDelay                      WrappedDuration `gcfg:"listener-delay"`
	UpdatesBacklog                     int             `gcfg:"updates-backlog"`
	FrameworkIdRefreshInterval         WrappedDuration `gcfg:"listener-delay"`
	InitialImplicitReconciliationDelay WrappedDuration `gcfg:"initial-implicit-reconciliation-delay"`
	ExplicitReconciliationMaxBackoff   WrappedDuration `gcfg:"explicit-reconciliantion-max-backoff"`
	ExplicitReconciliationAbortTimeout WrappedDuration `gcfg:"explicit-reconciliantion-abort-timeout"`
	InitialPodBackoff                  WrappedDuration `gcfg:"initial-pod-backoff"`
	MaxPodBackoff                      WrappedDuration `gcfg:"max-pod-backoff"`
	HttpHandlerTimeout                 WrappedDuration `gcfg:"http-handler-timeout"`
}

type WrappedDuration struct {
	Duration time.Duration `gcfg:"duration"`
}

func (wd *WrappedDuration) UnmarshalText(data []byte) error {
	d, err := time.ParseDuration(string(data))
	if err == nil {
		wd.Duration = d
	}
	return err
}

func (c *Config) SetDefaults() {
	c.OfferTTL = WrappedDuration{Duration: DefaultOfferTTL}
	c.OfferLingerTTL = WrappedDuration{Duration: DefaultOfferLingerTTL}
	c.ListenerDelay = WrappedDuration{Duration: DefaultListenerDelay}
	c.UpdatesBacklog = DefaultUpdatesBacklog
	c.FrameworkIdRefreshInterval = WrappedDuration{Duration: DefaultFrameworkIdRefreshInterval}
	c.InitialImplicitReconciliationDelay = WrappedDuration{Duration: DefaultInitialImplicitReconciliationDelay}
	c.ExplicitReconciliationMaxBackoff = WrappedDuration{Duration: DefaultExplicitReconciliationMaxBackoff}
	c.ExplicitReconciliationAbortTimeout = WrappedDuration{Duration: DefaultExplicitReconciliationAbortTimeout}
	c.InitialPodBackoff = WrappedDuration{Duration: DefaultInitialPodBackoff}
	c.MaxPodBackoff = WrappedDuration{Duration: DefaultMaxPodBackoff}
	c.HttpHandlerTimeout = WrappedDuration{Duration: DefaultHttpHandlerTimeout}
}

func CreateDefaultConfig() *Config {
	c := &Config{}
	c.SetDefaults()
	return c
}

func (c *Config) Read(configReader io.Reader) error {
	wrapper := &ConfigWrapper{Scheduler: *c}
	if configReader != nil {
		if err := gcfg.ReadInto(wrapper, configReader); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>Fix indention<commit_after>package config

import (
	"io"
	"time"

	"code.google.com/p/gcfg"
)

const (
	DefaultOfferTTL                           = 5 * time.Second    // duration an offer is viable, prior to being expired
	DefaultOfferLingerTTL                     = 120  * time.Second // duration an expired offer lingers in history
	DefaultListenerDelay                      = 1 * time.Second    // duration between offer listener notifications
	DefaultUpdatesBacklog                     = 2048               // size of the pod updates channel
	DefaultFrameworkIdRefreshInterval         = 30 * time.Second   // interval we update the frameworkId stored in etcd
	DefaultInitialImplicitReconciliationDelay = 15 * time.Second   // wait this amount of time after initial registration before attempting implicit reconciliation
	DefaultExplicitReconciliationMaxBackoff   = 2 * time.Minute    // interval in between internal task status checks/updates
	DefaultExplicitReconciliationAbortTimeout = 30 * time.Second   // waiting period after attempting to cancel an ongoing reconciliation
	DefaultInitialPodBackoff                  = 1 * time.Second
	DefaultMaxPodBackoff                      = 60 * time.Second
	DefaultHttpHandlerTimeout                 = 10 * time.Second
)

// Example scheduler configuration file:
//
// [scheduler]
//  info-name        = Kubernetes
//  offer-ttl        = 5s
//  offer-linger-ttl = 2m

type ConfigWrapper struct {
	Scheduler Config
}

type Config struct {
	OfferTTL                           WrappedDuration `gcfg:"offer-ttl"`
	OfferLingerTTL                     WrappedDuration `gcfg:"offer-linger-ttl"`
	ListenerDelay                      WrappedDuration `gcfg:"listener-delay"`
	UpdatesBacklog                     int             `gcfg:"updates-backlog"`
	FrameworkIdRefreshInterval         WrappedDuration `gcfg:"listener-delay"`
	InitialImplicitReconciliationDelay WrappedDuration `gcfg:"initial-implicit-reconciliation-delay"`
	ExplicitReconciliationMaxBackoff   WrappedDuration `gcfg:"explicit-reconciliantion-max-backoff"`
	ExplicitReconciliationAbortTimeout WrappedDuration `gcfg:"explicit-reconciliantion-abort-timeout"`
	InitialPodBackoff                  WrappedDuration `gcfg:"initial-pod-backoff"`
	MaxPodBackoff                      WrappedDuration `gcfg:"max-pod-backoff"`
	HttpHandlerTimeout                 WrappedDuration `gcfg:"http-handler-timeout"`
}

type WrappedDuration struct {
	Duration time.Duration `gcfg:"duration"`
}

func (wd *WrappedDuration) UnmarshalText(data []byte) error {
	d, err := time.ParseDuration(string(data))
	if err == nil {
		wd.Duration = d
	}
	return err
}

func (c *Config) SetDefaults() {
	c.OfferTTL = WrappedDuration{Duration: DefaultOfferTTL}
	c.OfferLingerTTL = WrappedDuration{Duration: DefaultOfferLingerTTL}
	c.ListenerDelay = WrappedDuration{Duration: DefaultListenerDelay}
	c.UpdatesBacklog = DefaultUpdatesBacklog
	c.FrameworkIdRefreshInterval = WrappedDuration{Duration: DefaultFrameworkIdRefreshInterval}
	c.InitialImplicitReconciliationDelay = WrappedDuration{Duration: DefaultInitialImplicitReconciliationDelay}
	c.ExplicitReconciliationMaxBackoff = WrappedDuration{Duration: DefaultExplicitReconciliationMaxBackoff}
	c.ExplicitReconciliationAbortTimeout = WrappedDuration{Duration: DefaultExplicitReconciliationAbortTimeout}
	c.InitialPodBackoff = WrappedDuration{Duration: DefaultInitialPodBackoff}
	c.MaxPodBackoff = WrappedDuration{Duration: DefaultMaxPodBackoff}
	c.HttpHandlerTimeout = WrappedDuration{Duration: DefaultHttpHandlerTimeout}
}

func CreateDefaultConfig() *Config {
	c := &Config{}
	c.SetDefaults()
	return c
}

func (c *Config) Read(configReader io.Reader) error {
	wrapper := &ConfigWrapper{Scheduler: *c}
	if configReader != nil {
		if err := gcfg.ReadInto(wrapper, configReader); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>