<commit_before>package libchunk

import (
	"fmt"
	"io"
	"os"
)

//Join will read and decrypt chunks for keys provided by the iterator and writes
//each chunk's contents to writer 'w' in order of key appearance. Chunks
//are fetched concurrently (locally or remote) but are guaranteed arrive in
//order to writer 'w' for assembly in the original format
func Join(keys KeyIterator, w io.Writer, conf Config) error {

	//result of working the item
	type result struct {
		chunk []byte
		err   error
	}

	//work item
	type item struct {
		key   K
		resCh chan *result
		err   error
	}

	//work is run concurrently
	work := func(it *item) {
		chunk, err := conf.Store.Get(it.key)
		if err != nil {
			if os.IsNotExist(err) {
				//@TODO add fetching from remote
				it.resCh <- &result{nil, ErrNoSuchKey}
				return
			}

			it.resCh <- &result{nil, fmt.Errorf("failed to find key '%s': %v", it.key, err)}
			return
		}

		res := &result{}
		res.chunk, res.err = conf.AEAD.Open(nil, it.key[:], chunk, nil)
		it.resCh <- res
	}

	//fan-out concurrent work
	itemCh := make(chan *item, 10)
	go func() {
		defer close(itemCh)
		for {
			k, err := keys.Next()
			if err != nil {
				if err != io.EOF {
					itemCh <- &item{
						key: k,
						err: fmt.Errorf("failed to iterate into next key: %v", err),
					}
				}

				break
			}

			it := &item{
				key:   k,
				resCh: make(chan *result),
			}

			go work(it)  //create work
			itemCh <- it //send to fan-in thread for syncing results
		}
	}()

	//fan in, output plaintext chunks
	for it := range itemCh {
		if it.err != nil {
			return fmt.Errorf("failed to iterate: %v", it.err)
		}

		res := <-it.resCh
		if res.err != nil {
			return fmt.Errorf("failed to work chunk '%s': %v", it.key, res.err)
		} else {
			_, err := w.Write(res.chunk)
			if err != nil {
				return fmt.Errorf("failed to write chunk '%s' to output: %v", it.key, err)
			}
		}
	}

	return nil
}
<commit_msg>added race condition protection in join logic<commit_after>package libchunk

import (
	"fmt"
	"io"
	"os"
)

//Join will read and decrypt chunks for keys provided by the iterator and write
//each chunk's contents to writer 'w' in order of key appearance. Chunks are
//fetched concurrently (locally or remote) but are guaranteed to arrive in
//order to writer 'w' for assembly in the original format
func Join(keys KeyIterator, w io.Writer, conf Config) error {

	//result of working the item
	type result struct {
		chunk []byte
		err   error
	}

	//work item
	type item struct {
		key   K
		resCh chan *result
		err   error
		pos   int64
	}

	//work is run concurrently
	work := func(it *item) {
		chunk, err := conf.Store.Get(it.key)
		if err != nil {
			if os.IsNotExist(err) {
				//@TODO add fetching from remote
				it.resCh <- &result{nil, ErrNoSuchKey}
				return
			}

			it.resCh <- &result{nil, fmt.Errorf("failed to find key '%s': %v", it.key, err)}
			return
		}

		res := &result{}
		res.chunk, res.err = conf.AEAD.Open(nil, it.key[:], chunk, nil)
		it.resCh <- res
	}

	//fan-out concurrent work
	itemCh := make(chan *item, 10)
	go func() {
		defer close(itemCh)
		pos := int64(0)
		for {
			k, err := keys.Next()
			if err != nil {
				if err != io.EOF {
					itemCh <- &item{
						key: k,
						err: fmt.Errorf("failed to iterate into next key: %v", err),
					}
				}

				break
			}

			it := &item{
				pos:   pos,
				key:   k,
				resCh: make(chan *result),
			}

			go work(it)  //create work
			itemCh <- it //send to fan-in thread for syncing results
			pos++
		}
	}()

	//fan in, output plaintext chunks
	var lastpos int64
	for it := range itemCh {
		if it.err != nil {
			return fmt.Errorf("failed to iterate: %v", it.err)
		}

		if lastpos > it.pos {
			//the language spec is unclear about guaranteed FIFO behaviour of
			//buffered channels, in rare conditions this behaviour might not
			//be guaranteed, for this project such a case be catestropic as it WILL
			//corrupt large files. This is a buildin safeguard that asks the user to
			//submit a real world example if this happens
			return fmt.Errorf("Unexpected race condition during joining, chunk '%d' arrived before chunk '%d', please report this to the author with the file that is being split", lastpos, it.pos)
		}

		res := <-it.resCh
		if res.err != nil {
			return fmt.Errorf("failed to work chunk '%s': %v", it.key, res.err)
		} else {
			_, err := w.Write(res.chunk)
			if err != nil {
				return fmt.Errorf("failed to write chunk '%s' to output: %v", it.key, err)
			}
		}

		lastpos = it.pos
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"time"

	"github.com/joshsoftware/curem/config"
	"labix.org/v2/mgo/bson"
)

type lead struct {
	Id                 bson.ObjectId `bson:"_id"                          json:"id"`
	ContactId          bson.ObjectId `bson:"contactId,omitempty"          json:"contactId,omitempty"`
	Source             string        `bson:"source,omitempty"             json:"source,omitempty"`
	Owner              string        `bson:"owner,omitempty"              json:"owner,omitempty"`
	Status             string        `bson:"status,omitempty"             json:"status,omitempty"`
	TeamSize           float64       `bson:"teamSize,omitempty"           json:"teamSize,omitempty"`
	RatePerHour        float64       `bson:"ratePerHour,omitempty"        json:"ratePerHour,omitempty"`
	DurationInMonths   float64       `bson:"durationInMonths,omitempty"   json:"durationInMonths,omitempty"`
	EstimatedStartDate string        `bson:"estimatedStartDate,omitempty" json:"estimatedStartDate,omitempty"`
	Comments           []string      `bson:"comments,omitempty"           json:"comments,omitempty"`
	CreatedAt          time.Time     `bson:"createdAt,omitempty"          json:"createdAt,omitempty"`
	UpdatedAt          time.Time     `bson:"updatedAt,omitempty"          json:"updatedAt,omitempty"`
}

// NewLead takes the fields of a lead, initializes a struct of lead type and returns
// the pointer to that struct.
// Also, It inserts the lead object into the database.
func NewLead(cid bson.ObjectId, source, owner, status string, teamsize, rate, duration float64,
	start string, comments []string) (*lead, error) {
	doc := lead{
		Id:                 bson.NewObjectId(),
		ContactId:          cid,
		Source:             source,
		Owner:              owner,
		Status:             status,
		TeamSize:           teamsize,
		RatePerHour:        rate,
		DurationInMonths:   duration,
		EstimatedStartDate: start,
		Comments:           comments,
	}

	doc.CreatedAt = doc.Id.Time()
	doc.UpdatedAt = doc.CreatedAt

	err := config.LeadsCollection.Insert(doc)
	if err != nil {
		return &lead{}, err
	}
	return &doc, nil
}

// GetLead takes the lead Id as an argument and returns a pointer to a lead object.
func GetLead(i bson.ObjectId) (*lead, error) {
	var l lead
	err := config.LeadsCollection.FindId(i).One(&l)
	if err != nil {
		return &lead{}, err
	}
	return &l, nil
}

// GetAllLeads fetches all the leads from the database.
func GetAllLeads() ([]lead, error) {
	var l []lead
	err := config.LeadsCollection.Find(nil).All(&l)
	if err != nil {
		return []lead{}, err
	}
	return l, nil
}

// Update updates the lead in the database.
// First, fetch a lead from the database and change the necessary fields.
// Then call the Update method on that lead object.
func (l *lead) Update() error {
	l.UpdatedAt = bson.Now()
	err := config.LeadsCollection.UpdateId(l.Id, l)
	return err
}

// Delete deletes the lead from the database.
func (l *lead) Delete() error {
	return config.LeadsCollection.RemoveId(l.Id)
}
<commit_msg>Add incomingLead type and copyIncomingFields method<commit_after>package main

import (
	"errors"
	"time"

	"github.com/joshsoftware/curem/config"
	"labix.org/v2/mgo/bson"
)

type lead struct {
	Id                 bson.ObjectId `bson:"_id"                          json:"id"`
	ContactId          bson.ObjectId `bson:"contactId,omitempty"          json:"contactId,omitempty"`
	Source             string        `bson:"source,omitempty"             json:"source,omitempty"`
	Owner              string        `bson:"owner,omitempty"              json:"owner,omitempty"`
	Status             string        `bson:"status,omitempty"             json:"status,omitempty"`
	TeamSize           float64       `bson:"teamSize,omitempty"           json:"teamSize,omitempty"`
	RatePerHour        float64       `bson:"ratePerHour,omitempty"        json:"ratePerHour,omitempty"`
	DurationInMonths   float64       `bson:"durationInMonths,omitempty"   json:"durationInMonths,omitempty"`
	EstimatedStartDate string        `bson:"estimatedStartDate,omitempty" json:"estimatedStartDate,omitempty"`
	Comments           []string      `bson:"comments,omitempty"           json:"comments,omitempty"`
	CreatedAt          time.Time     `bson:"createdAt,omitempty"          json:"createdAt,omitempty"`
	UpdatedAt          time.Time     `bson:"updatedAt,omitempty"          json:"updatedAt,omitempty"`
}

type incomingLead struct {
	Id                 *bson.ObjectId `json:"id"`
	ContactId          *bson.ObjectId `json:"contactId,omitempty"`
	Source             *string        `json:"source,omitempty"`
	Owner              *string        `json:"owner,omitempty"`
	Status             *string        `json:"status,omitempty"`
	TeamSize           *float64       `json:"teamSize,omitempty"`
	RatePerHour        *float64       `json:"ratePerHour,omitempty"`
	DurationInMonths   *float64       `json:"durationInMonths,omitempty"`
	EstimatedStartDate *string        `json:"estimatedStartDate,omitempty"`
	Comments           *[]string      `json:"comments,omitempty"`
}

func (l *lead) copyIncomingFields(i *incomingLead) error {
	if i.Id != nil {
		if *i.Id != l.Id {
			return errors.New("Id doesn't match")
		}
	}
	if i.ContactId != nil {
		l.Id = *i.Id
	}
	if i.Source != nil {
		l.Source = *i.Source
	}
	if i.Owner != nil {
		l.Owner = *i.Owner
	}
	if i.Status != nil {
		l.Status = *i.Status
	}
	if i.TeamSize != nil {
		l.TeamSize = *i.TeamSize
	}
	if i.RatePerHour != nil {
		l.RatePerHour = *i.RatePerHour
	}
	if i.DurationInMonths != nil {
		l.DurationInMonths = *i.DurationInMonths
	}
	if i.EstimatedStartDate != nil {
		l.EstimatedStartDate = *i.EstimatedStartDate
	}
	if i.Comments != nil {
		l.Comments = *i.Comments
	}
	return nil
}

// NewLead takes the fields of a lead, initializes a struct of lead type and returns
// the pointer to that struct.
// Also, It inserts the lead object into the database.
func NewLead(cid bson.ObjectId, source, owner, status string, teamsize, rate, duration float64,
	start string, comments []string) (*lead, error) {
	doc := lead{
		Id:                 bson.NewObjectId(),
		ContactId:          cid,
		Source:             source,
		Owner:              owner,
		Status:             status,
		TeamSize:           teamsize,
		RatePerHour:        rate,
		DurationInMonths:   duration,
		EstimatedStartDate: start,
		Comments:           comments,
	}

	doc.CreatedAt = doc.Id.Time()
	doc.UpdatedAt = doc.CreatedAt

	err := config.LeadsCollection.Insert(doc)
	if err != nil {
		return &lead{}, err
	}
	return &doc, nil
}

// GetLead takes the lead Id as an argument and returns a pointer to a lead object.
func GetLead(i bson.ObjectId) (*lead, error) {
	var l lead
	err := config.LeadsCollection.FindId(i).One(&l)
	if err != nil {
		return &lead{}, err
	}
	return &l, nil
}

// GetAllLeads fetches all the leads from the database.
func GetAllLeads() ([]lead, error) {
	var l []lead
	err := config.LeadsCollection.Find(nil).All(&l)
	if err != nil {
		return []lead{}, err
	}
	return l, nil
}

// Update updates the lead in the database.
// First, fetch a lead from the database and change the necessary fields.
// Then call the Update method on that lead object.
func (l *lead) Update() error {
	l.UpdatedAt = bson.Now()
	err := config.LeadsCollection.UpdateId(l.Id, l)
	return err
}

// Delete deletes the lead from the database.
func (l *lead) Delete() error {
	return config.LeadsCollection.RemoveId(l.Id)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/gob"
	"errors"
	"flag"
	"fmt"
	"io"
	"net"
	"os"
	"os/exec"
	"os/signal"
	"runtime"
	"syscall"
	"unsafe"
)

var (
	modshell32         = syscall.NewLazyDLL("shell32.dll")
	procShellExecuteEx = modshell32.NewProc("ShellExecuteExW")
)

const (
	_SEE_MASK_NOCLOSEPROCESS = 0x00000040
)

const (
	_ERROR_BAD_FORMAT = 11
)

const (
	_SE_ERR_FNF             = 2
	_SE_ERR_PNF             = 3
	_SE_ERR_ACCESSDENIED    = 5
	_SE_ERR_OOM             = 8
	_SE_ERR_DLLNOTFOUND     = 32
	_SE_ERR_SHARE           = 26
	_SE_ERR_ASSOCINCOMPLETE = 27
	_SE_ERR_DDETIMEOUT      = 28
	_SE_ERR_DDEFAIL         = 29
	_SE_ERR_DDEBUSY         = 30
	_SE_ERR_NOASSOC         = 31
)

type (
	dword     uint32
	hinstance syscall.Handle
	hkey      syscall.Handle
	hwnd      syscall.Handle
	ulong     uint32
	lpctstr   uintptr
	lpvoid    uintptr
)

// SHELLEXECUTEINFO struct
type _SHELLEXECUTEINFO struct {
	cbSize         dword
	fMask          ulong
	hwnd           hwnd
	lpVerb         lpctstr
	lpFile         lpctstr
	lpParameters   lpctstr
	lpDirectory    lpctstr
	nShow          int
	hInstApp       hinstance
	lpIDList       lpvoid
	lpClass        lpctstr
	hkeyClass      hkey
	dwHotKey       dword
	hIconOrMonitor syscall.Handle
	hProcess       syscall.Handle
}

// _ShellExecuteAndWait is version of ShellExecuteEx which want process
func _ShellExecuteAndWait(hwnd hwnd, lpOperation, lpFile, lpParameters, lpDirectory string, nShowCmd int) error {
	var lpctstrVerb, lpctstrParameters, lpctstrDirectory lpctstr
	if len(lpOperation) != 0 {
		lpctstrVerb = lpctstr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpOperation)))
	}
	if len(lpParameters) != 0 {
		lpctstrParameters = lpctstr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpParameters)))
	}
	if len(lpDirectory) != 0 {
		lpctstrDirectory = lpctstr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpDirectory)))
	}
	i := &_SHELLEXECUTEINFO{
		fMask:        _SEE_MASK_NOCLOSEPROCESS,
		hwnd:         hwnd,
		lpVerb:       lpctstrVerb,
		lpFile:       lpctstr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpFile))),
		lpParameters: lpctstrParameters,
		lpDirectory:  lpctstrDirectory,
		nShow:        nShowCmd,
	}
	i.cbSize = dword(unsafe.Sizeof(*i))
	return _ShellExecuteEx(i)
}

// ShellExecuteEx is Windows API
func _ShellExecuteEx(pExecInfo *_SHELLEXECUTEINFO) error {
	ret, _, _ := procShellExecuteEx.Call(uintptr(unsafe.Pointer(pExecInfo)))
	if ret == 1 && pExecInfo.fMask&_SEE_MASK_NOCLOSEPROCESS != 0 {
		s, e := syscall.WaitForSingleObject(syscall.Handle(pExecInfo.hProcess), syscall.INFINITE)
		switch s {
		case syscall.WAIT_OBJECT_0:
			break
		case syscall.WAIT_FAILED:
			return os.NewSyscallError("WaitForSingleObject", e)
		default:
			return errors.New("Unexpected result from WaitForSingleObject")
		}
	}
	errorMsg := ""
	if pExecInfo.hInstApp != 0 && pExecInfo.hInstApp <= 32 {
		switch int(pExecInfo.hInstApp) {
		case _SE_ERR_FNF:
			errorMsg = "The specified file was not found"
		case _SE_ERR_PNF:
			errorMsg = "The specified path was not found"
		case _ERROR_BAD_FORMAT:
			errorMsg = "The .exe file is invalid (non-Win32 .exe or error in .exe image)"
		case _SE_ERR_ACCESSDENIED:
			errorMsg = "The operating system denied access to the specified file"
		case _SE_ERR_ASSOCINCOMPLETE:
			errorMsg = "The file name association is incomplete or invalid"
		case _SE_ERR_DDEBUSY:
			errorMsg = "The DDE transaction could not be completed because other DDE transactions were being processed"
		case _SE_ERR_DDEFAIL:
			errorMsg = "The DDE transaction failed"
		case _SE_ERR_DDETIMEOUT:
			errorMsg = "The DDE transaction could not be completed because the request timed out"
		case _SE_ERR_DLLNOTFOUND:
			errorMsg = "The specified DLL was not found"
		case _SE_ERR_NOASSOC:
			errorMsg = "There is no application associated with the given file name extension"
		case _SE_ERR_OOM:
			errorMsg = "There was not enough memory to complete the operation"
		case _SE_ERR_SHARE:
			errorMsg = "A sharing violation occurred"
		default:
			errorMsg = fmt.Sprintf("Unknown error occurred with error code %v", pExecInfo.hInstApp)
		}
	} else {
		return nil
	}
	return errors.New(errorMsg)
}

type msg struct {
	Name  string
	Exit  int
	Error string
	Data  []byte
}

func msgWrite(enc *gob.Encoder, typ string) io.WriteCloser {
	r, w := io.Pipe()
	go func() {
		defer r.Close()
		var b [4096]byte
		for {
			n, err := r.Read(b[:])
			if err != nil {
				break
			}
			err = enc.Encode(&msg{Name: typ, Data: b[:n]})
			if err != nil {
				break
			}
		}
	}()
	return w
}

func client(addr string) int {
	// connect to server
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		panic(err.Error())
	}
	defer conn.Close()

	enc, dec := gob.NewEncoder(conn), gob.NewDecoder(conn)

	cmd := exec.Command(flag.Arg(0), flag.Args()[1:]...)

	// stdin
	inw, err := cmd.StdinPipe()
	if err != nil {
		enc.Encode(&msg{Name: "error", Error: fmt.Sprintf("cannot execute command: %v", makeCmdLine(flag.Args()))})
		return 1
	}
	defer inw.Close()

	// stdout
	outw := msgWrite(enc, "stdout")
	defer outw.Close()
	cmd.Stdout = outw

	// stderr
	errw := msgWrite(enc, "stderr")
	defer errw.Close()
	cmd.Stderr = errw

	go func() {
		defer inw.Close()
	in_loop:
		for {
			var m msg
			err = dec.Decode(&m)
			if err != nil {
				return
			}
			switch m.Name {
			case "close":
				break in_loop
			case "ctrlc":
				if runtime.GOOS == "windows" {
					// windows doesn't support os.Interrupt
					exec.Command("taskkill", "/F", "/T", "/PID", fmt.Sprint(cmd.Process.Pid)).Run()
				} else {
					cmd.Process.Signal(os.Interrupt)
				}
				break in_loop
			case "stdin":
				inw.Write(m.Data)
			}
		}
	}()

	err = cmd.Run()

	code := 1
	if err != nil {
		if status, ok := cmd.ProcessState.Sys().(syscall.WaitStatus); ok {
			code = status.ExitStatus()
		}
	} else {
		code = 0
	}

	err = enc.Encode(&msg{Name: "exit", Exit: code})
	if err != nil {
		enc.Encode(&msg{Name: "error", Error: fmt.Sprintf("cannot detect exit code: %v", makeCmdLine(flag.Args()))})
		return 1
	}
	return 0
}

func makeCmdLine(args []string) string {
	var s string
	for _, v := range args {
		if s != "" {
			s += " "
		}
		s += syscall.EscapeArg(v)
	}
	return s
}

func server() int {
	// make listner to communicate child process
	lis, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v: cannot make listener\n", os.Args[0])
		return 1
	}
	defer lis.Close()

	// make sure executable name to avoid detecting same executable name
	exe, err := os.Executable()
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v: cannot find executable\n", os.Args[0])
		return 1
	}
	args := []string{"-mode", lis.Addr().String()}
	args = append(args, flag.Args()...)

	var errExec error
	go func() {
		err = _ShellExecuteAndWait(0, "runas", exe, makeCmdLine(args), "", syscall.SW_HIDE)
		if err != nil {
			errExec = err
			lis.Close()
		}
	}()

	conn, err := lis.Accept()
	if err != nil {
		if errExec != nil {
			fmt.Fprintf(os.Stderr, "%v: %v\n", os.Args[0], errExec)
		} else {
			fmt.Fprintf(os.Stderr, "%v: cannot execute command: %v\n", os.Args[0], makeCmdLine(flag.Args()))
		}
		return 1
	}
	defer conn.Close()

	enc, dec := gob.NewEncoder(conn), gob.NewDecoder(conn)

	sc := make(chan os.Signal, 1)
	signal.Notify(sc, os.Interrupt)
	go func() {
		for range sc {
			enc.Encode(&msg{Name: "ctrlc"})
		}
	}()
	defer close(sc)

	go func() {
		var b [256]byte
		for {
			n, err := os.Stdin.Read(b[:])
			if err != nil {
				// stdin was closed
				if err == io.EOF {
					enc.Encode(&msg{Name: "close"})
				}
				continue
			}
			err = enc.Encode(&msg{Name: "stdin", Data: b[:n]})
			if err != nil {
				break
			}
		}
	}()

	for {
		var m msg
		err = dec.Decode(&m)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%v: cannot execute command: %v\n", os.Args[0], makeCmdLine(flag.Args()))
			return 1
		}
		switch m.Name {
		case "stdout":
			syscall.Write(syscall.Stdout, m.Data)
		case "stderr":
			syscall.Write(syscall.Stderr, m.Data)
		case "error":
			fmt.Fprintln(os.Stderr, m.Error)
		case "exit":
			return m.Exit
		}
	}
}

func main() {
	var mode string
	flag.StringVar(&mode, "mode", "", "mode")
	flag.Parse()
	if mode != "" {
		os.Exit(client(mode))
	}
	os.Exit(server())
}
<commit_msg>fix typo<commit_after>package main

import (
	"encoding/gob"
	"errors"
	"flag"
	"fmt"
	"io"
	"net"
	"os"
	"os/exec"
	"os/signal"
	"runtime"
	"syscall"
	"unsafe"
)

var (
	modshell32         = syscall.NewLazyDLL("shell32.dll")
	procShellExecuteEx = modshell32.NewProc("ShellExecuteExW")
)

const (
	_SEE_MASK_NOCLOSEPROCESS = 0x00000040
)

const (
	_ERROR_BAD_FORMAT = 11
)

const (
	_SE_ERR_FNF             = 2
	_SE_ERR_PNF             = 3
	_SE_ERR_ACCESSDENIED    = 5
	_SE_ERR_OOM             = 8
	_SE_ERR_DLLNOTFOUND     = 32
	_SE_ERR_SHARE           = 26
	_SE_ERR_ASSOCINCOMPLETE = 27
	_SE_ERR_DDETIMEOUT      = 28
	_SE_ERR_DDEFAIL         = 29
	_SE_ERR_DDEBUSY         = 30
	_SE_ERR_NOASSOC         = 31
)

type (
	dword     uint32
	hinstance syscall.Handle
	hkey      syscall.Handle
	hwnd      syscall.Handle
	ulong     uint32
	lpctstr   uintptr
	lpvoid    uintptr
)

// SHELLEXECUTEINFO struct
type _SHELLEXECUTEINFO struct {
	cbSize         dword
	fMask          ulong
	hwnd           hwnd
	lpVerb         lpctstr
	lpFile         lpctstr
	lpParameters   lpctstr
	lpDirectory    lpctstr
	nShow          int
	hInstApp       hinstance
	lpIDList       lpvoid
	lpClass        lpctstr
	hkeyClass      hkey
	dwHotKey       dword
	hIconOrMonitor syscall.Handle
	hProcess       syscall.Handle
}

// _ShellExecuteAndWait is version of ShellExecuteEx which want process
func _ShellExecuteAndWait(hwnd hwnd, lpOperation, lpFile, lpParameters, lpDirectory string, nShowCmd int) error {
	var lpctstrVerb, lpctstrParameters, lpctstrDirectory lpctstr
	if len(lpOperation) != 0 {
		lpctstrVerb = lpctstr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpOperation)))
	}
	if len(lpParameters) != 0 {
		lpctstrParameters = lpctstr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpParameters)))
	}
	if len(lpDirectory) != 0 {
		lpctstrDirectory = lpctstr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpDirectory)))
	}
	i := &_SHELLEXECUTEINFO{
		fMask:        _SEE_MASK_NOCLOSEPROCESS,
		hwnd:         hwnd,
		lpVerb:       lpctstrVerb,
		lpFile:       lpctstr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpFile))),
		lpParameters: lpctstrParameters,
		lpDirectory:  lpctstrDirectory,
		nShow:        nShowCmd,
	}
	i.cbSize = dword(unsafe.Sizeof(*i))
	return _ShellExecuteEx(i)
}

// ShellExecuteEx is Windows API
func _ShellExecuteEx(pExecInfo *_SHELLEXECUTEINFO) error {
	ret, _, _ := procShellExecuteEx.Call(uintptr(unsafe.Pointer(pExecInfo)))
	if ret == 1 && pExecInfo.fMask&_SEE_MASK_NOCLOSEPROCESS != 0 {
		s, e := syscall.WaitForSingleObject(syscall.Handle(pExecInfo.hProcess), syscall.INFINITE)
		switch s {
		case syscall.WAIT_OBJECT_0:
			break
		case syscall.WAIT_FAILED:
			return os.NewSyscallError("WaitForSingleObject", e)
		default:
			return errors.New("Unexpected result from WaitForSingleObject")
		}
	}
	errorMsg := ""
	if pExecInfo.hInstApp != 0 && pExecInfo.hInstApp <= 32 {
		switch int(pExecInfo.hInstApp) {
		case _SE_ERR_FNF:
			errorMsg = "The specified file was not found"
		case _SE_ERR_PNF:
			errorMsg = "The specified path was not found"
		case _ERROR_BAD_FORMAT:
			errorMsg = "The .exe file is invalid (non-Win32 .exe or error in .exe image)"
		case _SE_ERR_ACCESSDENIED:
			errorMsg = "The operating system denied access to the specified file"
		case _SE_ERR_ASSOCINCOMPLETE:
			errorMsg = "The file name association is incomplete or invalid"
		case _SE_ERR_DDEBUSY:
			errorMsg = "The DDE transaction could not be completed because other DDE transactions were being processed"
		case _SE_ERR_DDEFAIL:
			errorMsg = "The DDE transaction failed"
		case _SE_ERR_DDETIMEOUT:
			errorMsg = "The DDE transaction could not be completed because the request timed out"
		case _SE_ERR_DLLNOTFOUND:
			errorMsg = "The specified DLL was not found"
		case _SE_ERR_NOASSOC:
			errorMsg = "There is no application associated with the given file name extension"
		case _SE_ERR_OOM:
			errorMsg = "There was not enough memory to complete the operation"
		case _SE_ERR_SHARE:
			errorMsg = "A sharing violation occurred"
		default:
			errorMsg = fmt.Sprintf("Unknown error occurred with error code %v", pExecInfo.hInstApp)
		}
	} else {
		return nil
	}
	return errors.New(errorMsg)
}

type msg struct {
	Name  string
	Exit  int
	Error string
	Data  []byte
}

func msgWrite(enc *gob.Encoder, typ string) io.WriteCloser {
	r, w := io.Pipe()
	go func() {
		defer r.Close()
		var b [4096]byte
		for {
			n, err := r.Read(b[:])
			if err != nil {
				break
			}
			err = enc.Encode(&msg{Name: typ, Data: b[:n]})
			if err != nil {
				break
			}
		}
	}()
	return w
}

func client(addr string) int {
	// connect to server
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		panic(err.Error())
	}
	defer conn.Close()

	enc, dec := gob.NewEncoder(conn), gob.NewDecoder(conn)

	cmd := exec.Command(flag.Arg(0), flag.Args()[1:]...)

	// stdin
	inw, err := cmd.StdinPipe()
	if err != nil {
		enc.Encode(&msg{Name: "error", Error: fmt.Sprintf("cannot execute command: %v", makeCmdLine(flag.Args()))})
		return 1
	}
	defer inw.Close()

	// stdout
	outw := msgWrite(enc, "stdout")
	defer outw.Close()
	cmd.Stdout = outw

	// stderr
	errw := msgWrite(enc, "stderr")
	defer errw.Close()
	cmd.Stderr = errw

	go func() {
		defer inw.Close()
	in_loop:
		for {
			var m msg
			err = dec.Decode(&m)
			if err != nil {
				return
			}
			switch m.Name {
			case "close":
				break in_loop
			case "ctrlc":
				if runtime.GOOS == "windows" {
					// windows doesn't support os.Interrupt
					exec.Command("taskkill", "/F", "/T", "/PID", fmt.Sprint(cmd.Process.Pid)).Run()
				} else {
					cmd.Process.Signal(os.Interrupt)
				}
				break in_loop
			case "stdin":
				inw.Write(m.Data)
			}
		}
	}()

	err = cmd.Run()

	code := 1
	if err != nil {
		if status, ok := cmd.ProcessState.Sys().(syscall.WaitStatus); ok {
			code = status.ExitStatus()
		}
	} else {
		code = 0
	}

	err = enc.Encode(&msg{Name: "exit", Exit: code})
	if err != nil {
		enc.Encode(&msg{Name: "error", Error: fmt.Sprintf("cannot detect exit code: %v", makeCmdLine(flag.Args()))})
		return 1
	}
	return 0
}

func makeCmdLine(args []string) string {
	var s string
	for _, v := range args {
		if s != "" {
			s += " "
		}
		s += syscall.EscapeArg(v)
	}
	return s
}

func server() int {
	// make listener to communicate child process
	lis, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v: cannot make listener\n", os.Args[0])
		return 1
	}
	defer lis.Close()

	// make sure executable name to avoid detecting same executable name
	exe, err := os.Executable()
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v: cannot find executable\n", os.Args[0])
		return 1
	}
	args := []string{"-mode", lis.Addr().String()}
	args = append(args, flag.Args()...)

	var errExec error
	go func() {
		err = _ShellExecuteAndWait(0, "runas", exe, makeCmdLine(args), "", syscall.SW_HIDE)
		if err != nil {
			errExec = err
			lis.Close()
		}
	}()

	conn, err := lis.Accept()
	if err != nil {
		if errExec != nil {
			fmt.Fprintf(os.Stderr, "%v: %v\n", os.Args[0], errExec)
		} else {
			fmt.Fprintf(os.Stderr, "%v: cannot execute command: %v\n", os.Args[0], makeCmdLine(flag.Args()))
		}
		return 1
	}
	defer conn.Close()

	enc, dec := gob.NewEncoder(conn), gob.NewDecoder(conn)

	sc := make(chan os.Signal, 1)
	signal.Notify(sc, os.Interrupt)
	go func() {
		for range sc {
			enc.Encode(&msg{Name: "ctrlc"})
		}
	}()
	defer close(sc)

	go func() {
		var b [256]byte
		for {
			n, err := os.Stdin.Read(b[:])
			if err != nil {
				// stdin was closed
				if err == io.EOF {
					enc.Encode(&msg{Name: "close"})
				}
				continue
			}
			err = enc.Encode(&msg{Name: "stdin", Data: b[:n]})
			if err != nil {
				break
			}
		}
	}()

	for {
		var m msg
		err = dec.Decode(&m)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%v: cannot execute command: %v\n", os.Args[0], makeCmdLine(flag.Args()))
			return 1
		}
		switch m.Name {
		case "stdout":
			syscall.Write(syscall.Stdout, m.Data)
		case "stderr":
			syscall.Write(syscall.Stderr, m.Data)
		case "error":
			fmt.Fprintln(os.Stderr, m.Error)
		case "exit":
			return m.Exit
		}
	}
}

func main() {
	var mode string
	flag.StringVar(&mode, "mode", "", "mode")
	flag.Parse()
	if mode != "" {
		os.Exit(client(mode))
	}
	os.Exit(server())
}
<|endoftext|>


<commit_before>// Copyright 2015 The Prometheus 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 main

import (
	"compress/gzip"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"math"
	"net/http"
	"sort"
	"strings"
	"sync"
	"time"

	"bosun.org/opentsdb"
	"github.com/prometheus/client_golang/prometheus"
	"gopkg.in/inconshreveable/log15.v2"
)

var (
	Log = log15.New()

	sampleExpiry  = flag.Duration("scollector.sample-expiry", 5*time.Minute, "How long a sample is valid for.")
	lastProcessed = prometheus.NewGauge(
		prometheus.GaugeOpts{
			Name: "scollector_last_processed_timestamp_seconds",
			Help: "Unix timestamp of the last processed scollector metric.",
		},
	)
)

// Most of the ideas are stolen from https://github.com/prometheus/graphite_exporter/blob/master/main.go
// https://github.com/prometheus/graphite_exporter/commit/298611cd340e0a34bc9d2d434f47456c6c201221

type scollectorSample struct {
	Name      string
	Labels    map[string]string
	Help      string
	Value     float64
	Type      prometheus.ValueType
	Timestamp time.Time
}

func (s scollectorSample) NameWithLabels() string {
	labels := make([]string, 0, len(s.Labels))
	for k, v := range s.Labels {
		labels = append(labels, k+"="+v)
	}
	sort.Strings(labels)
	return s.Name + "#" + strings.Join(labels, ";")
}

type scollectorCollector struct {
	samples map[string]scollectorSample
	types   map[string]string
	ch      chan scollectorSample
	mu      sync.Mutex
}

func newScollectorCollector() *scollectorCollector {
	c := &scollectorCollector{
		ch:      make(chan scollectorSample, 0),
		samples: make(map[string]scollectorSample, 512),
		types:   make(map[string]string, 512),
	}
	go c.processSamples()
	return c
}

func (c *scollectorCollector) processSamples() {
	ticker := time.NewTicker(time.Minute).C
	for {
		select {
		case sample := <-c.ch:
			c.mu.Lock()
			c.samples[sample.NameWithLabels()] = sample
			c.mu.Unlock()
		case <-ticker:
			// Garbage collect expired samples.
			ageLimit := time.Now().Add(-*sampleExpiry)
			c.mu.Lock()
			for k, sample := range c.samples {
				if ageLimit.After(sample.Timestamp) {
					delete(c.samples, k)
				}
			}
			c.mu.Unlock()
		}
	}
}

// Collect implements prometheus.Collector.
func (c *scollectorCollector) Collect(ch chan<- prometheus.Metric) {
	Log.Debug("Collect", "samples", len(c.samples))
	ch <- lastProcessed
	Log.Debug("Collect", "lastProcessed", lastProcessed)

	c.mu.Lock()
	samples := make([]scollectorSample, 0, len(c.samples))
	for _, sample := range c.samples {
		samples = append(samples, sample)
	}
	c.mu.Unlock()

	ageLimit := time.Now().Add(-*sampleExpiry)
	for _, sample := range samples {
		if ageLimit.After(sample.Timestamp) {
			Log.Debug("skipping old sample", "limit", ageLimit, "sample", sample)
			continue
		}
		Log.Debug("sending sample", "sample", sample)
		ch <- prometheus.MustNewConstMetric(
			prometheus.NewDesc(sample.Name, sample.Help, []string{}, sample.Labels),
			sample.Type,
			sample.Value,
		)
	}
}

// Describe implements prometheus.Collector.
func (c *scollectorCollector) Describe(ch chan<- *prometheus.Desc) {
	ch <- lastProcessed.Desc()
}

var dotReplacer = strings.NewReplacer(".", "_")

func (c *scollectorCollector) handleScoll(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()
	sendErr := func(msg string, code int) {
		Log.Error(msg)
		http.Error(w, msg, http.StatusMethodNotAllowed)
	}
	if r.Method != "POST" {
		sendErr("Only POST is allowed", http.StatusMethodNotAllowed)
		return
	}
	if r.Header.Get("Content-Type") != "application/json" {
		sendErr("Only application/json is allowed", http.StatusBadRequest)
		return
	}

	rdr := io.Reader(r.Body)
	if r.Header.Get("Content-Encoding") == "gzip" {
		var err error
		if rdr, err = gzip.NewReader(rdr); err != nil {
			sendErr("Not gzipped: "+err.Error(), http.StatusBadRequest)
			return
		}
	}
	var batch []opentsdb.DataPoint
	if err := json.NewDecoder(rdr).Decode(&batch); err != nil {
		sendErr("cannot decode JSON: "+err.Error(), http.StatusBadRequest)
		return
	}

	Log.Debug("batch", "size", len(batch))
	n := 0
	for _, m := range batch {
		Log.Debug("got", "msg", m)
		name := clearName(m.Metric, true, 'x')
		if name == "" {
			Log.Warn("bad metric name: " + m.Metric)
			continue
		}

		var v float64
		switch x := m.Value.(type) {
		case float64:
			v = x
		case int:
			v = float64(x)
		case int64:
			v = float64(x)
		case int32:
			v = float64(x)
		case string: // type info
			if x != "" {
				if z, ok := c.types[name]; !ok || z != x {
					c.types[name] = x
				}
			}
			continue
		default:
			Log.Warn("unknown value", "type", fmt.Sprintf("%T", m.Value), "msg", m)
			continue
		}
		typ := prometheus.GaugeValue
		if c.types[name] == "counter" {
			typ = prometheus.CounterValue
		}
		var ts time.Time
		if m.Timestamp >= 1e10 {
			ts = time.Unix(
				m.Timestamp&(1e10-1),
				int64(math.Mod(float64(m.Timestamp), 1e10))*int64(time.Millisecond))
		} else {
			ts = time.Unix(m.Timestamp, 0)
		}
		for k := range m.Tags {
			k2 := clearName(k, false, 'x')
			if k2 != "" && k2 != k {
				Log.Warn("bad label name " + k)
				m.Tags[k2] = m.Tags[k]
				delete(m.Tags, k)
			}
		}
		if m.Tags["host"] != "" {
			m.Tags["instance"] = m.Tags["host"]
			delete(m.Tags, "host")
		}
		c.ch <- scollectorSample{
			Name:      name,
			Labels:    m.Tags,
			Type:      typ,
			Help:      fmt.Sprintf("Scollector metric %s (%s)", m.Metric, c.types[name]),
			Value:     v,
			Timestamp: ts,
		}
		n++
	}
	lastProcessed.Set(float64(time.Now().UnixNano()) / 1e9)
	Log.Info("processed", "messages", n, "samples", len(c.samples), "types", len(c.types))

	w.WriteHeader(http.StatusNoContent)
}

var (
	flagAddr      = flag.String("http", "0.0.0.0:9107", "address to listen on")
	flagScollPref = flag.String("scollector.prefix", "/api/put", "HTTP path prefix for listening for scollector-sent data")
	flagVerbose   = flag.Bool("v", false, "verbose logging")
)

func main() {
	hndl := log15.CallerFileHandler(log15.StderrHandler)
	Log.SetHandler(hndl)

	flag.Parse()
	if !*flagVerbose {
		Log.SetHandler(log15.LvlFilterHandler(log15.LvlInfo, hndl))
	}

	c := newScollectorCollector()
	prometheus.MustRegister(c)

	http.HandleFunc(*flagScollPref, c.handleScoll)
	http.Handle("/metrics", prometheus.Handler())
	Log.Info("Serving on " + *flagAddr)
	http.ListenAndServe(*flagAddr, nil)
}

// clearName replaces non-allowed characters.
func clearName(txt string, allowColon bool, replaceRune rune) string {
	if replaceRune == 0 {
		replaceRune = -1
	}
	i := -1
	return strings.Map(
		func(r rune) rune {
			i++
			if r == '.' {
				return '_'
			}
			if 'a' <= r && r <= 'z' || 'A' <= r && r <= 'Z' || r == '_' {
				return r
			}
			if allowColon && r == ':' {
				return r
			}
			if i > 0 && '0' <= r && r <= '9' {
				return r
			}
			return replaceRune
		},
		txt)
}
<commit_msg>Bugfix: handleScoll's error response now uses the code parameter instead of http.StatusMethodNotAllowed<commit_after>// Copyright 2015 The Prometheus 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 main

import (
	"compress/gzip"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"math"
	"net/http"
	"sort"
	"strings"
	"sync"
	"time"

	"bosun.org/opentsdb"
	"github.com/prometheus/client_golang/prometheus"
	"gopkg.in/inconshreveable/log15.v2"
)

var (
	Log = log15.New()

	sampleExpiry  = flag.Duration("scollector.sample-expiry", 5*time.Minute, "How long a sample is valid for.")
	lastProcessed = prometheus.NewGauge(
		prometheus.GaugeOpts{
			Name: "scollector_last_processed_timestamp_seconds",
			Help: "Unix timestamp of the last processed scollector metric.",
		},
	)
)

// Most of the ideas are stolen from https://github.com/prometheus/graphite_exporter/blob/master/main.go
// https://github.com/prometheus/graphite_exporter/commit/298611cd340e0a34bc9d2d434f47456c6c201221

type scollectorSample struct {
	Name      string
	Labels    map[string]string
	Help      string
	Value     float64
	Type      prometheus.ValueType
	Timestamp time.Time
}

func (s scollectorSample) NameWithLabels() string {
	labels := make([]string, 0, len(s.Labels))
	for k, v := range s.Labels {
		labels = append(labels, k+"="+v)
	}
	sort.Strings(labels)
	return s.Name + "#" + strings.Join(labels, ";")
}

type scollectorCollector struct {
	samples map[string]scollectorSample
	types   map[string]string
	ch      chan scollectorSample
	mu      sync.Mutex
}

func newScollectorCollector() *scollectorCollector {
	c := &scollectorCollector{
		ch:      make(chan scollectorSample, 0),
		samples: make(map[string]scollectorSample, 512),
		types:   make(map[string]string, 512),
	}
	go c.processSamples()
	return c
}

func (c *scollectorCollector) processSamples() {
	ticker := time.NewTicker(time.Minute).C
	for {
		select {
		case sample := <-c.ch:
			c.mu.Lock()
			c.samples[sample.NameWithLabels()] = sample
			c.mu.Unlock()
		case <-ticker:
			// Garbage collect expired samples.
			ageLimit := time.Now().Add(-*sampleExpiry)
			c.mu.Lock()
			for k, sample := range c.samples {
				if ageLimit.After(sample.Timestamp) {
					delete(c.samples, k)
				}
			}
			c.mu.Unlock()
		}
	}
}

// Collect implements prometheus.Collector.
func (c *scollectorCollector) Collect(ch chan<- prometheus.Metric) {
	Log.Debug("Collect", "samples", len(c.samples))
	ch <- lastProcessed
	Log.Debug("Collect", "lastProcessed", lastProcessed)

	c.mu.Lock()
	samples := make([]scollectorSample, 0, len(c.samples))
	for _, sample := range c.samples {
		samples = append(samples, sample)
	}
	c.mu.Unlock()

	ageLimit := time.Now().Add(-*sampleExpiry)
	for _, sample := range samples {
		if ageLimit.After(sample.Timestamp) {
			Log.Debug("skipping old sample", "limit", ageLimit, "sample", sample)
			continue
		}
		Log.Debug("sending sample", "sample", sample)
		ch <- prometheus.MustNewConstMetric(
			prometheus.NewDesc(sample.Name, sample.Help, []string{}, sample.Labels),
			sample.Type,
			sample.Value,
		)
	}
}

// Describe implements prometheus.Collector.
func (c *scollectorCollector) Describe(ch chan<- *prometheus.Desc) {
	ch <- lastProcessed.Desc()
}

var dotReplacer = strings.NewReplacer(".", "_")

func (c *scollectorCollector) handleScoll(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()
	sendErr := func(msg string, code int) {
		Log.Error(msg)
		http.Error(w, msg, code)
	}
	if r.Method != "POST" {
		sendErr("Only POST is allowed", http.StatusMethodNotAllowed)
		return
	}
	if r.Header.Get("Content-Type") != "application/json" {
		sendErr("Only application/json is allowed", http.StatusBadRequest)
		return
	}

	rdr := io.Reader(r.Body)
	if r.Header.Get("Content-Encoding") == "gzip" {
		var err error
		if rdr, err = gzip.NewReader(rdr); err != nil {
			sendErr("Not gzipped: "+err.Error(), http.StatusBadRequest)
			return
		}
	}
	var batch []opentsdb.DataPoint
	if err := json.NewDecoder(rdr).Decode(&batch); err != nil {
		sendErr("cannot decode JSON: "+err.Error(), http.StatusBadRequest)
		return
	}

	Log.Debug("batch", "size", len(batch))
	n := 0
	for _, m := range batch {
		Log.Debug("got", "msg", m)
		name := clearName(m.Metric, true, 'x')
		if name == "" {
			Log.Warn("bad metric name: " + m.Metric)
			continue
		}

		var v float64
		switch x := m.Value.(type) {
		case float64:
			v = x
		case int:
			v = float64(x)
		case int64:
			v = float64(x)
		case int32:
			v = float64(x)
		case string: // type info
			if x != "" {
				if z, ok := c.types[name]; !ok || z != x {
					c.types[name] = x
				}
			}
			continue
		default:
			Log.Warn("unknown value", "type", fmt.Sprintf("%T", m.Value), "msg", m)
			continue
		}
		typ := prometheus.GaugeValue
		if c.types[name] == "counter" {
			typ = prometheus.CounterValue
		}
		var ts time.Time
		if m.Timestamp >= 1e10 {
			ts = time.Unix(
				m.Timestamp&(1e10-1),
				int64(math.Mod(float64(m.Timestamp), 1e10))*int64(time.Millisecond))
		} else {
			ts = time.Unix(m.Timestamp, 0)
		}
		for k := range m.Tags {
			k2 := clearName(k, false, 'x')
			if k2 != "" && k2 != k {
				Log.Warn("bad label name " + k)
				m.Tags[k2] = m.Tags[k]
				delete(m.Tags, k)
			}
		}
		if m.Tags["host"] != "" {
			m.Tags["instance"] = m.Tags["host"]
			delete(m.Tags, "host")
		}
		c.ch <- scollectorSample{
			Name:      name,
			Labels:    m.Tags,
			Type:      typ,
			Help:      fmt.Sprintf("Scollector metric %s (%s)", m.Metric, c.types[name]),
			Value:     v,
			Timestamp: ts,
		}
		n++
	}
	lastProcessed.Set(float64(time.Now().UnixNano()) / 1e9)
	Log.Info("processed", "messages", n, "samples", len(c.samples), "types", len(c.types))

	w.WriteHeader(http.StatusNoContent)
}

var (
	flagAddr      = flag.String("http", "0.0.0.0:9107", "address to listen on")
	flagScollPref = flag.String("scollector.prefix", "/api/put", "HTTP path prefix for listening for scollector-sent data")
	flagVerbose   = flag.Bool("v", false, "verbose logging")
)

func main() {
	hndl := log15.CallerFileHandler(log15.StderrHandler)
	Log.SetHandler(hndl)

	flag.Parse()
	if !*flagVerbose {
		Log.SetHandler(log15.LvlFilterHandler(log15.LvlInfo, hndl))
	}

	c := newScollectorCollector()
	prometheus.MustRegister(c)

	http.HandleFunc(*flagScollPref, c.handleScoll)
	http.Handle("/metrics", prometheus.Handler())
	Log.Info("Serving on " + *flagAddr)
	http.ListenAndServe(*flagAddr, nil)
}

// clearName replaces non-allowed characters.
func clearName(txt string, allowColon bool, replaceRune rune) string {
	if replaceRune == 0 {
		replaceRune = -1
	}
	i := -1
	return strings.Map(
		func(r rune) rune {
			i++
			if r == '.' {
				return '_'
			}
			if 'a' <= r && r <= 'z' || 'A' <= r && r <= 'Z' || r == '_' {
				return r
			}
			if allowColon && r == ':' {
				return r
			}
			if i > 0 && '0' <= r && r <= '9' {
				return r
			}
			return replaceRune
		},
		txt)
}
<|endoftext|>


<commit_before>// A command line tool that shows the status of (many) Go packages.
package main

import (
	"flag"
	"fmt"
	"os"
	"runtime"
	"sync"

	"github.com/kisielk/gotool"
	"github.com/shurcooL/gostatus/status"

	"github.com/shurcooL/go/gists/gist7480523"
	"github.com/shurcooL/go/gists/gist7651991"
	"github.com/shurcooL/go/gists/gist7802150"
)

const numWorkers = 8

var vFlag = flag.Bool("v", false, "Verbose output: show all Go packages, not just ones with notable status.")
var stdinFlag = flag.Bool("stdin", false, "Read the list of newline separated Go packages from stdin.")
var plumbingFlag = flag.Bool("plumbing", false, "Give the output in an easy-to-parse format for scripts.")
var debugFlag = flag.Bool("debug", false, "Give the output with verbose debug information.")

func usage() {
	fmt.Fprint(os.Stderr, "Usage: gostatus [flags] [packages]\n")
	fmt.Fprint(os.Stderr, "       [newline separated packages] | gostatus --stdin [flags]\n")
	flag.PrintDefaults()
	fmt.Fprint(os.Stderr, `
Examples:
  # Show status of package in current directory, if notable.
  gostatus .

  # Show status of all packages with notable status.
  gostatus all

  # Show status of all dependencies (recursive) of package in cur working dir.
  go list -f '{{join .Deps "\n"}}' . | gostatus --stdin -v

Legend:
  ???? - Not under (recognized) version control
  b - Non-master branch checked out
  * - Uncommited changes in working dir
  + - Update available
  - - Local revision is ahead of remote (need to push?)
  ! - No remote
  # - Remote path doesn't match import path
  $ - Stash exists
`)
	os.Exit(2)
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	flag.Usage = usage
	flag.Parse()

	// Get current directory.
	wd, err := os.Getwd()
	if err != nil {
		panic(err)
	}

	shouldShow := func(goPackage *gist7480523.GoPackage) bool {
		// Check for notable status.
		return status.PorcelainPresenter(goPackage)[:4] != "    "
	}
	if *vFlag == true {
		shouldShow = func(_ *gist7480523.GoPackage) bool { return true }
	}

	var presenter gist7480523.GoPackageStringer = status.PorcelainPresenter
	if *debugFlag == true {
		presenter = status.DebugPresenter
	} else if *plumbingFlag == true {
		presenter = status.PlumbingPresenter
	}

	// A map of repos that have been checked, to avoid doing same repo more than once.
	var lock sync.Mutex
	checkedRepos := map[string]bool{}

	// Input: Go package Import Path
	// Output: If a valid Go package and not part of standard library, output a status string, else nil.
	reduceFunc := func(in string) interface{} {
		goPackage := gist7480523.GoPackageFromPath(in, wd)
		if goPackage == nil {
			return nil
		}
		if goPackage.Standard {
			return nil
		}

		goPackage.UpdateVcs()
		// Check that the same repo hasn't already been done.
		if goPackage.Dir.Repo != nil {
			rootPath := goPackage.Dir.Repo.Vcs.RootPath()
			lock.Lock()
			if !checkedRepos[rootPath] {
				checkedRepos[rootPath] = true
				lock.Unlock()
			} else {
				lock.Unlock()
				// Skip repos that were done.
				return nil
			}
		}

		if goPackage.Dir.Repo != nil {
			gist7802150.MakeUpdated(goPackage.Dir.Repo.VcsLocal)
			gist7802150.MakeUpdated(goPackage.Dir.Repo.VcsRemote)
		}

		if shouldShow(goPackage) == false {
			return nil
		}
		return presenter(goPackage)
	}

	// Run reduceFunc on all import paths in parallel.
	var outChan <-chan interface{}
	switch *stdinFlag {
	case false:
		importPathPatterns := flag.Args()
		if len(importPathPatterns) == 0 {
			importPathPatterns = []string{"."}
		}
		importPaths := gotool.ImportPaths(importPathPatterns)
		outChan = gist7651991.GoReduceLinesFromSlice(importPaths, numWorkers, reduceFunc)
	case true:
		outChan = gist7651991.GoReduceLinesFromReader(os.Stdin, numWorkers, reduceFunc)
	}

	// Output results.
	for out := range outChan {
		fmt.Println(out.(string))
	}
}
<commit_msg>Print "can't load package" message if invalid Go package is supplied.<commit_after>// A command line tool that shows the status of (many) Go packages.
package main

import (
	"flag"
	"fmt"
	"os"
	"runtime"
	"sync"

	"github.com/kisielk/gotool"
	"github.com/shurcooL/gostatus/status"

	"github.com/shurcooL/go/gists/gist7480523"
	"github.com/shurcooL/go/gists/gist7651991"
	"github.com/shurcooL/go/gists/gist7802150"
)

const numWorkers = 8

var vFlag = flag.Bool("v", false, "Verbose output: show all Go packages, not just ones with notable status.")
var stdinFlag = flag.Bool("stdin", false, "Read the list of newline separated Go packages from stdin.")
var plumbingFlag = flag.Bool("plumbing", false, "Give the output in an easy-to-parse format for scripts.")
var debugFlag = flag.Bool("debug", false, "Give the output with verbose debug information.")

func usage() {
	fmt.Fprint(os.Stderr, "Usage: gostatus [flags] [packages]\n")
	fmt.Fprint(os.Stderr, "       [newline separated packages] | gostatus --stdin [flags]\n")
	flag.PrintDefaults()
	fmt.Fprint(os.Stderr, `
Examples:
  # Show status of package in current directory, if notable.
  gostatus .

  # Show status of all packages with notable status.
  gostatus all

  # Show status of all dependencies (recursive) of package in cur working dir.
  go list -f '{{join .Deps "\n"}}' . | gostatus --stdin -v

Legend:
  ???? - Not under (recognized) version control
  b - Non-master branch checked out
  * - Uncommited changes in working dir
  + - Update available
  - - Local revision is ahead of remote (need to push?)
  ! - No remote
  # - Remote path doesn't match import path
  $ - Stash exists
`)
	os.Exit(2)
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	flag.Usage = usage
	flag.Parse()

	// Get current directory.
	wd, err := os.Getwd()
	if err != nil {
		panic(err)
	}

	shouldShow := func(goPackage *gist7480523.GoPackage) bool {
		// Check for notable status.
		return status.PorcelainPresenter(goPackage)[:4] != "    "
	}
	if *vFlag == true {
		shouldShow = func(_ *gist7480523.GoPackage) bool { return true }
	}

	var presenter gist7480523.GoPackageStringer = status.PorcelainPresenter
	if *debugFlag == true {
		presenter = status.DebugPresenter
	} else if *plumbingFlag == true {
		presenter = status.PlumbingPresenter
	}

	// A map of repos that have been checked, to avoid doing same repo more than once.
	var lock sync.Mutex
	checkedRepos := map[string]bool{}

	// Input: Go package Import Path
	// Output: If a valid Go package and not part of standard library, output a status string, else nil.
	reduceFunc := func(in string) interface{} {
		goPackage, err := gist7480523.GoPackageFromPath(in, wd)
		if err != nil {
			fmt.Fprintf(os.Stderr, "can't load package: %s\n", err)
			return nil
		}
		if goPackage == nil {
			return nil
		}
		if goPackage.Standard {
			return nil
		}

		goPackage.UpdateVcs()
		// Check that the same repo hasn't already been done.
		if goPackage.Dir.Repo != nil {
			rootPath := goPackage.Dir.Repo.Vcs.RootPath()
			lock.Lock()
			if !checkedRepos[rootPath] {
				checkedRepos[rootPath] = true
				lock.Unlock()
			} else {
				lock.Unlock()
				// Skip repos that were done.
				return nil
			}
		}

		if goPackage.Dir.Repo != nil {
			gist7802150.MakeUpdated(goPackage.Dir.Repo.VcsLocal)
			gist7802150.MakeUpdated(goPackage.Dir.Repo.VcsRemote)
		}

		if shouldShow(goPackage) == false {
			return nil
		}
		return presenter(goPackage)
	}

	// Run reduceFunc on all import paths in parallel.
	var outChan <-chan interface{}
	switch *stdinFlag {
	case false:
		importPathPatterns := flag.Args()
		if len(importPathPatterns) == 0 {
			importPathPatterns = []string{"."}
		}
		importPaths := gotool.ImportPaths(importPathPatterns)
		outChan = gist7651991.GoReduceLinesFromSlice(importPaths, numWorkers, reduceFunc)
	case true:
		outChan = gist7651991.GoReduceLinesFromReader(os.Stdin, numWorkers, reduceFunc)
	}

	// Output results.
	for out := range outChan {
		fmt.Println(out.(string))
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/sha1"
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"html"
	"io"
	"io/ioutil"
	"log"
	"net/http"

	"github.com/dchest/uniuri"
	"github.com/ewhal/pygments"
	"github.com/gorilla/mux"
	_ "github.com/mattn/go-sqlite3"
)

const (
	ADDRESS = "http://localhost:9900"
	LENGTH  = 6
	TEXT    = "$ <command> | curl -F 'p=<-' " + ADDRESS + "\n"
	PORT    = ":9900"
)

type Response struct {
	ID     string `json:"id"`
	HASH   string `json:"hash"`
	URL    string `json:"url"`
	SIZE   int    `json:"size"`
	DELKEY string `json:"delkey"`
}

func check(err error) {
	if err != nil {
		fmt.Println(err)
	}
}

func generateName() string {
	s := uniuri.NewLen(LENGTH)
	db, err := sql.Open("sqlite3", "./database.db")
	check(err)

	query, err := db.Query("select id from pastebin")
	for query.Next() {
		var id string
		err := query.Scan(&id)
		if err != nil {

		}
		if id == s {
			generateName()
		}
	}
	db.Close()

	return s

}
func hash(paste []byte) string {
	hasher := sha1.New()
	hasher.Write(paste)
	sha := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
	return sha
}

func save(raw []byte) []string {
	p := raw[86 : len(raw)-46]

	db, err := sql.Open("sqlite3", "./database.db")
	check(err)

	sha := hash(p)
	id := generateName()
	url := ADDRESS + "/p/" + id
	delKey := uniuri.NewLen(40)
	paste := html.EscapeString(string(p))

	stmt, err := db.Prepare("INSERT INTO pastebin(id, hash, data, delkey) values(?,?,?,?)")
	check(err)
	_, err = stmt.Exec(id, sha, paste, delKey)
	check(err)
	db.Close()
	return []string{id, sha, url, paste, delKey}

}

func delHandler(w http.ResponseWriter, r *http.Request) {
}
func saveHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	output := vars["output"]
	switch r.Method {
	case "POST":
		buf, err := ioutil.ReadAll(r.Body)
		if err != nil {
			http.Error(w, err.Error(), 500)
		}

		values := save(buf)

		switch output {
		case "json":
			b := &Response{
				ID:     values[0],
				HASH:   values[1],
				URL:    values[2],
				SIZE:   len(values[3]),
				DELKEY: values[4],
			}

			w.Header().Set("Content-Type", "application/json")
			err := json.NewEncoder(w).Encode(b)

			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

		default:
			io.WriteString(w, values[2]+"\n")
		}
	}

}

func rootHandler(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, TEXT)
}
func langHandler(w http.ResponseWriter, r *http.Request) {

	vars := mux.Vars(r)
	paste := vars["pasteId"]
	lang := vars["lang"]
	s := getPaste(paste)
	highlight := pygments.Highlight(html.UnescapeString(s), lang, "html", "full, style=autumn,linenos=True, lineanchors=True,anchorlinenos=True,", "utf-8")
	io.WriteString(w, highlight)

}

func getPaste(paste string) string {
	param1 := html.EscapeString(paste)
	db, err := sql.Open("sqlite3", "./database.db")
	var s string
	err = db.QueryRow("select data from pastebin where id=?", param1).Scan(&s)
	db.Close()
	check(err)

	if err == sql.ErrNoRows {
		return "Error invalid paste"
	} else {
		return html.UnescapeString(s)
	}

}
func pasteHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s := getPaste(paste)
	io.WriteString(w, s)

}

func main() {
	router := mux.NewRouter().StrictSlash(true)
	router.HandleFunc("/", rootHandler)
	router.HandleFunc("/p/{pasteId}", pasteHandler)
	router.HandleFunc("/p/{pasteId}/{lang}", langHandler)
	router.HandleFunc("/save", saveHandler)
	router.HandleFunc("/save/{output}", saveHandler)
	router.HandleFunc("/del/{pasteId}/{delKey}", delHandler)
	err := http.ListenAndServe(PORT, router)
	if err != nil {
		log.Fatal(err)
	}

}
<commit_msg>Add xml response<commit_after>package main

import (
	"crypto/sha1"
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"html"
	"io"
	"io/ioutil"
	"log"
	"net/http"

	"github.com/dchest/uniuri"
	"github.com/ewhal/pygments"
	"github.com/gorilla/mux"
	_ "github.com/mattn/go-sqlite3"
)

const (
	ADDRESS = "http://localhost:9900"
	LENGTH  = 6
	TEXT    = "$ <command> | curl -F 'p=<-' " + ADDRESS + "\n"
	PORT    = ":9900"
)

type Response struct {
	ID     string `json:"id"`
	HASH   string `json:"hash"`
	URL    string `json:"url"`
	SIZE   int    `json:"size"`
	DELKEY string `json:"delkey"`
}

func check(err error) {
	if err != nil {
		fmt.Println(err)
	}
}

func generateName() string {
	s := uniuri.NewLen(LENGTH)
	db, err := sql.Open("sqlite3", "./database.db")
	check(err)

	query, err := db.Query("select id from pastebin")
	for query.Next() {
		var id string
		err := query.Scan(&id)
		if err != nil {

		}
		if id == s {
			generateName()
		}
	}
	db.Close()

	return s

}
func hash(paste []byte) string {
	hasher := sha1.New()
	hasher.Write(paste)
	sha := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
	return sha
}

func save(raw []byte) []string {
	p := raw[86 : len(raw)-46]

	db, err := sql.Open("sqlite3", "./database.db")
	check(err)

	sha := hash(p)
	id := generateName()
	url := ADDRESS + "/p/" + id
	delKey := uniuri.NewLen(40)
	paste := html.EscapeString(string(p))

	stmt, err := db.Prepare("INSERT INTO pastebin(id, hash, data, delkey) values(?,?,?,?)")
	check(err)
	_, err = stmt.Exec(id, sha, paste, delKey)
	check(err)
	db.Close()
	return []string{id, sha, url, paste, delKey}

}

func delHandler(w http.ResponseWriter, r *http.Request) {
}
func saveHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	output := vars["output"]
	switch r.Method {
	case "POST":
		buf, err := ioutil.ReadAll(r.Body)
		if err != nil {
			http.Error(w, err.Error(), 500)
		}

		values := save(buf)
		b := &Response{
			ID:     values[0],
			HASH:   values[1],
			URL:    values[2],
			SIZE:   len(values[3]),
			DELKEY: values[4],
		}

		switch output {
		case "json":

			w.Header().Set("Content-Type", "application/json")
			err := json.NewEncoder(w).Encode(b)

			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		case "xml":
			x, err := xml.MarshalIndent(b, "", "  ")
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

			w.Header().Set("Content-Type", "application/xml")
			w.Write(x)

		default:
			io.WriteString(w, values[2]+"\n")
		}
	}

}

func rootHandler(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, TEXT)
}
func langHandler(w http.ResponseWriter, r *http.Request) {

	vars := mux.Vars(r)
	paste := vars["pasteId"]
	lang := vars["lang"]
	s := getPaste(paste)
	highlight := pygments.Highlight(html.UnescapeString(s), lang, "html", "full, style=autumn,linenos=True, lineanchors=True,anchorlinenos=True,", "utf-8")
	io.WriteString(w, highlight)

}

func getPaste(paste string) string {
	param1 := html.EscapeString(paste)
	db, err := sql.Open("sqlite3", "./database.db")
	var s string
	err = db.QueryRow("select data from pastebin where id=?", param1).Scan(&s)
	db.Close()
	check(err)

	if err == sql.ErrNoRows {
		return "Error invalid paste"
	} else {
		return html.UnescapeString(s)
	}

}
func pasteHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s := getPaste(paste)
	io.WriteString(w, s)

}

func main() {
	router := mux.NewRouter().StrictSlash(true)
	router.HandleFunc("/", rootHandler)
	router.HandleFunc("/p/{pasteId}", pasteHandler)
	router.HandleFunc("/p/{pasteId}/{lang}", langHandler)
	router.HandleFunc("/save", saveHandler)
	router.HandleFunc("/save/{output}", saveHandler)
	router.HandleFunc("/del/{pasteId}/{delKey}", delHandler)
	err := http.ListenAndServe(PORT, router)
	if err != nil {
		log.Fatal(err)
	}

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"

	"github.com/dtan4/ct2stimer/crontab"
	"github.com/dtan4/ct2stimer/systemd"
	flag "github.com/spf13/pflag"
)

var opts = struct {
	after      string
	filename   string
	nameRegexp string
	outdir     string
	reload     bool
}{}

func parseArgs(args []string) error {
	f := flag.NewFlagSet("ct2stimer", flag.ExitOnError)

	f.StringVar(&opts.filename, "after", "", "unit dependencies (After=)")
	f.StringVarP(&opts.filename, "file", "f", "", "crontab file")
	f.StringVar(&opts.nameRegexp, "name-regexp", "", "regexp to extract scheduler name from crontab")
	f.StringVarP(&opts.outdir, "outdir", "o", systemd.DefaultUnitsDirectory, "directory to save systemd files")
	f.BoolVar(&opts.reload, "reload", false, "reload & start genreated timers")

	f.Parse(args)

	if opts.filename == "" {
		return fmt.Errorf("Please specify crontab file.")
	}

	if opts.outdir == "" {
		return fmt.Errorf("Please specify directory to save systemd files.")
	}

	if _, err := os.Stat(opts.outdir); err != nil {
		if os.IsNotExist(err) {
			return fmt.Errorf("%s: directory does not exist", opts.outdir)
		}

		return err
	}

	return nil
}

func reloadSystemd(timers []string) error {
	conn, err := systemd.NewConn()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	defer conn.Close()

	client := systemd.NewClient(conn)

	if err := client.Reload(); err != nil {
		return err
	}

	for _, timerUnit := range timers {
		if err := client.StartUnit(timerUnit); err != nil {
			return err
		}
	}

	return nil
}

func main() {
	if err := parseArgs(os.Args[1:]); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	body, err := ioutil.ReadFile(opts.filename)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	schedules, err := crontab.Parse(string(body))
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	timers := []string{}

	for _, schedule := range schedules {
		calendar, err := schedule.ConvertToSystemdCalendar()
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}

		var name string

		if opts.nameRegexp != "" {
			re, err := regexp.Compile(opts.nameRegexp)
			if err != nil {
				fmt.Fprintln(os.Stderr, err)
				os.Exit(1)
			}

			name = schedule.NameByRegexp(re)
		}

		if name == "" {
			name = "cron-" + schedule.SHA256Sum()[0:12]
		}

		service, err := systemd.GenerateService(name, schedule.Command, opts.after)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}

		servicePath := filepath.Join(opts.outdir, name+".service")
		if err := ioutil.WriteFile(servicePath, []byte(service), 0644); err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}

		timer, err := systemd.GenerateTimer(name, calendar)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}

		timerPath := filepath.Join(opts.outdir, name+".timer")
		if err := ioutil.WriteFile(timerPath, []byte(timer), 0644); err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}

		timers = append(timers, name+".timer")
	}

	if opts.reload {
		if err := reloadSystemd(timers); err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
	}
}
<commit_msg>Modify --after variable<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"

	"github.com/dtan4/ct2stimer/crontab"
	"github.com/dtan4/ct2stimer/systemd"
	flag "github.com/spf13/pflag"
)

var opts = struct {
	after      string
	filename   string
	nameRegexp string
	outdir     string
	reload     bool
}{}

func parseArgs(args []string) error {
	f := flag.NewFlagSet("ct2stimer", flag.ExitOnError)

	f.StringVar(&opts.after, "after", "", "unit dependencies (After=)")
	f.StringVarP(&opts.filename, "file", "f", "", "crontab file")
	f.StringVar(&opts.nameRegexp, "name-regexp", "", "regexp to extract scheduler name from crontab")
	f.StringVarP(&opts.outdir, "outdir", "o", systemd.DefaultUnitsDirectory, "directory to save systemd files")
	f.BoolVar(&opts.reload, "reload", false, "reload & start genreated timers")

	f.Parse(args)

	if opts.filename == "" {
		return fmt.Errorf("Please specify crontab file.")
	}

	if opts.outdir == "" {
		return fmt.Errorf("Please specify directory to save systemd files.")
	}

	if _, err := os.Stat(opts.outdir); err != nil {
		if os.IsNotExist(err) {
			return fmt.Errorf("%s: directory does not exist", opts.outdir)
		}

		return err
	}

	return nil
}

func reloadSystemd(timers []string) error {
	conn, err := systemd.NewConn()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	defer conn.Close()

	client := systemd.NewClient(conn)

	if err := client.Reload(); err != nil {
		return err
	}

	for _, timerUnit := range timers {
		if err := client.StartUnit(timerUnit); err != nil {
			return err
		}
	}

	return nil
}

func main() {
	if err := parseArgs(os.Args[1:]); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	body, err := ioutil.ReadFile(opts.filename)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	schedules, err := crontab.Parse(string(body))
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	timers := []string{}

	for _, schedule := range schedules {
		calendar, err := schedule.ConvertToSystemdCalendar()
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}

		var name string

		if opts.nameRegexp != "" {
			re, err := regexp.Compile(opts.nameRegexp)
			if err != nil {
				fmt.Fprintln(os.Stderr, err)
				os.Exit(1)
			}

			name = schedule.NameByRegexp(re)
		}

		if name == "" {
			name = "cron-" + schedule.SHA256Sum()[0:12]
		}

		service, err := systemd.GenerateService(name, schedule.Command, opts.after)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}

		servicePath := filepath.Join(opts.outdir, name+".service")
		if err := ioutil.WriteFile(servicePath, []byte(service), 0644); err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}

		timer, err := systemd.GenerateTimer(name, calendar)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}

		timerPath := filepath.Join(opts.outdir, name+".timer")
		if err := ioutil.WriteFile(timerPath, []byte(timer), 0644); err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}

		timers = append(timers, name+".timer")
	}

	if opts.reload {
		if err := reloadSystemd(timers); err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strconv"

	"github.com/gorilla/mux"
	"github.com/tiltfactor/simish/domain"
	"github.com/tiltfactor/simish/impl"
	"github.com/tiltfactor/simish/test"
	"github.com/urfave/cli"
)

type inputData map[string]string

// App holds the db structure. Used for dep injection.
type App struct {
	db domain.InputOutputStore
}

type response struct {
	Input      string  `json:"input"`
	Response   string  `json:"response"`
	Match      string  `json:"match,omitempty"`
	Room       string  `json:"room"`
	Score      float64 `json:"score"`
	AiCol      int64   `json:"aiCol"`
	ResultType int64   `json:"resultType"`
}

func (r response) String() string {
	return fmt.Sprintf("Input: %s, Matched: %s, Score: %f, Response: %s, Room: %s",
		r.Input, r.Match, r.Score, r.Response, r.Room)
}

type rawData struct {
	Text  string `json:"text"`
	Reply string `json:"reply"`
}

// ResponseHandler handles the user request for a input output pair
func (a App) ResponseHandler(w http.ResponseWriter, r *http.Request) {
	vars := r.URL.Query()
	input := vars["input"]
	room := vars["room"]

	if len(room) < 1 {
		http.Error(w, "Must provide room number", 400)
		return
	}

	roomNumber, err := strconv.ParseInt(room[0], 10, 64)
	if err != nil {
		http.Error(w, "Room number must be an int", 400)
		return
	}

	io, score := a.db.Response(input[0], roomNumber)

	resp := response{
		Input:      input[0],
		Response:   io.Output,
		Match:      io.Input,
		Room:       room[0],
		Score:      score,
		AiCol:      io.AiCol,
		ResultType: io.ResultType,
	}

	log.Println(resp)

	data, err := json.Marshal(resp)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write(data)
}

// DBConfig is used to import the db_cfg.json file
type DBConfig struct {
	User       string `json:"username"`
	Pass       string `json:"password"`
	IP         string `json:"ip_addr"`
	Port       string `json:"db_port"`
	DB         string `json:"database"`
	ServerPort string `json:"server_port"`
}

func (cfg *DBConfig) connectionString() string {
	connStr := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s", cfg.User, cfg.Pass, cfg.IP, cfg.Port, cfg.DB)
	log.Println(connStr)
	return connStr
}

func startSimish(c *cli.Context) error {
	cfgFile, err := ioutil.ReadFile("./db_cfg.json")
	if err != nil {
		log.Fatal(err)
	}

	cfg := &DBConfig{}
	if err := json.Unmarshal(cfgFile, cfg); err != nil {
		log.Fatal(err)
	}

	store, err := impl.NewSQLStore(cfg.connectionString())
	if err != nil {
		log.Fatal(err)
	}

	app := App{db: store}

	r := mux.NewRouter()

	// Routes consist of a path and a handler function.
	r.HandleFunc("/api/v1/response", app.ResponseHandler)

	// Bind to a port and pass our router in
	log.Println("Running on port:", cfg.ServerPort)

	logFile, err := os.OpenFile("logs", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		log.Fatal("Could not open log file")
	}
	defer logFile.Close()
	log.SetOutput(logFile)
	if err := http.ListenAndServe(":"+cfg.ServerPort, r); err != nil {
		log.Fatal(err)
	}
	return nil
}

func readInput(prompt string) string {
	scan := bufio.NewScanner(os.Stdin)
	fmt.Print(prompt + " ")
	scan.Scan()
	return scan.Text()
}

func createCfg(c *cli.Context) error {

	fmt.Println("Follow along to create a db_cfg.")
	fmt.Println("Warning: This will overwrite existing db_cfg.json file")

	f, err := os.Create("./db_cfg.json")
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	serverPort := readInput("Port to run Simish on:")
	user := readInput("MySQL database username:")
	pass := readInput("MySQL database password:")
	ip := readInput("MySQL database IP address:")
	port := readInput("MySQL database port:")
	db := readInput("MySQL database name:")

	cfg := DBConfig{
		ServerPort: serverPort,
		User:       user,
		Pass:       pass,
		IP:         ip,
		DB:         db,
		Port:       port,
	}

	cm, err := json.MarshalIndent(&cfg, "", "  ")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println()
	fmt.Println(string(cm))
	w := bufio.NewWriter(f)
	if _, err := w.Write(cm); err != nil {
		log.Fatal(err)
	}
	w.Flush()
	fmt.Println("Successfully created db_cfg.json")

	return nil
}

func runTest(c *cli.Context) {
	cfgFile, err := ioutil.ReadFile("./db_cfg.json")
	if err != nil {
		log.Fatal(err)
	}

	cfg := &DBConfig{}
	if err := json.Unmarshal(cfgFile, cfg); err != nil {
		log.Fatal(err)
	}

	store, err := impl.NewSQLStore(cfg.connectionString())
	if err != nil {
		log.Fatal(err)
	}

	pairs := store.GetAllPairs(1)
	args := c.Args()
	if len(args) > 2 {
		log.Fatal("Too many arguments")
	}
	test.RunSoftMatch(args, pairs)
}

func main() {
	app := cli.NewApp()
	app.Name = "Simish"
	app.Usage = "Soft Matching Algorithm as a service"
	app.Version = "0.4.0"
	app.Commands = []cli.Command{
		{
			Name:   "init",
			Usage:  "Create db_cfg.json file",
			Action: createCfg,
		},
		{
			Name:   "start",
			Usage:  "Start the simish server",
			Action: startSimish,
		},
		{
			Name:   "test",
			Usage:  "Test the softmatch algorithm",
			Action: runTest,
		},
	}
	app.Run(os.Args)
}
<commit_msg>Bump simish version<commit_after>package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strconv"

	"github.com/gorilla/mux"
	"github.com/tiltfactor/simish/domain"
	"github.com/tiltfactor/simish/impl"
	"github.com/tiltfactor/simish/test"
	"github.com/urfave/cli"
)

type inputData map[string]string

// App holds the db structure. Used for dep injection.
type App struct {
	db domain.InputOutputStore
}

type response struct {
	Input      string  `json:"input"`
	Response   string  `json:"response"`
	Match      string  `json:"match,omitempty"`
	Room       string  `json:"room"`
	Score      float64 `json:"score"`
	AiCol      int64   `json:"aiCol"`
	ResultType int64   `json:"resultType"`
}

func (r response) String() string {
	return fmt.Sprintf("Input: %s, Matched: %s, Score: %f, Response: %s, Room: %s",
		r.Input, r.Match, r.Score, r.Response, r.Room)
}

type rawData struct {
	Text  string `json:"text"`
	Reply string `json:"reply"`
}

// ResponseHandler handles the user request for a input output pair
func (a App) ResponseHandler(w http.ResponseWriter, r *http.Request) {
	vars := r.URL.Query()
	input := vars["input"]
	room := vars["room"]

	if len(room) < 1 {
		http.Error(w, "Must provide room number", 400)
		return
	}

	roomNumber, err := strconv.ParseInt(room[0], 10, 64)
	if err != nil {
		http.Error(w, "Room number must be an int", 400)
		return
	}

	io, score := a.db.Response(input[0], roomNumber)

	resp := response{
		Input:      input[0],
		Response:   io.Output,
		Match:      io.Input,
		Room:       room[0],
		Score:      score,
		AiCol:      io.AiCol,
		ResultType: io.ResultType,
	}

	log.Println(resp)

	data, err := json.Marshal(resp)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write(data)
}

// DBConfig is used to import the db_cfg.json file
type DBConfig struct {
	User       string `json:"username"`
	Pass       string `json:"password"`
	IP         string `json:"ip_addr"`
	Port       string `json:"db_port"`
	DB         string `json:"database"`
	ServerPort string `json:"server_port"`
}

func (cfg *DBConfig) connectionString() string {
	connStr := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s", cfg.User, cfg.Pass, cfg.IP, cfg.Port, cfg.DB)
	log.Println(connStr)
	return connStr
}

func startSimish(c *cli.Context) error {
	cfgFile, err := ioutil.ReadFile("./db_cfg.json")
	if err != nil {
		log.Fatal(err)
	}

	cfg := &DBConfig{}
	if err := json.Unmarshal(cfgFile, cfg); err != nil {
		log.Fatal(err)
	}

	store, err := impl.NewSQLStore(cfg.connectionString())
	if err != nil {
		log.Fatal(err)
	}

	app := App{db: store}

	r := mux.NewRouter()

	// Routes consist of a path and a handler function.
	r.HandleFunc("/api/v1/response", app.ResponseHandler)

	// Bind to a port and pass our router in
	log.Println("Running on port:", cfg.ServerPort)

	logFile, err := os.OpenFile("logs", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		log.Fatal("Could not open log file")
	}
	defer logFile.Close()
	log.SetOutput(logFile)
	if err := http.ListenAndServe(":"+cfg.ServerPort, r); err != nil {
		log.Fatal(err)
	}
	return nil
}

func readInput(prompt string) string {
	scan := bufio.NewScanner(os.Stdin)
	fmt.Print(prompt + " ")
	scan.Scan()
	return scan.Text()
}

func createCfg(c *cli.Context) error {

	fmt.Println("Follow along to create a db_cfg.")
	fmt.Println("Warning: This will overwrite existing db_cfg.json file")

	f, err := os.Create("./db_cfg.json")
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	serverPort := readInput("Port to run Simish on:")
	user := readInput("MySQL database username:")
	pass := readInput("MySQL database password:")
	ip := readInput("MySQL database IP address:")
	port := readInput("MySQL database port:")
	db := readInput("MySQL database name:")

	cfg := DBConfig{
		ServerPort: serverPort,
		User:       user,
		Pass:       pass,
		IP:         ip,
		DB:         db,
		Port:       port,
	}

	cm, err := json.MarshalIndent(&cfg, "", "  ")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println()
	fmt.Println(string(cm))
	w := bufio.NewWriter(f)
	if _, err := w.Write(cm); err != nil {
		log.Fatal(err)
	}
	w.Flush()
	fmt.Println("Successfully created db_cfg.json")

	return nil
}

func runTest(c *cli.Context) {
	cfgFile, err := ioutil.ReadFile("./db_cfg.json")
	if err != nil {
		log.Fatal(err)
	}

	cfg := &DBConfig{}
	if err := json.Unmarshal(cfgFile, cfg); err != nil {
		log.Fatal(err)
	}

	store, err := impl.NewSQLStore(cfg.connectionString())
	if err != nil {
		log.Fatal(err)
	}

	pairs := store.GetAllPairs(1)
	args := c.Args()
	if len(args) > 2 {
		log.Fatal("Too many arguments")
	}
	test.RunSoftMatch(args, pairs)
}

func main() {
	app := cli.NewApp()
	app.Name = "Simish"
	app.Usage = "Soft Matching Algorithm as a service"
	app.Version = "0.5.0"
	app.Commands = []cli.Command{
		{
			Name:   "init",
			Usage:  "Create db_cfg.json file",
			Action: createCfg,
		},
		{
			Name:   "start",
			Usage:  "Start the simish server",
			Action: startSimish,
		},
		{
			Name:   "test",
			Usage:  "Test the softmatch algorithm",
			Action: runTest,
		},
	}
	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/jessevdk/go-flags"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"log"
	"net/http"
	"regexp"
	"strings"
	"sync"
	"time"
)

const (
	expectingVersion = "1.1.1 DISABLED"                                  // number being expected. must be changed manually (for now).
	changeURLBase    = "https://code.google.com/p/go/source/detail?r=go" // base url to poll the tag
	updateInterval   = 6 * time.Second                                   // Update interval for the expected number
)

var defaultPage = "http://isgo1point3.outyet.org"

var (
	versions     = make(map[string]*version) // map with all versions by number(string)
	versionsLock sync.RWMutex                // map lock
)

var regexpNumber = regexp.MustCompile(`^[1-9](?:\.[0-9]){0,2}$`)

var colVersions *mgo.Collection
var colNV *mgo.Collection

var options struct {
	Listen string `short:"l" long:"listen" default:"141.138.139.6:80" description:"IP:post to listen on"`
}

func main() {
	args, err := flags.Parse(&options)
	if err != nil {
		log.Fatalln(err)
	}
	if len(args) > 0 {
		log.Fatalln("Unexpected arguments.")
	}

	mgoSess, err := mgo.Dial("localhost")
	if err != nil {
		log.Fatalln(err)
	}
	colVersions = mgoSess.DB("outyet").C("versions")
	colVersions.EnsureIndex(mgo.Index{
		Key:      []string{"number"},
		Unique:   true,
		DropDups: true,
	})
	colNV = mgoSess.DB("outyet").C("namevalue")
	colNV.EnsureIndex(mgo.Index{
		Key:      []string{"name"},
		Unique:   true,
		DropDups: true,
	})

	if err := http.ListenAndServe(options.Listen, http.HandlerFunc(rootHandler)); err != nil {
		log.Fatalln(err)
	}
}

func rootHandler(w http.ResponseWriter, r *http.Request) {
	// handler for stats page
	if r.Host == "stats.outyet.org" {
		statsHandler(w, r)
		return
	}

	// redirect for 'old' domain
	if r.Host == "isgo1point2outyet.com" {
		http.Redirect(w, r, "http://isgo1point2.outyet.org", http.StatusTemporaryRedirect)
		return
	}

	// only handle requests on /
	if r.RequestURI != "/" {
		http.NotFound(w, r)
		return
	}

	// check if Host header matches isgo*.outyet.org
	if !strings.HasSuffix(r.Host, ".outyet.org") || !strings.HasPrefix(r.Host, "isgo") {
		log.Printf("Invalid host format detected. %s\n", r.Host)
		http.Redirect(w, r, defaultPage, http.StatusTemporaryRedirect)
		return
	}

	number := strings.Replace(r.Host[4:len(r.Host)-11], "point", ".", -1)
	log.Println(number)

	if !regexpNumber.MatchString(number) {
		http.Error(w, "invalid request format", http.StatusBadRequest)
		return
	}

	// get right version in a safe way
	o := getVersion(number)

	// add hitCount's
	colVersions.Upsert(bson.M{"number": o.number}, bson.M{"$inc": bson.M{"hits": 1}})
	colNV.Upsert(bson.M{"name": "counts"}, bson.M{"$inc": bson.M{"hits": 1}})

	// execute template
	data := dataOutyet{
		Outyet: <-o.isOutyetChan, //retrieve outyet directly from channel
		Number: number,
	}
	err := tmplOutyet.Execute(w, data)
	if err != nil {
		log.Print(err)
	}
}

func statsHandler(w http.ResponseWriter, r *http.Request) {
	data := &dataStats{}

	colNV.Find(bson.M{"name": "counts"}).One(data)
	colVersions.Find(nil).Sort("number").All(&data.Versions)

	for _, v := range data.Versions {
		// get outyet for given version number
		v.Outyet = <-getVersion(v.Number).isOutyetChan

		// add hitCount's
		colVersions.Upsert(bson.M{"number": v.Number}, bson.M{"$inc": bson.M{"hits": 1}})
	}

	err := tmplStats.Execute(w, data)
	if err != nil {
		log.Print(err)
	}
}
<commit_msg>Redirect x.0 to x<commit_after>package main

import (
	"github.com/jessevdk/go-flags"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"log"
	"net/http"
	"regexp"
	"strings"
	"sync"
	"time"
)

const (
	expectingVersion = "1.1.1 DISABLED"                                  // number being expected. must be changed manually (for now).
	changeURLBase    = "https://code.google.com/p/go/source/detail?r=go" // base url to poll the tag
	updateInterval   = 6 * time.Second                                   // Update interval for the expected number
)

var defaultPage = "http://isgo1point3.outyet.org"

var (
	versions     = make(map[string]*version) // map with all versions by number(string)
	versionsLock sync.RWMutex                // map lock
)

var regexpNumber = regexp.MustCompile(`^[1-9](?:\.[0-9]){0,2}$`)

var colVersions *mgo.Collection
var colNV *mgo.Collection

var options struct {
	Listen string `short:"l" long:"listen" default:"141.138.139.6:80" description:"IP:post to listen on"`
}

func main() {
	args, err := flags.Parse(&options)
	if err != nil {
		log.Fatalln(err)
	}
	if len(args) > 0 {
		log.Fatalln("Unexpected arguments.")
	}

	mgoSess, err := mgo.Dial("localhost")
	if err != nil {
		log.Fatalln(err)
	}
	colVersions = mgoSess.DB("outyet").C("versions")
	colVersions.EnsureIndex(mgo.Index{
		Key:      []string{"number"},
		Unique:   true,
		DropDups: true,
	})
	colNV = mgoSess.DB("outyet").C("namevalue")
	colNV.EnsureIndex(mgo.Index{
		Key:      []string{"name"},
		Unique:   true,
		DropDups: true,
	})

	if err := http.ListenAndServe(options.Listen, http.HandlerFunc(rootHandler)); err != nil {
		log.Fatalln(err)
	}
}

func rootHandler(w http.ResponseWriter, r *http.Request) {
	// handler for stats page
	if r.Host == "stats.outyet.org" {
		statsHandler(w, r)
		return
	}

	// redirect for 'old' domain
	if r.Host == "isgo1point2outyet.com" {
		http.Redirect(w, r, "http://isgo1point2.outyet.org", http.StatusTemporaryRedirect)
		return
	}

	// only handle requests on /
	if r.RequestURI != "/" {
		http.NotFound(w, r)
		return
	}

	// check if Host header matches isgo*.outyet.org
	if !strings.HasSuffix(r.Host, ".outyet.org") || !strings.HasPrefix(r.Host, "isgo") {
		log.Printf("Invalid host format detected. %s\n", r.Host)
		http.Redirect(w, r, defaultPage, http.StatusTemporaryRedirect)
		return
	}

	number := strings.Replace(r.Host[4:len(r.Host)-11], "point", ".", -1)
	log.Println(number)

	if !regexpNumber.MatchString(number) {
		http.Error(w, "invalid request format", http.StatusBadRequest)
		return
	}

	if strings.HasSuffix(number, ".0") {
		number = number[:len(number)-2]
		if len(number) > 0 {
			http.Redirect(w, r, "http://isgo"+strings.Replace(number, ".", "point", -1)+".outyet.org", code)
			return
		}
		http.Redirect(w, r, defaultPage, http.StatusTemporaryRedirect)
		return
	}

	// get right version in a safe way
	o := getVersion(number)

	// add hitCount's
	colVersions.Upsert(bson.M{"number": o.number}, bson.M{"$inc": bson.M{"hits": 1}})
	colNV.Upsert(bson.M{"name": "counts"}, bson.M{"$inc": bson.M{"hits": 1}})

	// execute template
	data := dataOutyet{
		Outyet: <-o.isOutyetChan, //retrieve outyet directly from channel
		Number: number,
	}
	err := tmplOutyet.Execute(w, data)
	if err != nil {
		log.Print(err)
	}
}

func statsHandler(w http.ResponseWriter, r *http.Request) {
	data := &dataStats{}

	colNV.Find(bson.M{"name": "counts"}).One(data)
	colVersions.Find(nil).Sort("number").All(&data.Versions)

	for _, v := range data.Versions {
		// get outyet for given version number
		v.Outyet = <-getVersion(v.Number).isOutyetChan

		// add hitCount's
		colVersions.Upsert(bson.M{"number": v.Number}, bson.M{"$inc": bson.M{"hits": 1}})
	}

	err := tmplStats.Execute(w, data)
	if err != nil {
		log.Print(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"log"
	"os"

	WardenClient "github.com/cloudfoundry-incubator/garden/client"
	WardenConnection "github.com/cloudfoundry-incubator/garden/client/connection"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/grouper"
	"github.com/tedsuo/ifrit/http_server"
	"github.com/tedsuo/ifrit/sigmon"
	"github.com/tedsuo/router"

	"github.com/winston-ci/prole/api"
	"github.com/winston-ci/prole/builder"
	"github.com/winston-ci/prole/config"
	"github.com/winston-ci/prole/resource"
	"github.com/winston-ci/prole/routes"
	"github.com/winston-ci/prole/scheduler"
	"github.com/winston-ci/prole/snapshotter"
)

var listenAddr = flag.String(
	"listenAddr",
	"0.0.0.0:4637",
	"listening address",
)

var peerAddr = flag.String(
	"peerAddr",
	"127.0.0.1:4637",
	"external address of the api server, used for callbacks",
)

var wardenNetwork = flag.String(
	"wardenNetwork",
	"unix",
	"warden API connection network (unix or tcp)",
)

var wardenAddr = flag.String(
	"wardenAddr",
	"/tmp/warden.sock",
	"warden API connection address",
)

var resourceTypes = flag.String(
	"resourceTypes",
	`{"git":"concourse/git-resource","raw":"concourse/raw-resource","docker-image":"concourse/docker-image-resource"}`,
	"map of resource type to its docker image",
)

var snapshotPath = flag.String(
	"snapshotPath",
	"/tmp/prole.json",
	"path to file to store/load snapshots from",
)

func main() {
	flag.Parse()

	wardenClient := WardenClient.New(&WardenConnection.Info{
		Network: *wardenNetwork,
		Addr:    *wardenAddr,
	})

	resourceTypesMap := map[string]string{}
	err := json.Unmarshal([]byte(*resourceTypes), &resourceTypesMap)
	if err != nil {
		log.Fatalln("failed to parse resource types:", err)
	}

	var resourceTypesConfig config.ResourceTypes
	for typ, image := range resourceTypesMap {
		resourceTypesConfig = append(resourceTypesConfig, config.ResourceType{
			Name:  typ,
			Image: image,
		})
	}

	resourceTracker := resource.NewTracker(resourceTypesConfig, wardenClient)

	builder := builder.NewBuilder(resourceTracker, wardenClient)

	scheduler := scheduler.NewScheduler(builder)

	generator := router.NewRequestGenerator("http://"+*peerAddr, routes.Routes)

	drain := make(chan struct{})

	handler, err := api.New(scheduler, resourceTracker, generator, drain)
	if err != nil {
		log.Fatalln("failed to initialize handler:", err)
	}

	group := grouper.EnvokeGroup(grouper.RunGroup{
		"api":         http_server.New(*listenAddr, handler),
		"snapshotter": snapshotter.NewSnapshotter(*snapshotPath, scheduler),
		"drainer": ifrit.RunFunc(func(signals <-chan os.Signal, ready chan<- struct{}) error {
			close(ready)
			<-signals
			close(drain)
			return nil
		}),
	})

	running := ifrit.Envoke(sigmon.New(group))

	log.Println("serving api on", *listenAddr)

	err = <-running.Wait()
	if err != nil {
		log.Println("exited with error:", err)
		os.Exit(1)
	}

	log.Println("exited")
}
<commit_msg>add time resource to defaults<commit_after>package main

import (
	"encoding/json"
	"flag"
	"log"
	"os"

	WardenClient "github.com/cloudfoundry-incubator/garden/client"
	WardenConnection "github.com/cloudfoundry-incubator/garden/client/connection"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/grouper"
	"github.com/tedsuo/ifrit/http_server"
	"github.com/tedsuo/ifrit/sigmon"
	"github.com/tedsuo/router"

	"github.com/winston-ci/prole/api"
	"github.com/winston-ci/prole/builder"
	"github.com/winston-ci/prole/config"
	"github.com/winston-ci/prole/resource"
	"github.com/winston-ci/prole/routes"
	"github.com/winston-ci/prole/scheduler"
	"github.com/winston-ci/prole/snapshotter"
)

var listenAddr = flag.String(
	"listenAddr",
	"0.0.0.0:4637",
	"listening address",
)

var peerAddr = flag.String(
	"peerAddr",
	"127.0.0.1:4637",
	"external address of the api server, used for callbacks",
)

var wardenNetwork = flag.String(
	"wardenNetwork",
	"unix",
	"warden API connection network (unix or tcp)",
)

var wardenAddr = flag.String(
	"wardenAddr",
	"/tmp/warden.sock",
	"warden API connection address",
)

var resourceTypes = flag.String(
	"resourceTypes",
	`{"git":"concourse/git-resource","raw":"concourse/raw-resource","docker-image":"concourse/docker-image-resource","time":"concourse/time-resource"}`,
	"map of resource type to its docker image",
)

var snapshotPath = flag.String(
	"snapshotPath",
	"/tmp/prole.json",
	"path to file to store/load snapshots from",
)

func main() {
	flag.Parse()

	wardenClient := WardenClient.New(&WardenConnection.Info{
		Network: *wardenNetwork,
		Addr:    *wardenAddr,
	})

	resourceTypesMap := map[string]string{}
	err := json.Unmarshal([]byte(*resourceTypes), &resourceTypesMap)
	if err != nil {
		log.Fatalln("failed to parse resource types:", err)
	}

	var resourceTypesConfig config.ResourceTypes
	for typ, image := range resourceTypesMap {
		resourceTypesConfig = append(resourceTypesConfig, config.ResourceType{
			Name:  typ,
			Image: image,
		})
	}

	resourceTracker := resource.NewTracker(resourceTypesConfig, wardenClient)

	builder := builder.NewBuilder(resourceTracker, wardenClient)

	scheduler := scheduler.NewScheduler(builder)

	generator := router.NewRequestGenerator("http://"+*peerAddr, routes.Routes)

	drain := make(chan struct{})

	handler, err := api.New(scheduler, resourceTracker, generator, drain)
	if err != nil {
		log.Fatalln("failed to initialize handler:", err)
	}

	group := grouper.EnvokeGroup(grouper.RunGroup{
		"api":         http_server.New(*listenAddr, handler),
		"snapshotter": snapshotter.NewSnapshotter(*snapshotPath, scheduler),
		"drainer": ifrit.RunFunc(func(signals <-chan os.Signal, ready chan<- struct{}) error {
			close(ready)
			<-signals
			close(drain)
			return nil
		}),
	})

	running := ifrit.Envoke(sigmon.New(group))

	log.Println("serving api on", *listenAddr)

	err = <-running.Wait()
	if err != nil {
		log.Println("exited with error:", err)
		os.Exit(1)
	}

	log.Println("exited")
}
<|endoftext|>