<commit_before>// Package udp implements a BitTorrent tracker via the UDP protocol as
// described in BEP 15.
package udp

import (
	"bytes"
	"context"
	"encoding/binary"
	"net"
	"sync"
	"time"

	"github.com/prometheus/client_golang/prometheus"

	"github.com/chihaya/chihaya/bittorrent"
	"github.com/chihaya/chihaya/frontend"
	"github.com/chihaya/chihaya/frontend/udp/bytepool"
)

func init() {
	prometheus.MustRegister(promResponseDurationMilliseconds)
	recordResponseDuration("action", nil, time.Second)
}

var promResponseDurationMilliseconds = prometheus.NewHistogramVec(
	prometheus.HistogramOpts{
		Name:    "chihaya_udp_response_duration_milliseconds",
		Help:    "The duration of time it takes to receive and write a response to an API request",
		Buckets: prometheus.ExponentialBuckets(9.375, 2, 10),
	},
	[]string{"action", "error"},
)

// recordResponseDuration records the duration of time to respond to a UDP
// Request in milliseconds .
func recordResponseDuration(action string, err error, duration time.Duration) {
	var errString string
	if err != nil {
		errString = err.Error()
	}

	promResponseDurationMilliseconds.
		WithLabelValues(action, errString).
		Observe(float64(duration.Nanoseconds()) / float64(time.Millisecond))
}

// Config represents all of the configurable options for a UDP BitTorrent
// Tracker.
type Config struct {
	Addr            string
	PrivateKey      string
	MaxClockSkew    time.Duration
	AllowIPSpoofing bool
}

// Frontend holds the state of a UDP BitTorrent Frontend.
type Frontend struct {
	socket  *net.UDPConn
	closing chan struct{}
	wg      sync.WaitGroup

	logic frontend.TrackerLogic
	Config
}

// NewFrontend allocates a new instance of a Frontend.
func NewFrontend(logic frontend.TrackerLogic, cfg Config) *Frontend {
	return &Frontend{
		closing: make(chan struct{}),
		logic:   logic,
		Config:  cfg,
	}
}

// Stop provides a thread-safe way to shutdown a currently running Frontend.
func (t *Frontend) Stop() {
	close(t.closing)
	t.socket.SetReadDeadline(time.Now())
	t.wg.Wait()
}

// ListenAndServe listens on the UDP network address t.Addr and blocks serving
// BitTorrent requests until t.Stop() is called or an error is returned.
func (t *Frontend) ListenAndServe() error {
	udpAddr, err := net.ResolveUDPAddr("udp", t.Addr)
	if err != nil {
		return err
	}

	t.socket, err = net.ListenUDP("udp", udpAddr)
	if err != nil {
		return err
	}
	defer t.socket.Close()

	pool := bytepool.New(2048, 2048)

	for {
		// Check to see if we need to shutdown.
		select {
		case <-t.closing:
			return nil
		default:
		}

		// Read a UDP packet into a reusable buffer.
		buffer := pool.Get()
		t.socket.SetReadDeadline(time.Now().Add(time.Second))
		n, addr, err := t.socket.ReadFromUDP(buffer)
		if err != nil {
			pool.Put(buffer)
			if netErr, ok := err.(net.Error); ok && netErr.Temporary() {
				// A temporary failure is not fatal; just pretend it never happened.
				continue
			}
			return err
		}

		// We got nothin'
		if n == 0 {
			pool.Put(buffer)
			continue
		}

		t.wg.Add(1)
		go func() {
			defer t.wg.Done()
			defer pool.Put(buffer)

			// Handle the request.
			start := time.Now()
			action, err := t.handleRequest(
				Request{buffer[:n], addr.IP},
				ResponseWriter{t.socket, addr},
			)
			recordResponseDuration(action, err, time.Since(start))
		}()
	}
}

// Request represents a UDP payload received by a Tracker.
type Request struct {
	Packet []byte
	IP     net.IP
}

// ResponseWriter implements the ability to respond to a Request via the
// io.Writer interface.
type ResponseWriter struct {
	socket *net.UDPConn
	addr   *net.UDPAddr
}

// Write implements the io.Writer interface for a ResponseWriter.
func (w ResponseWriter) Write(b []byte) (int, error) {
	w.socket.WriteToUDP(b, w.addr)
	return len(b), nil
}

// handleRequest parses and responds to a UDP Request.
func (t *Frontend) handleRequest(r Request, w ResponseWriter) (actionName string, err error) {
	if len(r.Packet) < 16 {
		// Malformed, no client packets are less than 16 bytes.
		// We explicitly return nothing in case this is a DoS attempt.
		err = errMalformedPacket
		return
	}

	// Parse the headers of the UDP packet.
	connID := r.Packet[0:8]
	actionID := binary.BigEndian.Uint32(r.Packet[8:12])
	txID := r.Packet[12:16]

	// If this isn't requesting a new connection ID and the connection ID is
	// invalid, then fail.
	if actionID != connectActionID && !ValidConnectionID(connID, r.IP, time.Now(), t.MaxClockSkew, t.PrivateKey) {
		err = errBadConnectionID
		WriteError(w, txID, err)
		return
	}

	// Handle the requested action.
	switch actionID {
	case connectActionID:
		actionName = "connect"

		if !bytes.Equal(connID, initialConnectionID) {
			err = errMalformedPacket
			return
		}

		WriteConnectionID(w, txID, NewConnectionID(r.IP, time.Now(), t.PrivateKey))
		return

	case announceActionID:
		actionName = "announce"

		var req *bittorrent.AnnounceRequest
		req, err = ParseAnnounce(r, t.AllowIPSpoofing)
		if err != nil {
			WriteError(w, txID, err)
			return
		}

		var resp *bittorrent.AnnounceResponse
		resp, err = t.logic.HandleAnnounce(context.Background(), req)
		if err != nil {
			WriteError(w, txID, err)
			return
		}

		WriteAnnounce(w, txID, resp)

		go t.logic.AfterAnnounce(context.Background(), req, resp)

		return

	case scrapeActionID:
		actionName = "scrape"

		var req *bittorrent.ScrapeRequest
		req, err = ParseScrape(r)
		if err != nil {
			WriteError(w, txID, err)
			return
		}

		var resp *bittorrent.ScrapeResponse
		resp, err = t.logic.HandleScrape(context.Background(), req)
		if err != nil {
			WriteError(w, txID, err)
			return
		}

		WriteScrape(w, txID, resp)

		go t.logic.AfterScrape(context.Background(), req, resp)

		return

	default:
		err = errUnknownAction
		WriteError(w, txID, err)
		return
	}
}
<commit_msg>udp: remove unnecessary returns in switch stmt<commit_after>// Package udp implements a BitTorrent tracker via the UDP protocol as
// described in BEP 15.
package udp

import (
	"bytes"
	"context"
	"encoding/binary"
	"net"
	"sync"
	"time"

	"github.com/prometheus/client_golang/prometheus"

	"github.com/chihaya/chihaya/bittorrent"
	"github.com/chihaya/chihaya/frontend"
	"github.com/chihaya/chihaya/frontend/udp/bytepool"
)

func init() {
	prometheus.MustRegister(promResponseDurationMilliseconds)
	recordResponseDuration("action", nil, time.Second)
}

var promResponseDurationMilliseconds = prometheus.NewHistogramVec(
	prometheus.HistogramOpts{
		Name:    "chihaya_udp_response_duration_milliseconds",
		Help:    "The duration of time it takes to receive and write a response to an API request",
		Buckets: prometheus.ExponentialBuckets(9.375, 2, 10),
	},
	[]string{"action", "error"},
)

// recordResponseDuration records the duration of time to respond to a UDP
// Request in milliseconds .
func recordResponseDuration(action string, err error, duration time.Duration) {
	var errString string
	if err != nil {
		errString = err.Error()
	}

	promResponseDurationMilliseconds.
		WithLabelValues(action, errString).
		Observe(float64(duration.Nanoseconds()) / float64(time.Millisecond))
}

// Config represents all of the configurable options for a UDP BitTorrent
// Tracker.
type Config struct {
	Addr            string
	PrivateKey      string
	MaxClockSkew    time.Duration
	AllowIPSpoofing bool
}

// Frontend holds the state of a UDP BitTorrent Frontend.
type Frontend struct {
	socket  *net.UDPConn
	closing chan struct{}
	wg      sync.WaitGroup

	logic frontend.TrackerLogic
	Config
}

// NewFrontend allocates a new instance of a Frontend.
func NewFrontend(logic frontend.TrackerLogic, cfg Config) *Frontend {
	return &Frontend{
		closing: make(chan struct{}),
		logic:   logic,
		Config:  cfg,
	}
}

// Stop provides a thread-safe way to shutdown a currently running Frontend.
func (t *Frontend) Stop() {
	close(t.closing)
	t.socket.SetReadDeadline(time.Now())
	t.wg.Wait()
}

// ListenAndServe listens on the UDP network address t.Addr and blocks serving
// BitTorrent requests until t.Stop() is called or an error is returned.
func (t *Frontend) ListenAndServe() error {
	udpAddr, err := net.ResolveUDPAddr("udp", t.Addr)
	if err != nil {
		return err
	}

	t.socket, err = net.ListenUDP("udp", udpAddr)
	if err != nil {
		return err
	}
	defer t.socket.Close()

	pool := bytepool.New(2048, 2048)

	for {
		// Check to see if we need to shutdown.
		select {
		case <-t.closing:
			return nil
		default:
		}

		// Read a UDP packet into a reusable buffer.
		buffer := pool.Get()
		t.socket.SetReadDeadline(time.Now().Add(time.Second))
		n, addr, err := t.socket.ReadFromUDP(buffer)
		if err != nil {
			pool.Put(buffer)
			if netErr, ok := err.(net.Error); ok && netErr.Temporary() {
				// A temporary failure is not fatal; just pretend it never happened.
				continue
			}
			return err
		}

		// We got nothin'
		if n == 0 {
			pool.Put(buffer)
			continue
		}

		t.wg.Add(1)
		go func() {
			defer t.wg.Done()
			defer pool.Put(buffer)

			// Handle the request.
			start := time.Now()
			action, err := t.handleRequest(
				Request{buffer[:n], addr.IP},
				ResponseWriter{t.socket, addr},
			)
			recordResponseDuration(action, err, time.Since(start))
		}()
	}
}

// Request represents a UDP payload received by a Tracker.
type Request struct {
	Packet []byte
	IP     net.IP
}

// ResponseWriter implements the ability to respond to a Request via the
// io.Writer interface.
type ResponseWriter struct {
	socket *net.UDPConn
	addr   *net.UDPAddr
}

// Write implements the io.Writer interface for a ResponseWriter.
func (w ResponseWriter) Write(b []byte) (int, error) {
	w.socket.WriteToUDP(b, w.addr)
	return len(b), nil
}

// handleRequest parses and responds to a UDP Request.
func (t *Frontend) handleRequest(r Request, w ResponseWriter) (actionName string, err error) {
	if len(r.Packet) < 16 {
		// Malformed, no client packets are less than 16 bytes.
		// We explicitly return nothing in case this is a DoS attempt.
		err = errMalformedPacket
		return
	}

	// Parse the headers of the UDP packet.
	connID := r.Packet[0:8]
	actionID := binary.BigEndian.Uint32(r.Packet[8:12])
	txID := r.Packet[12:16]

	// If this isn't requesting a new connection ID and the connection ID is
	// invalid, then fail.
	if actionID != connectActionID && !ValidConnectionID(connID, r.IP, time.Now(), t.MaxClockSkew, t.PrivateKey) {
		err = errBadConnectionID
		WriteError(w, txID, err)
		return
	}

	// Handle the requested action.
	switch actionID {
	case connectActionID:
		actionName = "connect"

		if !bytes.Equal(connID, initialConnectionID) {
			err = errMalformedPacket
			return
		}

		WriteConnectionID(w, txID, NewConnectionID(r.IP, time.Now(), t.PrivateKey))

	case announceActionID:
		actionName = "announce"

		var req *bittorrent.AnnounceRequest
		req, err = ParseAnnounce(r, t.AllowIPSpoofing)
		if err != nil {
			WriteError(w, txID, err)
			return
		}

		var resp *bittorrent.AnnounceResponse
		resp, err = t.logic.HandleAnnounce(context.Background(), req)
		if err != nil {
			WriteError(w, txID, err)
			return
		}

		WriteAnnounce(w, txID, resp)

		go t.logic.AfterAnnounce(context.Background(), req, resp)

	case scrapeActionID:
		actionName = "scrape"

		var req *bittorrent.ScrapeRequest
		req, err = ParseScrape(r)
		if err != nil {
			WriteError(w, txID, err)
			return
		}

		var resp *bittorrent.ScrapeResponse
		resp, err = t.logic.HandleScrape(context.Background(), req)
		if err != nil {
			WriteError(w, txID, err)
			return
		}

		WriteScrape(w, txID, resp)

		go t.logic.AfterScrape(context.Background(), req, resp)

	default:
		err = errUnknownAction
		WriteError(w, txID, err)
	}

	return
}
<|endoftext|>


<commit_before>package servers

import (
	"encoding/json"
	"errors"
	"github.com/gorilla/mux"
	"github.com/hawkingrei/G53/utils"
	"net"
	"net/http"
	"regexp"
)

// HTTPServer represents the http endpoint
type HTTPServer struct {
	config *utils.Config
	list   ServiceListProvider
	server *http.Server
}

// NewHTTPServer create a new http endpoint
func NewHTTPServer(c *utils.Config, list ServiceListProvider) *HTTPServer {
	s := &HTTPServer{
		config: c,
		list:   list,
	}

	router := mux.NewRouter()
	router.HandleFunc("/services", s.getServices).Methods("GET")
	router.HandleFunc("/services/{id}", s.getService).Methods("GET")
	router.HandleFunc("/services", s.addService).Methods("PUT")
	router.HandleFunc("/services/{id}", s.updateService).Methods("PATCH")
	router.HandleFunc("/services/{id}", s.removeService).Methods("DELETE")
	router.HandleFunc("/set/ttl", s.setTTL).Methods("PUT")

	s.server = &http.Server{Addr: c.HttpAddr, Handler: router}

	return s
}

// Start starts the http endpoint
func (s *HTTPServer) Start() error {
	return s.server.ListenAndServe()
}

func (s *HTTPServer) getServices(w http.ResponseWriter, req *http.Request) {

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	json.NewEncoder(w).Encode(s.list.GetAllServices())
}

func (s *HTTPServer) getService(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	w.Header().Set("Content-Type", "application/json; charset=UTF-8")

	id, ok := vars["id"]
	if !ok {
		http.Error(w, "ID required", http.StatusBadRequest)
		return
	}

	service, err := s.list.GetService(id)
	if err != nil {
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}

	json.NewEncoder(w).Encode(service)
}

func (s *HTTPServer) addService(w http.ResponseWriter, req *http.Request) {
	service := NewService()
	if err := json.NewDecoder(req.Body).Decode(&service); err != nil {
		logger.Errorf("JSON decoding error: %s", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if err := s.validation(service); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	s.list.AddService(service.Aliases, *service)
}

func (s *HTTPServer) removeService(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)

	id, ok := vars["id"]
	if !ok {
		http.Error(w, "ID required", http.StatusBadRequest)
		return
	}

	if err := s.list.RemoveService(id); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
	}

}

func (s *HTTPServer) updateService(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)

	id, ok := vars["id"]
	if !ok {
		http.Error(w, "ID required", http.StatusBadRequest)
		return
	}

	service, err := s.list.GetService(id)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	if err := json.NewDecoder(req.Body).Decode(&service); err != nil {
		logger.Errorf("JSON decoding error: %s", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if err := s.validation(&service); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// todo: this probably needs to be moved. consider stop event in the
	// middle of sending PATCH. container would not be removed.
	s.list.AddService(id, service)

}

func (s *HTTPServer) setTTL(w http.ResponseWriter, req *http.Request) {
	var value int
	if err := json.NewDecoder(req.Body).Decode(&value); err != nil {
		logger.Errorf("Decoding error: %s", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	s.config.Ttl = value

}

func (s *HTTPServer) validation(service *Service) error {
	err := validateDomainType(service)
	if err != nil {
		return err
	}
	err = validateDomainValue(service)
	if err != nil {
		return err
	}
	return nil
}
func validateDomainType(service *Service) error {
	switch service.RecordType {
	case "A":
		if net.ParseIP(service.Value) == nil {
			logger.Debugf("Property \"Value\" is NOT IP")
			return errors.New("Property \"Value\" is NOT IP")
		}
	case "CNAME":
		if !validateDomainName(service.Value) {
			return errors.New("Property \"Value\" is wrong")
		}
	default:
		return errors.New("Property \"Record type\" is required or wrong")
	}
	return nil
}

func validateDomainValue(service *Service) error {
	if service.Aliases == "" {
		logger.Debugf("Property \"Aliases\" is required")
		return errors.New("Property \"Aliases\" is required")
	}
	if service.TTL <= 0 {
		logger.Debugf("Property \"TTL\" is required")
		return errors.New("Property \"TTL\" is required")
	}
	return nil
}

func validateDomainName(domain string) bool {
	RegExp := regexp.MustCompile(`^(([a-zA-Z]{1})|([a-zA-Z]{1}[a-zA-Z]{1})|([a-zA-Z]{1}[0-9]{1})|([0-9]{1}[a-zA-Z]{1})|([a-zA-Z0-9][a-zA-Z0-9-_]{1,61}[a-zA-Z0-9]))\.([a-zA-Z]{2,6}|[a-zA-Z0-9-]{2,30}\.[a-zA-Z
 ]{2,3})$`)
	return RegExp.MatchString(domain)
}
<commit_msg>style: remove useless error<commit_after>package servers

import (
	"encoding/json"
	"errors"
	"github.com/gorilla/mux"
	"github.com/hawkingrei/G53/utils"
	"net"
	"net/http"
	"regexp"
)

// HTTPServer represents the http endpoint
type HTTPServer struct {
	config *utils.Config
	list   ServiceListProvider
	server *http.Server
}

// NewHTTPServer create a new http endpoint
func NewHTTPServer(c *utils.Config, list ServiceListProvider) *HTTPServer {
	s := &HTTPServer{
		config: c,
		list:   list,
	}

	router := mux.NewRouter()
	router.HandleFunc("/services", s.getServices).Methods("GET")
	router.HandleFunc("/services/{id}", s.getService).Methods("GET")
	router.HandleFunc("/services", s.addService).Methods("PUT")
	router.HandleFunc("/services/{id}", s.updateService).Methods("PATCH")
	router.HandleFunc("/services/{id}", s.removeService).Methods("DELETE")
	router.HandleFunc("/set/ttl", s.setTTL).Methods("PUT")

	s.server = &http.Server{Addr: c.HttpAddr, Handler: router}

	return s
}

// Start starts the http endpoint
func (s *HTTPServer) Start() error {
	return s.server.ListenAndServe()
}

func (s *HTTPServer) getServices(w http.ResponseWriter, req *http.Request) {

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	json.NewEncoder(w).Encode(s.list.GetAllServices())
}

func (s *HTTPServer) getService(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	w.Header().Set("Content-Type", "application/json; charset=UTF-8")

	id, _ := vars["id"]

	service, err := s.list.GetService(id)
	if err != nil {
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}

	json.NewEncoder(w).Encode(service)
}

func (s *HTTPServer) addService(w http.ResponseWriter, req *http.Request) {
	service := NewService()
	if err := json.NewDecoder(req.Body).Decode(&service); err != nil {
		logger.Errorf("JSON decoding error: %s", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if err := s.validation(service); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	s.list.AddService(service.Aliases, *service)
}

func (s *HTTPServer) removeService(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)

	id, _ := vars["id"]

	if err := s.list.RemoveService(id); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
	}

}

func (s *HTTPServer) updateService(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)

	id, _ := vars["id"]

	service, err := s.list.GetService(id)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	if err := json.NewDecoder(req.Body).Decode(&service); err != nil {
		logger.Errorf("JSON decoding error: %s", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if err := s.validation(&service); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// todo: this probably needs to be moved. consider stop event in the
	// middle of sending PATCH. container would not be removed.
	s.list.AddService(id, service)

}

func (s *HTTPServer) setTTL(w http.ResponseWriter, req *http.Request) {
	var value int
	if err := json.NewDecoder(req.Body).Decode(&value); err != nil {
		logger.Errorf("Decoding error: %s", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	s.config.Ttl = value

}

func (s *HTTPServer) validation(service *Service) error {
	err := validateDomainType(service)
	if err != nil {
		return err
	}
	err = validateDomainValue(service)
	if err != nil {
		return err
	}
	return nil
}
func validateDomainType(service *Service) error {
	switch service.RecordType {
	case "A":
		if net.ParseIP(service.Value) == nil {
			logger.Debugf("Property \"Value\" is NOT IP")
			return errors.New("Property \"Value\" is NOT IP")
		}
	case "CNAME":
		if !validateDomainName(service.Value) {
			return errors.New("Property \"Value\" is wrong")
		}
	default:
		return errors.New("Property \"Record type\" is required or wrong")
	}
	return nil
}

func validateDomainValue(service *Service) error {
	if service.Aliases == "" {
		logger.Debugf("Property \"Aliases\" is required")
		return errors.New("Property \"Aliases\" is required")
	}
	if service.TTL <= 0 {
		logger.Debugf("Property \"TTL\" is required")
		return errors.New("Property \"TTL\" is required")
	}
	return nil
}

func validateDomainName(domain string) bool {
	RegExp := regexp.MustCompile(`^(([a-zA-Z]{1})|([a-zA-Z]{1}[a-zA-Z]{1})|([a-zA-Z]{1}[0-9]{1})|([0-9]{1}[a-zA-Z]{1})|([a-zA-Z0-9][a-zA-Z0-9-_]{1,61}[a-zA-Z0-9]))\.([a-zA-Z]{2,6}|[a-zA-Z0-9-]{2,30}\.[a-zA-Z
 ]{2,3})$`)
	return RegExp.MatchString(domain)
}
<|endoftext|>


<commit_before>package service

import (
    "github.com/ouqiang/cron-scheduler/models"
    "github.com/ouqiang/cron-scheduler/modules/ansible"
    "github.com/ouqiang/cron-scheduler/modules/crontask"
    "github.com/robfig/cron"
    "io/ioutil"
    "net/http"
    "strconv"
    "time"
    "github.com/ouqiang/cron-scheduler/modules/logger"
)

type Task struct{}

// 初始化任务, 从数据库取出所有任务, 添加到定时任务并运行
func (task *Task) Initialize() {
    taskModel := new(models.Task)
    taskList, err := taskModel.ActiveList()
    if err != nil {
        logger.Error("获取任务列表错误-", err.Error())
        return
    }
    if len(taskList) == 0 {
        logger.Debug("任务列表为空")
        return
    }
    for _, item := range taskList {
        task.Add(item)
    }
}

// 添加任务
func (task *Task) Add(taskModel models.Task) {
    taskFunc := createHandlerJob(taskModel)
    if taskFunc == nil {
        logger.Error("添加任务#不存在的任务协议编号", taskModel.Protocol)
        return
    }
    // 定时任务
    if taskModel.Type == models.Timing {
        err := crontask.DefaultCronTask.AddOrReplace(strconv.Itoa(taskModel.Id), taskModel.Spec, taskFunc)
        if err != nil {
            logger.Error(err)
        }
    } else if taskModel.Type == models.Delay {
        // 延时任务
        delay := time.Duration(taskModel.Delay) * time.Second
        time.AfterFunc(delay, taskFunc)
    }
}

type Handler interface {
    Run(taskModel models.Task) (string, error)
}

// HTTP任务
type HTTPHandler struct{}

func (h *HTTPHandler) Run(taskModel models.Task) (result string, err error) {
    client := &http.Client{}
    if taskModel.Timeout > 0 {
        client.Timeout = time.Duration(taskModel.Timeout) * time.Second
    }
    req, err := http.NewRequest("POST", taskModel.Command, nil)
    if err != nil {
        logger.Error("创建HTTP请求错误-", err.Error())
        return
    }
    req.Header.Set("Content-type", "application/x-www-form-urlencoded")
    req.Header.Set("User-Agent", "golang/cron-scheduler")

    resp, err := client.Do(req)
    defer func() {
        if resp != nil {
            resp.Body.Close()
        }
    }()
    if err != nil {
        logger.Error("HTTP请求错误-", err.Error())
        return
    }
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        logger.Error("读取HTTP请求返回值失败-", err.Error())
    }

    return string(body), err
}

// SSH-command任务
type SSHCommandHandler struct{}

func (ssh *SSHCommandHandler) Run(taskModel models.Task) (string, error) {
    return execSSHHandler("shell", taskModel)
}

// SSH-script任务
type SSHScriptHandler struct{}

func (ssh *SSHScriptHandler) Run(taskModel models.Task) (string, error) {
    return execSSHHandler("script", taskModel)
}

// SSH任务
func execSSHHandler(module string, taskModel models.Task) (string, error) {
    var args []string = []string{taskModel.Command}
    if taskModel.Timeout > 0 {
        // -B 异步执行超时时间, -P 轮询时间
        args = append(args, "-B", strconv.Itoa(taskModel.Timeout), "-P", "10")
    }
    if module == "shell" {
        return ansible.Shell(taskModel.SshHosts, ansible.DefaultHosts.GetFilename(), args...)
    }
    if module == "script" {
        return ansible.Script(taskModel.SshHosts, ansible.DefaultHosts.GetFilename(), args...)
    }

    return "", nil
}

func createTaskLog(taskId int) (int, error) {
    taskLogModel := new(models.TaskLog)
    taskLogModel.TaskId = taskId
    taskLogModel.StartTime = time.Now()
    taskLogModel.Status = models.Running
    insertId, err := taskLogModel.Create()

    return insertId, err
}

func updateTaskLog(taskLogId int, result string, err error) (int64, error) {
    taskLogModel := new(models.TaskLog)
    var status models.Status
    if err != nil {
        result = err.Error() + " " + result
        status = models.Failure
    } else {
        status = models.Finish
    }
    return taskLogModel.Update(taskLogId, models.CommonMap{
        "status": status,
        "result": result,
    })

}

func createHandlerJob(taskModel models.Task) cron.FuncJob {
    var handler Handler = nil
    switch taskModel.Protocol {
    case models.HTTP:
        handler = new(HTTPHandler)
    case models.SSHCommand:
        handler = new(SSHCommandHandler)
    case models.SSHScript:
        handler = new(SSHScriptHandler)
    }
    taskFunc := func() {
        taskLogId, err := createTaskLog(taskModel.Id)
        if err != nil {
            logger.Error("写入任务日志失败-", err)
            return
        }
        // err != nil 执行失败
        result, err := handler.Run(taskModel)
        _, err = updateTaskLog(int(taskLogId), result, err)
        if err != nil {
            logger.Error("更新任务日志失败-", err)
        }
    }

    return taskFunc
}
<commit_msg>定时任务-使用不支持的任务协议时,返回nil<commit_after>package service

import (
    "github.com/ouqiang/cron-scheduler/models"
    "github.com/ouqiang/cron-scheduler/modules/ansible"
    "github.com/ouqiang/cron-scheduler/modules/crontask"
    "github.com/robfig/cron"
    "io/ioutil"
    "net/http"
    "strconv"
    "time"
    "github.com/ouqiang/cron-scheduler/modules/logger"
)

type Task struct{}

// 初始化任务, 从数据库取出所有任务, 添加到定时任务并运行
func (task *Task) Initialize() {
    taskModel := new(models.Task)
    taskList, err := taskModel.ActiveList()
    if err != nil {
        logger.Error("获取任务列表错误-", err.Error())
        return
    }
    if len(taskList) == 0 {
        logger.Debug("任务列表为空")
        return
    }
    for _, item := range taskList {
        task.Add(item)
    }
}

// 添加任务
func (task *Task) Add(taskModel models.Task) {
    taskFunc := createHandlerJob(taskModel)
    if taskFunc == nil {
        logger.Error("添加任务#不存在的任务协议编号", taskModel.Protocol)
        return
    }
    // 定时任务
    if taskModel.Type == models.Timing {
        err := crontask.DefaultCronTask.AddOrReplace(strconv.Itoa(taskModel.Id), taskModel.Spec, taskFunc)
        if err != nil {
            logger.Error(err)
        }
    } else if taskModel.Type == models.Delay {
        // 延时任务
        delay := time.Duration(taskModel.Delay) * time.Second
        time.AfterFunc(delay, taskFunc)
    }
}

type Handler interface {
    Run(taskModel models.Task) (string, error)
}

// HTTP任务
type HTTPHandler struct{}

func (h *HTTPHandler) Run(taskModel models.Task) (result string, err error) {
    client := &http.Client{}
    if taskModel.Timeout > 0 {
        client.Timeout = time.Duration(taskModel.Timeout) * time.Second
    }
    req, err := http.NewRequest("POST", taskModel.Command, nil)
    if err != nil {
        logger.Error("创建HTTP请求错误-", err.Error())
        return
    }
    req.Header.Set("Content-type", "application/x-www-form-urlencoded")
    req.Header.Set("User-Agent", "golang/cron-scheduler")

    resp, err := client.Do(req)
    defer func() {
        if resp != nil {
            resp.Body.Close()
        }
    }()
    if err != nil {
        logger.Error("HTTP请求错误-", err.Error())
        return
    }
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        logger.Error("读取HTTP请求返回值失败-", err.Error())
    }

    return string(body), err
}

// SSH-command任务
type SSHCommandHandler struct{}

func (ssh *SSHCommandHandler) Run(taskModel models.Task) (string, error) {
    return execSSHHandler("shell", taskModel)
}

// SSH-script任务
type SSHScriptHandler struct{}

func (ssh *SSHScriptHandler) Run(taskModel models.Task) (string, error) {
    return execSSHHandler("script", taskModel)
}

// SSH任务
func execSSHHandler(module string, taskModel models.Task) (string, error) {
    var args []string = []string{taskModel.Command}
    if taskModel.Timeout > 0 {
        // -B 异步执行超时时间, -P 轮询时间
        args = append(args, "-B", strconv.Itoa(taskModel.Timeout), "-P", "10")
    }
    if module == "shell" {
        return ansible.Shell(taskModel.SshHosts, ansible.DefaultHosts.GetFilename(), args...)
    }
    if module == "script" {
        return ansible.Script(taskModel.SshHosts, ansible.DefaultHosts.GetFilename(), args...)
    }

    return "", nil
}

func createTaskLog(taskId int) (int, error) {
    taskLogModel := new(models.TaskLog)
    taskLogModel.TaskId = taskId
    taskLogModel.StartTime = time.Now()
    taskLogModel.Status = models.Running
    insertId, err := taskLogModel.Create()

    return insertId, err
}

func updateTaskLog(taskLogId int, result string, err error) (int64, error) {
    taskLogModel := new(models.TaskLog)
    var status models.Status
    if err != nil {
        result = err.Error() + " " + result
        status = models.Failure
    } else {
        status = models.Finish
    }
    return taskLogModel.Update(taskLogId, models.CommonMap{
        "status": status,
        "result": result,
    })

}

func createHandlerJob(taskModel models.Task) cron.FuncJob {
    var handler Handler = nil
    switch taskModel.Protocol {
    case models.HTTP:
        handler = new(HTTPHandler)
    case models.SSHCommand:
        handler = new(SSHCommandHandler)
    case models.SSHScript:
        handler = new(SSHScriptHandler)
    }
    if handler == nil {
        return nil
    }
    taskFunc := func() {
        taskLogId, err := createTaskLog(taskModel.Id)
        if err != nil {
            logger.Error("写入任务日志失败-", err)
            return
        }
        // err != nil 执行失败
        result, err := handler.Run(taskModel)
        _, err = updateTaskLog(int(taskLogId), result, err)
        if err != nil {
            logger.Error("更新任务日志失败-", err)
        }
    }

    return taskFunc
}
<|endoftext|>


<commit_before>package sugars

import (
	"context"
	"fmt"
)

func ExampleServiceFunc() {
	fn := func(ctx context.Context) {
		fmt.Println("running")
		defer fmt.Println("stopped")
		<-ctx.Done()
	}

	svc := ServiceFunc(context.Background(), fn)
	fmt.Println(1, svc.Running())

	svc.Start()
	fmt.Println(2, svc.Running())

	svc.Start()
	fmt.Println(3, svc.Running())

	svc.Stop()
	fmt.Println(4, svc.Running())

	svc.Stop()
	fmt.Println(5, svc.Running())

	svc.Start()
	fmt.Println(6, svc.Running())

	svc.Stop()
	fmt.Println(7, svc.Running())

	svc.Dispose()
	fmt.Println(8, svc.Running())

	// Output:
	// 1 false
	// running
	// 2 true
	// 3 true
	// stopped
	// 4 false
	// 5 false
	// running
	// 6 true
	// stopped
	// 7 false
	// 8 false
}
<commit_msg>テストケース追加<commit_after>package sugars

import (
	"context"
	"fmt"
	"testing"
)

func ExampleServiceFunc() {
	fn := func(ctx context.Context) {
		fmt.Println("running")
		defer fmt.Println("stopped")
		<-ctx.Done()
	}

	svc := ServiceFunc(context.Background(), fn)
	fmt.Println(1, svc.Running())

	svc.Start()
	fmt.Println(2, svc.Running())

	svc.Start()
	fmt.Println(3, svc.Running())

	svc.Stop()
	fmt.Println(4, svc.Running())

	svc.Stop()
	fmt.Println(5, svc.Running())

	svc.Start()
	fmt.Println(6, svc.Running())

	svc.Stop()
	fmt.Println(7, svc.Running())

	svc.Dispose()
	fmt.Println(8, svc.Running())

	// Output:
	// 1 false
	// running
	// 2 true
	// 3 true
	// stopped
	// 4 false
	// 5 false
	// running
	// 6 true
	// stopped
	// 7 false
	// 8 false
}

func TestServiceFuncContextCanceled(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())

	svc := ServiceFunc(ctx, func(ctx context.Context) {
		cancel()
		<-ctx.Done()
	})
	svc.Start()
	svc.Dispose()
}
<|endoftext|>


<commit_before>package ecc

import (
	"errors"
	"fmt"
	"github.com/bfix/gospel/math"
)

// Curve is the elliptic curve used for Bitcoin (Secp256k1)
type Curve struct {
	// P is the generator of the underlying field "F_p"
	// = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
	P *math.Int
	// Gx is the x-coord of the base point
	Gx *math.Int
	// Gy is the y-coord of the base point
	Gy *math.Int
	// N is the order of G
	N *math.Int
	// curve parameter (=7)
	B *math.Int
}

var (
	// Curve is the reference to a curve instance (meant as singleton)
	c = &Curve{
		P:  math.NewIntFromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F"),
		Gx: math.NewIntFromHex("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"),
		Gy: math.NewIntFromHex("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"),
		N:  math.NewIntFromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"),
		B:  math.SEVEN,
	}
)

// GetCurve returns the singleton curve instance
func GetCurve() *Curve {
	return c
}

// GetBasePoint returns the base Point of the curve
func GetBasePoint() *Point {
	return NewPoint(c.Gx, c.Gy)
}

// MultBase multiplies the base Point of the curve with a scalar value k
func MultBase(k *math.Int) *Point {
	return GetBasePoint().Mult(k)
}

// Inf is the point at "infinity"
var Inf = NewPoint(math.ZERO, math.ZERO)

// Point (x,y) on the curve
type Point struct { // exported Point type
	x, y *math.Int // coordinate values
}

// NewPoint instaniates a new Point
func NewPoint(a, b *math.Int) *Point {
	return &Point{x: a, y: b}
}

// NewPointFromBytes reconstructs a Point from binary representation.
func NewPointFromBytes(b []byte) (p *Point, compr bool, err error) {
	p = NewPoint(math.ZERO, math.ZERO)
	err = nil
	compr = true
	switch b[0] {
	case 0:
	case 4:
		p.x = math.NewIntFromBytes(b[1:33])
		p.y = math.NewIntFromBytes(b[33:])
		compr = false
	case 3:
		p.x = math.NewIntFromBytes(b[1:])
		p.y, err = computeY(p.x, 1)
		if err != nil {
			return
		}
	case 2:
		p.x = math.NewIntFromBytes(b[1:])
		p.y, err = computeY(p.x, 0)
		if err != nil {
			return
		}
	default:
		err = errors.New("Invalid binary Point representation")
	}
	return
}

// Neg returns -P for the point P.
func (p *Point) Neg() *Point {
	return NewPoint(p.x, p.y.Neg())
}

// String returns a human-readable representation of a point.
func (p *Point) String() string {
	return fmt.Sprintf("(%v,%v)", p.x, p.y)
}

// Equals checks if two Points are equal
func (p *Point) Equals(q *Point) bool {
	return p.x.Cmp(q.x) == 0 && p.y.Cmp(q.y) == 0
}

// IsInf checks if a Point is at infinity
func (p *Point) IsInf() bool {
	return p.x.Cmp(math.ZERO) == 0 && p.y.Cmp(math.ZERO) == 0
}

// IsOnCurve checks if a Point (x,y) is on the curve
func (p *Point) IsOnCurve() bool {
	// y² = x³ + 7
	y2 := pSqr(p.y)
	x3 := pCub(p.x)
	return y2.Cmp(pAdd(x3, c.B)) == 0
}

// Add two Points on the curve
func (p *Point) Add(q *Point) *Point {
	if p.Equals(q) {
		return p.Double()
	}
	if p.Equals(Inf) {
		return q
	}
	if q.Equals(Inf) {
		return p
	}
	_p1 := newJacPoint(p.x, p.y, math.ONE)
	_p2 := newJacPoint(q.x, q.y, math.ONE)
	return _p1.add(_p2).conv()
}

// Double a Point on the curve
func (p *Point) Double() *Point {
	if p.Equals(Inf) {
		return Inf
	}
	return newJacPoint(p.x, p.y, math.ONE).double().conv()
}

// Mult multiplies a Point on the curve with a scalar value k using
// a Montgomery multiplication approach
func (p *Point) Mult(k *math.Int) *Point {
	return newJacPoint(p.x, p.y, math.ONE).mult(k).conv()
}

// Bytes returns a byte representation of Point (compressed or uncompressed).
func (p *Point) Bytes(compressed bool) []byte {
	if p.Equals(Inf) {
		return []byte{0}
	}
	var res []byte
	if compressed {
		rc := byte(2)
		if p.y.Bit(0) == 1 {
			rc = 3
		}
		res = append(res, rc)
		res = append(res, coordAsBytes(p.x)...)
	} else {
		res = append(res, 4)
		res = append(res, coordAsBytes(p.x)...)
		res = append(res, coordAsBytes(p.y)...)
	}
	return res
}

// JacPoint is a point on the curve that is represented internally in
// Jacobian coordinates (X,Y,Z) with "x = X/Z^2" and "y = Y/Z^3". See:
// [http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html]
type jacPoint struct { // internal Point type
	x, y, z *math.Int // using Jacobian coordinates
}

// NewJacPoint instaniates a new Point
func newJacPoint(a, b, c *math.Int) *jacPoint {
	return &jacPoint{x: a, y: b, z: c}
}

// Point at infinity
var jacInf = newJacPoint(Inf.x, Inf.y, math.ONE)

// check if a Point is at infinity
func (p *jacPoint) isInf() bool {
	return p.x.Equals(math.ZERO) && p.y.Equals(math.ZERO)
}

// convert internal Point to external representation
func (p *jacPoint) conv() *Point {
	zi := pInv(p.z)
	x := pMul(p.x, pSqr(zi))
	y := pMul(p.y, pCub(zi))
	return NewPoint(x, y)
}

// add two jacPoints on the curve
// [http://www.hyperelliptic.org/EFD/g1p/data/shortw/jacobian-0/addJacition/addJac-2007-bl]
func (p *jacPoint) add(q *jacPoint) *jacPoint {
	if p.isInf() {
		return q
	}
	if q.isInf() {
		return p
	}
	z1z1 := pSqr(p.z)
	z2z2 := pSqr(q.z)
	u1 := pMul(p.x, z2z2)
	u2 := pMul(q.x, z1z1)
	s1 := pMul(pMul(p.y, q.z), z2z2)
	s2 := pMul(pMul(q.y, p.z), z1z1)
	h := pSub(u2, u1)
	i := pSqr(pMul(math.TWO, h))
	j := pMul(h, i)
	r := pMul(math.TWO, pSub(s2, s1))
	v := pMul(u1, i)
	w := pAdd(p.z, q.z)
	x := pSub(pSub(pSqr(r), j), pMul(math.TWO, v))
	y := pSub(pMul(r, pSub(v, x)), pMul(math.TWO, pMul(s1, j)))
	z := pMul(pSub(pSub(pSqr(w), z1z1), z2z2), h)
	return newJacPoint(x, y, z)
}

// double a Point on the curve
// [http://www.hyperelliptic.org/EFD/g1p/data/shortw/jacobian-0/doubling/dbl-2009-alnr]
func (p *jacPoint) double() *jacPoint {
	if p.isInf() {
		return p
	}
	a := pSqr(p.x)
	b := pSqr(p.y)
	zz := pSqr(p.z)
	c := pSqr(b)
	d := pMul(math.TWO, pSub(pSub(pSqr(p.x.Add(b)), a), c))
	e := pMul(math.THREE, a)
	f := pSqr(e)
	x := pSub(f, pMul(math.TWO, d))
	y := pSub(pMul(e, pSub(d, x)), pMul(math.EIGHT, c))
	z := pSub(pSub(pSqr(pAdd(p.y, p.z)), b), zz)
	return newJacPoint(x, y, z)
}

// Multiply a Point on the curve with a scalar value k using
// a Montgomery multiplication algorithm
func (p *jacPoint) mult(k *math.Int) *jacPoint {
	if p.isInf() {
		return p
	}
	if k.Cmp(math.ZERO) == 0 {
		return jacInf
	}
	r := jacInf
	for _, val := range k.Bytes() {
		for pos := 0; pos < 8; pos++ {
			r = r.double()
			if val&0x80 == 0x80 {
				r = p.add(r)
			}
			val <<= 1
		}
	}
	return r
}

// helper: convert coordinate to byte array of correct length
func coordAsBytes(v *math.Int) []byte {
	bv := v.Bytes()
	plen := 32 - len(bv)
	if plen == 0 {
		return bv
	}
	b := make([]byte, plen)
	return append(b, bv...)
}

// helper: reconstruct y-coordinate of Point
func computeY(x *math.Int, m uint) (y *math.Int, err error) {
	y = math.ZERO
	err = nil
	y2 := pAdd(pCub(x), c.B)
	y, err = math.SqrtModP(y2, c.P)
	if err == nil {
		if y.Bit(0) != m {
			y = c.P.Sub(y)
		}
	}
	return
}

// modulus
func nMod(a *math.Int) *math.Int {
	return a.Mod(c.N)
}

func pInv(a *math.Int) *math.Int {
	return a.ModInverse(c.P)
}

func pMul(a, b *math.Int) *math.Int {
	return a.Mul(b).Mod(c.P)
}

func pSqr(a *math.Int) *math.Int {
	return pMul(a, a)
}

func pCub(a *math.Int) *math.Int {
	return pMul(pSqr(a), a)
}

func pSub(a, b *math.Int) *math.Int {
	x := a.Sub(b)
	if x.Sign() == -1 {
		x = x.Add(c.P)
	}
	return x
}

func pAdd(a, b *math.Int) *math.Int {
	return a.Add(b).Mod(c.P)
}

func nInv(a *math.Int) *math.Int {
	return a.ModInverse(c.N)
}

func nMul(a, b *math.Int) *math.Int {
	return a.Mul(b).Mod(c.N)
}

func nRnd(a *math.Int) *math.Int {
	return math.NewIntRndRange(a, c.N)
}
<commit_msg>Added point methods to access coordinate values.<commit_after>package ecc

import (
	"errors"
	"fmt"
	"github.com/bfix/gospel/math"
)

// Curve is the elliptic curve used for Bitcoin (Secp256k1)
type Curve struct {
	// P is the generator of the underlying field "F_p"
	// = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
	P *math.Int
	// Gx is the x-coord of the base point
	Gx *math.Int
	// Gy is the y-coord of the base point
	Gy *math.Int
	// N is the order of G
	N *math.Int
	// curve parameter (=7)
	B *math.Int
}

var (
	// Curve is the reference to a curve instance (meant as singleton)
	c = &Curve{
		P:  math.NewIntFromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F"),
		Gx: math.NewIntFromHex("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"),
		Gy: math.NewIntFromHex("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"),
		N:  math.NewIntFromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"),
		B:  math.SEVEN,
	}
)

// GetCurve returns the singleton curve instance
func GetCurve() *Curve {
	return c
}

// GetBasePoint returns the base Point of the curve
func GetBasePoint() *Point {
	return NewPoint(c.Gx, c.Gy)
}

// MultBase multiplies the base Point of the curve with a scalar value k
func MultBase(k *math.Int) *Point {
	return GetBasePoint().Mult(k)
}

// Inf is the point at "infinity"
var Inf = NewPoint(math.ZERO, math.ZERO)

// Point (x,y) on the curve
type Point struct { // exported Point type
	x, y *math.Int // coordinate values
}

// NewPoint instaniates a new Point
func NewPoint(a, b *math.Int) *Point {
	return &Point{x: a, y: b}
}

// NewPointFromBytes reconstructs a Point from binary representation.
func NewPointFromBytes(b []byte) (p *Point, compr bool, err error) {
	p = NewPoint(math.ZERO, math.ZERO)
	err = nil
	compr = true
	switch b[0] {
	case 0:
	case 4:
		p.x = math.NewIntFromBytes(b[1:33])
		p.y = math.NewIntFromBytes(b[33:])
		compr = false
	case 3:
		p.x = math.NewIntFromBytes(b[1:])
		p.y, err = computeY(p.x, 1)
		if err != nil {
			return
		}
	case 2:
		p.x = math.NewIntFromBytes(b[1:])
		p.y, err = computeY(p.x, 0)
		if err != nil {
			return
		}
	default:
		err = errors.New("Invalid binary Point representation")
	}
	return
}

// X returns the x-coordinate of a point.
func (p *Point) X() *math.Int {
	return p.x
}

// Y returns the y-coordinate of a point.
func (p *Point) Y() *math.Int {
	return p.y
}

// Neg returns -P for the point P.
func (p *Point) Neg() *Point {
	return NewPoint(p.x, p.y.Neg())
}

// String returns a human-readable representation of a point.
func (p *Point) String() string {
	return fmt.Sprintf("(%v,%v)", p.x, p.y)
}

// Equals checks if two Points are equal
func (p *Point) Equals(q *Point) bool {
	return p.x.Cmp(q.x) == 0 && p.y.Cmp(q.y) == 0
}

// IsInf checks if a Point is at infinity
func (p *Point) IsInf() bool {
	return p.x.Cmp(math.ZERO) == 0 && p.y.Cmp(math.ZERO) == 0
}

// IsOnCurve checks if a Point (x,y) is on the curve
func (p *Point) IsOnCurve() bool {
	// y² = x³ + 7
	y2 := pSqr(p.y)
	x3 := pCub(p.x)
	return y2.Cmp(pAdd(x3, c.B)) == 0
}

// Add two Points on the curve
func (p *Point) Add(q *Point) *Point {
	if p.Equals(q) {
		return p.Double()
	}
	if p.Equals(Inf) {
		return q
	}
	if q.Equals(Inf) {
		return p
	}
	_p1 := newJacPoint(p.x, p.y, math.ONE)
	_p2 := newJacPoint(q.x, q.y, math.ONE)
	return _p1.add(_p2).conv()
}

// Double a Point on the curve
func (p *Point) Double() *Point {
	if p.Equals(Inf) {
		return Inf
	}
	return newJacPoint(p.x, p.y, math.ONE).double().conv()
}

// Mult multiplies a Point on the curve with a scalar value k using
// a Montgomery multiplication approach
func (p *Point) Mult(k *math.Int) *Point {
	return newJacPoint(p.x, p.y, math.ONE).mult(k).conv()
}

// Bytes returns a byte representation of Point (compressed or uncompressed).
func (p *Point) Bytes(compressed bool) []byte {
	if p.Equals(Inf) {
		return []byte{0}
	}
	var res []byte
	if compressed {
		rc := byte(2)
		if p.y.Bit(0) == 1 {
			rc = 3
		}
		res = append(res, rc)
		res = append(res, coordAsBytes(p.x)...)
	} else {
		res = append(res, 4)
		res = append(res, coordAsBytes(p.x)...)
		res = append(res, coordAsBytes(p.y)...)
	}
	return res
}

// JacPoint is a point on the curve that is represented internally in
// Jacobian coordinates (X,Y,Z) with "x = X/Z^2" and "y = Y/Z^3". See:
// [http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html]
type jacPoint struct { // internal Point type
	x, y, z *math.Int // using Jacobian coordinates
}

// NewJacPoint instaniates a new Point
func newJacPoint(a, b, c *math.Int) *jacPoint {
	return &jacPoint{x: a, y: b, z: c}
}

// Point at infinity
var jacInf = newJacPoint(Inf.x, Inf.y, math.ONE)

// check if a Point is at infinity
func (p *jacPoint) isInf() bool {
	return p.x.Equals(math.ZERO) && p.y.Equals(math.ZERO)
}

// convert internal Point to external representation
func (p *jacPoint) conv() *Point {
	zi := pInv(p.z)
	x := pMul(p.x, pSqr(zi))
	y := pMul(p.y, pCub(zi))
	return NewPoint(x, y)
}

// add two jacPoints on the curve
// [http://www.hyperelliptic.org/EFD/g1p/data/shortw/jacobian-0/addJacition/addJac-2007-bl]
func (p *jacPoint) add(q *jacPoint) *jacPoint {
	if p.isInf() {
		return q
	}
	if q.isInf() {
		return p
	}
	z1z1 := pSqr(p.z)
	z2z2 := pSqr(q.z)
	u1 := pMul(p.x, z2z2)
	u2 := pMul(q.x, z1z1)
	s1 := pMul(pMul(p.y, q.z), z2z2)
	s2 := pMul(pMul(q.y, p.z), z1z1)
	h := pSub(u2, u1)
	i := pSqr(pMul(math.TWO, h))
	j := pMul(h, i)
	r := pMul(math.TWO, pSub(s2, s1))
	v := pMul(u1, i)
	w := pAdd(p.z, q.z)
	x := pSub(pSub(pSqr(r), j), pMul(math.TWO, v))
	y := pSub(pMul(r, pSub(v, x)), pMul(math.TWO, pMul(s1, j)))
	z := pMul(pSub(pSub(pSqr(w), z1z1), z2z2), h)
	return newJacPoint(x, y, z)
}

// double a Point on the curve
// [http://www.hyperelliptic.org/EFD/g1p/data/shortw/jacobian-0/doubling/dbl-2009-alnr]
func (p *jacPoint) double() *jacPoint {
	if p.isInf() {
		return p
	}
	a := pSqr(p.x)
	b := pSqr(p.y)
	zz := pSqr(p.z)
	c := pSqr(b)
	d := pMul(math.TWO, pSub(pSub(pSqr(p.x.Add(b)), a), c))
	e := pMul(math.THREE, a)
	f := pSqr(e)
	x := pSub(f, pMul(math.TWO, d))
	y := pSub(pMul(e, pSub(d, x)), pMul(math.EIGHT, c))
	z := pSub(pSub(pSqr(pAdd(p.y, p.z)), b), zz)
	return newJacPoint(x, y, z)
}

// Multiply a Point on the curve with a scalar value k using
// a Montgomery multiplication algorithm
func (p *jacPoint) mult(k *math.Int) *jacPoint {
	if p.isInf() {
		return p
	}
	if k.Cmp(math.ZERO) == 0 {
		return jacInf
	}
	r := jacInf
	for _, val := range k.Bytes() {
		for pos := 0; pos < 8; pos++ {
			r = r.double()
			if val&0x80 == 0x80 {
				r = p.add(r)
			}
			val <<= 1
		}
	}
	return r
}

// helper: convert coordinate to byte array of correct length
func coordAsBytes(v *math.Int) []byte {
	bv := v.Bytes()
	plen := 32 - len(bv)
	if plen == 0 {
		return bv
	}
	b := make([]byte, plen)
	return append(b, bv...)
}

// helper: reconstruct y-coordinate of Point
func computeY(x *math.Int, m uint) (y *math.Int, err error) {
	y = math.ZERO
	err = nil
	y2 := pAdd(pCub(x), c.B)
	y, err = math.SqrtModP(y2, c.P)
	if err == nil {
		if y.Bit(0) != m {
			y = c.P.Sub(y)
		}
	}
	return
}

// modulus
func nMod(a *math.Int) *math.Int {
	return a.Mod(c.N)
}

func pInv(a *math.Int) *math.Int {
	return a.ModInverse(c.P)
}

func pMul(a, b *math.Int) *math.Int {
	return a.Mul(b).Mod(c.P)
}

func pSqr(a *math.Int) *math.Int {
	return pMul(a, a)
}

func pCub(a *math.Int) *math.Int {
	return pMul(pSqr(a), a)
}

func pSub(a, b *math.Int) *math.Int {
	x := a.Sub(b)
	if x.Sign() == -1 {
		x = x.Add(c.P)
	}
	return x
}

func pAdd(a, b *math.Int) *math.Int {
	return a.Add(b).Mod(c.P)
}

func nInv(a *math.Int) *math.Int {
	return a.ModInverse(c.N)
}

func nMul(a, b *math.Int) *math.Int {
	return a.Mul(b).Mod(c.N)
}

func nRnd(a *math.Int) *math.Int {
	return math.NewIntRndRange(a, c.N)
}
<|endoftext|>


<commit_before>package fsutil

import (
	"path/filepath"
	"testing"

	"github.com/rjeczalik/tools/fs/memfs"
)

var trees = []memfs.FS{
	0: memfs.Must(memfs.TabTree([]byte(".\ndata\n\tgithub.com\n\t\tuser\n\t\t" +
		"\texample\n\t\t\t\t.git/\n\t\t\t\tdir\n\t\t\t\t\tdir.txt\n\t\t\t\tas" +
		"sets\n\t\t\t\t\tjs\n\t\t\t\t\t\tapp.js\n\t\t\t\t\t\tlink.js\n\t\t\t" +
		"\t\tcss\n\t\t\t\t\t\tdefault.css\nsrc\n\tgithub.com\n\t\tuser\n\t\t" +
		"\texample\n\t\t\t\t.git/\n\t\t\t\tdir\n\t\t\t\t\tdir.go\n\t\t\t\tex" +
		"ample.go"))),
	1: memfs.Must(memfs.TabTree([]byte(".\ndata\n\tgithub.com\n\t\tuser\n\t" +
		"\t\texample\n\t\t\t\tdir\n\t\t\t\t\tdir.dat\n\t\t\t\tfirst\n\t\t\t\t" +
		"\tcss\n\t\t\t\t\t\tfirst.css\n\t\t\t\t\tjs\n\t\t\t\t\t\tfirst.js\n\t" +
		"\t\t\tsecond\n\t\t\t\t\tcss\n\t\t\t\t\t\tsecond.css\n\t\t\t\t\tjs\n" +
		"\t\t\t\t\t\tsecond.js\nsrc\n\tgithub.com\n\t\tuser\n\t\t\texample\n" +
		"\t\t\t\tdir\n\t\t\t\t\tdir.go\n\t\t\t\texample.go"))),
	2: memfs.Must(memfs.TabTree([]byte(".\nschema\n\tlicstat\n\t\tschema\n\t" +
		"\t\tdatabasequery\n\t\t\t\treqaddaliasls.json\n\t\t\t\treqdeletef.j" +
		"son\n\t\t\t\treqdeletels.json\n\t\t\t\treqmergels.json\n\t\t\t\treq" +
		"querystatus.json\n\t\t\tdefinitions.json\n\t\t\tgeneralinfo\n\t\t\t" +
		"\treqinstallpath.json\n\t\t\tlicense\n\t\t\t\treqlicensedetail.json" +
		"\n\t\t\tmonitorconf\n\t\t\t\treqaddls.json\n\t\t\t\treqcheckls.json" +
		"\n\t\t\t\treqeditls.json\n\t\t\t\treqremovels.json\n\t\t\t\treqstat" +
		"usls.json\nsrc\n\tlicstat\n\t\tschema\n\t\t\tschema.go\n\t\t\ttmp/"))),
}

func equal(lhs, cas []string) bool {
	if len(lhs) != len(cas) {
		return false
	}
	for i := range cas {
		cas[i] = filepath.FromSlash(cas[i])
	}
LOOP:
	for i := range lhs {
		for j := range cas {
			if lhs[i] == cas[j] {
				continue LOOP
			}
		}
		return false
	}
	return true
}

func TestReadpaths(t *testing.T) {
	t.Skip("TODO(rjeczalik)")
}

func TestReaddirpaths(t *testing.T) {
	cases := map[string][]string{
		filepath.FromSlash("/data/github.com/user/example"): {
			"assets",
			"dir",
		},
		filepath.FromSlash("/src/github.com/user/example"): {
			"dir",
		},
	}
	c := Control{FS: trees[0]}
	for dir, cas := range cases {
		for _, b := range [...]bool{false, true} {
			if c.Hidden = b; b {
				cas = append(cas, ".git")
			}
			names := c.Readdirpaths(dir)
			if names == nil {
				t.Errorf("want names!=nil (dir=%q,hidden=%v)", dir, b)
				continue
			}
			if !equal(names, cas) {
				t.Errorf("want names=%v; got %v (dir=%q,hidden=%v)", cas, names, dir, b)
			}
		}
	}
}

func TestIntersect(t *testing.T) {
	cases := [...]struct {
		c    Control
		dirs []string
		src  string
		dst  string
	}{
		0: {
			Control{FS: trees[0]},
			[]string{
				"github.com/user/example",
				"github.com/user/example/dir",
			},
			"/src", "/data",
		},
		1: {
			Control{FS: trees[0], Hidden: true},
			[]string{
				"github.com/user/example",
				"github.com/user/example/dir",
				"github.com/user/example/.git",
			},
			"/src", "/data",
		},
		2: {
			Control{FS: trees[2]},
			[]string{
				"licstat/schema",
			},
			"/src", "/schema",
		},
	}
	for i, cas := range cases {
		dirs := cas.c.Intersect(
			filepath.FromSlash(cas.src),
			filepath.FromSlash(cas.dst),
		)
		if len(dirs) == 0 {
			t.Errorf("want len(dirs)!=0 (i=%d)", i)
			continue
		}
		if !equal(dirs, cas.dirs) {
			t.Errorf("want dirs=%v; got %v (i=%d)", cas.dirs, dirs, i)
		}
	}
}

func TestFind(t *testing.T) {
	t.Skip("TODO(rjeczalik)")
}
<commit_msg>fs/fsutil: Add a test-case for TestIntersect<commit_after>package fsutil

import (
	"path/filepath"
	"testing"

	"github.com/rjeczalik/tools/fs/memfs"
)

var trees = []memfs.FS{
	0: memfs.Must(memfs.TabTree([]byte(".\ndata\n\tgithub.com\n\t\tuser\n\t\t" +
		"\texample\n\t\t\t\t.git/\n\t\t\t\tdir\n\t\t\t\t\tdir.txt\n\t\t\t\tas" +
		"sets\n\t\t\t\t\tjs\n\t\t\t\t\t\tapp.js\n\t\t\t\t\t\tlink.js\n\t\t\t" +
		"\t\tcss\n\t\t\t\t\t\tdefault.css\nsrc\n\tgithub.com\n\t\tuser\n\t\t" +
		"\texample\n\t\t\t\t.git/\n\t\t\t\tdir\n\t\t\t\t\tdir.go\n\t\t\t\tex" +
		"ample.go"))),
	1: memfs.Must(memfs.TabTree([]byte(".\ndata\n\tgithub.com\n\t\tuser\n\t" +
		"\t\texample\n\t\t\t\tdir\n\t\t\t\t\tdir.dat\n\t\t\t\tfirst\n\t\t\t\t" +
		"\tcss\n\t\t\t\t\t\tfirst.css\n\t\t\t\t\tjs\n\t\t\t\t\t\tfirst.js\n\t" +
		"\t\t\tsecond\n\t\t\t\t\tcss\n\t\t\t\t\t\tsecond.css\n\t\t\t\t\tjs\n" +
		"\t\t\t\t\t\tsecond.js\nsrc\n\tgithub.com\n\t\tuser\n\t\t\texample\n" +
		"\t\t\t\tdir\n\t\t\t\t\tdir.go\n\t\t\t\texample.go"))),
	2: memfs.Must(memfs.TabTree([]byte(".\nschema\n\tlicstat\n\t\tschema\n\t" +
		"\t\tdatabasequery\n\t\t\t\treqaddaliasls.json\n\t\t\t\treqdeletef.j" +
		"son\n\t\t\t\treqdeletels.json\n\t\t\t\treqmergels.json\n\t\t\t\treq" +
		"querystatus.json\n\t\t\tdefinitions.json\n\t\t\tgeneralinfo\n\t\t\t" +
		"\treqinstallpath.json\n\t\t\tlicense\n\t\t\t\treqlicensedetail.json" +
		"\n\t\t\tmonitorconf\n\t\t\t\treqaddls.json\n\t\t\t\treqcheckls.json" +
		"\n\t\t\t\treqeditls.json\n\t\t\t\treqremovels.json\n\t\t\t\treqstat" +
		"usls.json\nsrc\n\tlicstat\n\t\tschema\n\t\t\tschema.go\n\t\t\ttmp/"))),
}

func equal(lhs, cas []string) bool {
	if len(lhs) != len(cas) {
		return false
	}
	for i := range cas {
		cas[i] = filepath.FromSlash(cas[i])
	}
LOOP:
	for i := range lhs {
		for j := range cas {
			if lhs[i] == cas[j] {
				continue LOOP
			}
		}
		return false
	}
	return true
}

func TestReadpaths(t *testing.T) {
	t.Skip("TODO(rjeczalik)")
}

func TestReaddirpaths(t *testing.T) {
	cases := map[string][]string{
		filepath.FromSlash("/data/github.com/user/example"): {
			"assets",
			"dir",
		},
		filepath.FromSlash("/src/github.com/user/example"): {
			"dir",
		},
	}
	c := Control{FS: trees[0]}
	for dir, cas := range cases {
		for _, b := range [...]bool{false, true} {
			if c.Hidden = b; b {
				cas = append(cas, ".git")
			}
			names := c.Readdirpaths(dir)
			if names == nil {
				t.Errorf("want names!=nil (dir=%q,hidden=%v)", dir, b)
				continue
			}
			if !equal(names, cas) {
				t.Errorf("want names=%v; got %v (dir=%q,hidden=%v)", cas, names, dir, b)
			}
		}
	}
}

func TestIntersect(t *testing.T) {
	cases := [...]struct {
		c    Control
		dirs []string
		src  string
		dst  string
	}{
		0: {
			Control{FS: trees[0]},
			[]string{
				"github.com/user/example",
				"github.com/user/example/dir",
			},
			"/src", "/data",
		},
		1: {
			Control{FS: trees[0], Hidden: true},
			[]string{
				"github.com/user/example",
				"github.com/user/example/dir",
				"github.com/user/example/.git",
			},
			"/src", "/data",
		},
		2: {
			Control{FS: trees[2]},
			[]string{
				"licstat/schema",
			},
			"/src", "/schema",
		},
		3: {
			Control{FS: trees[2], Hidden: true},
			[]string{
				"licstat/schema",
			},
			"/src", "/schema",
		},
		4: {
			Control{FS: trees[1]},
			[]string{
				"github.com/user/example",
				"github.com/user/example/dir",
			},
			"/src", "/data",
		},
		5: {
			Control{FS: trees[1], Hidden: true},
			[]string{
				"github.com/user/example",
				"github.com/user/example/dir",
			},
			"/src", "/data",
		},
	}
	for i, cas := range cases {
		dirs := cas.c.Intersect(
			filepath.FromSlash(cas.src),
			filepath.FromSlash(cas.dst),
		)
		if len(dirs) == 0 {
			t.Errorf("want len(dirs)!=0 (i=%d)", i)
			continue
		}
		if !equal(dirs, cas.dirs) {
			t.Errorf("want dirs=%v; got %v (i=%d)", cas.dirs, dirs, i)
		}
	}
}

func TestFind(t *testing.T) {
	t.Skip("TODO(rjeczalik)")
}
<|endoftext|>


<commit_before>package gockle

import (
	"fmt"
	"reflect"
	"testing"
	"time"

	"github.com/gocql/gocql"
	"github.com/maraino/go-mock"
)

const version = 4

const (
	ksCreate  = "create keyspace gockle_test with replication = {'class': 'SimpleStrategy', 'replication_factor': 1};"
	ksDrop    = "drop keyspace gockle_test"
	ksDropIf  = "drop keyspace if exists gockle_test"
	rowInsert = "insert into gockle_test.test (id, n) values (1, 2)"
	tabCreate = "create table gockle_test.test(id int primary key, n int)"
	tabDrop   = "drop table gockle_test.test"
)

func TestNewSession(t *testing.T) {
	if a, e := NewSession(nil), (session{}); a != e {
		t.Errorf("Actual session %v, expected %v", a, e)
	}

	var c = gocql.NewCluster("localhost")

	c.ProtoVersion = version

	var s, err = c.CreateSession()

	if err != nil {
		t.Skip(err)
	}

	if a, e := NewSession(s), (session{s: s}); a != e {
		t.Errorf("Actual session %v, expected %v", a, e)
	}
}

func TestNewSimpleSession(t *testing.T) {
	if s, err := NewSimpleSession(); err == nil {
		t.Error("Actual no error, expected error")
	} else if s != nil {
		t.Errorf("Actual session %v, expected nil", s)
		s.Close()
	}

	if a, err := NewSimpleSession("localhost"); err != nil {
		t.Errorf("Actual error %v, expected no error", err)
	} else if a == nil {
		t.Errorf("Actual session nil, expected not nil")
	} else {
		a.Close()
	}
}

func TestSessionMetadata(t *testing.T) {
	var exec = func(s Session, q string) {
		if err := s.QueryExec(q); err != nil {
			t.Fatalf("Actual error %v, expected no error", err)
		}
	}

	var s = newSession(t)

	exec(s, ksDropIf)
	exec(s, ksCreate)

	defer exec(s, ksDrop)

	exec(s, tabCreate)

	defer exec(s, tabDrop)

	s = newSession(t)

	if a, err := s.Tables("gockle_test"); err == nil {
		if e := ([]string{"test"}); !reflect.DeepEqual(a, e) {
			t.Fatalf("Actual tables %v, expected %v", a, e)
		}
	} else {
		t.Fatalf("Actual error %v, expected no error", err)
	}

	s.Close()

	if _, err := s.Tables("gockle_test"); err == nil {
		t.Errorf("Actual no error, expected error")
	}

	s = newSession(t)

	if a, err := s.Columns("gockle_test", "test"); err == nil {
		var ts = map[string]gocql.Type{"id": gocql.TypeInt, "n": gocql.TypeInt}

		if la, le := len(a), len(ts); la == le {
			for n, at := range a {
				if et, ok := ts[n]; ok {
					if at.Type() != et {
						t.Fatalf("Actual type %v, expected %v", at, et)
					}
				} else {
					t.Fatalf("Actual name %v invalid, expected valid", n)
				}
			}
		} else {
			t.Fatalf("Actual count %v, expected %v", la, le)
		}
	} else {
		t.Fatalf("Actual error %v, expected no error", err)
	}

	if _, err := s.Columns("gockle_test", "invalid"); err == nil {
		t.Error("Actual no error, expected error")
	}

	s.Close()

	if _, err := s.Columns("gockle_test", "test"); err == nil {
		t.Error("Actual no error, expected error")
	}
}

func TestSessionMock(t *testing.T) {
	var m, e = &SessionMock{}, fmt.Errorf("e")

	testMock(t, m, &m.Mock, []struct {
		method    string
		arguments []interface{}
		results   []interface{}
	}{
		{"Close", nil, nil},
		{"Columns", []interface{}{"", ""}, []interface{}{map[string]gocql.TypeInfo(nil), nil}},
		{"Columns", []interface{}{"a", "b"}, []interface{}{map[string]gocql.TypeInfo{"c": gocql.NativeType{}}, e}},
		{"QueryBatch", []interface{}{BatchKind(0)}, []interface{}{(*batch)(nil)}},
		{"QueryBatch", []interface{}{BatchKind(1)}, []interface{}{&batch{}}},
		{"QueryExec", []interface{}{"", []interface{}(nil)}, []interface{}{nil}},
		{"QueryExec", []interface{}{"a", []interface{}{1}}, []interface{}{e}},
		{"QueryIterator", []interface{}{"", []interface{}(nil)}, []interface{}{(*iterator)(nil)}},
		{"QueryIterator", []interface{}{"a", []interface{}{1}}, []interface{}{iterator{}}},
		{"QueryScan", []interface{}{"", []interface{}(nil), []interface{}(nil)}, []interface{}{nil}},
		{"QueryScan", []interface{}{"a", []interface{}{1}, []interface{}{1}}, []interface{}{e}},
		{"QueryScanMap", []interface{}{"", []interface{}(nil), map[string]interface{}(nil)}, []interface{}{nil}},
		{"QueryScanMap", []interface{}{"a", []interface{}{1}, map[string]interface{}{"b": 2}}, []interface{}{e}},
		{"QueryScanMapTx", []interface{}{"", []interface{}(nil), map[string]interface{}(nil)}, []interface{}{false, nil}},
		{"QueryScanMapTx", []interface{}{"a", []interface{}{1}, map[string]interface{}{"b": 2}}, []interface{}{true, e}},
		{"QuerySliceMap", []interface{}{"", []interface{}(nil)}, []interface{}{[]map[string]interface{}(nil), nil}},
		{"QuerySliceMap", []interface{}{"a", []interface{}{1}}, []interface{}{[]map[string]interface{}{{"b": 2}}, e}},
		{"Tables", []interface{}{""}, []interface{}{[]string(nil), nil}},
		{"Tables", []interface{}{"a"}, []interface{}{[]string{"b"}, e}},
	})
}

func TestSessionQuery(t *testing.T) {
	var s = newSession(t)

	defer s.Close()

	var exec = func(q string) {
		if err := s.QueryExec(q); err != nil {
			t.Fatalf("Actual error %v, expected no error", err)
		}
	}

	exec(ksDropIf)
	exec(ksCreate)

	defer exec(ksDrop)

	exec(tabCreate)

	defer exec(tabDrop)

	exec(rowInsert)

	// QueryBatch
	if s.QueryBatch(BatchKind(0)) == nil {
		t.Error("Actual batch nil, expected not nil")
	}

	// QueryIterator
	if s.QueryIterator("select * from gockle_test.test") == nil {
		t.Error("Actual iterator nil, expected not nil")
	}

	// QueryScan
	var id, n int

	if err := s.QueryScan("select id, n from gockle_test.test", nil, []interface{}{&id, &n}); err == nil {
		if id != 1 {
			t.Errorf("Actual id %v, expected 1", id)
		}

		if n != 2 {
			t.Errorf("Actual n %v, expected 2", n)
		}
	} else {
		t.Errorf("Actual error %v, expected no error", err)
	}

	// QueryScanMap
	var am, em = map[string]interface{}{}, map[string]interface{}{"id": 1, "n": 2}

	if err := s.QueryScanMap("select id, n from gockle_test.test", nil, am); err == nil {
		if !reflect.DeepEqual(am, em) {
			t.Errorf("Actual map %v, expected %v", am, em)
		}
	} else {
		t.Errorf("Actual error %v, expected no error", err)
	}

	// QueryScanMapTx
	am = map[string]interface{}{}

	if b, err := s.QueryScanMapTx("update gockle_test.test set n = 3 where id = 1 if n = 2", nil, am); err == nil {
		if !b {
			t.Error("Actual applied false, expected true")
		}

		if l := len(am); l != 0 {
			t.Errorf("Actual length %v, expected 0", l)
		}
	} else {
		t.Errorf("Actual error %v, expected no error", err)
	}

	// QuerySliceMap
	var es = []map[string]interface{}{{"id": 1, "n": 3}}

	if as, err := s.QuerySliceMap("select * from gockle_test.test"); err == nil {
		if !reflect.DeepEqual(as, es) {
			t.Errorf("Actual rows %v, expected %v", as, es)
		}
	} else {
		t.Errorf("Actual error %v, expected no error", err)
	}
}

func newSession(t *testing.T) Session {
	var c = gocql.NewCluster("localhost")

	c.ProtoVersion = version
	c.Timeout = 5 * time.Second

	var s, err = c.CreateSession()

	if err != nil {
		t.Skip(err)
	}

	return NewSession(s)
}

func testMock(t *testing.T, i interface{}, m *mock.Mock, tests []struct {
	method    string
	arguments []interface{}
	results   []interface{}
}) {
	var v = reflect.ValueOf(i)

	for _, test := range tests {
		t.Log("Test:", test)
		m.Reset()
		m.When(test.method, test.arguments...).Return(test.results...)

		var vs []reflect.Value

		for _, a := range test.arguments {
			vs = append(vs, reflect.ValueOf(a))
		}

		var method = v.MethodByName(test.method)

		if method.Type().IsVariadic() {
			vs = method.CallSlice(vs)
		} else {
			vs = method.Call(vs)
		}

		var is []interface{}

		for _, v := range vs {
			is = append(is, v.Interface())
		}

		if !reflect.DeepEqual(is, test.results) {
			t.Errorf("Actual %v, expected %v", is, test.results)
		}
	}
}
<commit_msg>Fix to skip on error<commit_after>package gockle

import (
	"fmt"
	"reflect"
	"testing"
	"time"

	"github.com/gocql/gocql"
	"github.com/maraino/go-mock"
)

const version = 4

const (
	ksCreate  = "create keyspace gockle_test with replication = {'class': 'SimpleStrategy', 'replication_factor': 1};"
	ksDrop    = "drop keyspace gockle_test"
	ksDropIf  = "drop keyspace if exists gockle_test"
	rowInsert = "insert into gockle_test.test (id, n) values (1, 2)"
	tabCreate = "create table gockle_test.test(id int primary key, n int)"
	tabDrop   = "drop table gockle_test.test"
)

func TestNewSession(t *testing.T) {
	if a, e := NewSession(nil), (session{}); a != e {
		t.Errorf("Actual session %v, expected %v", a, e)
	}

	var c = gocql.NewCluster("localhost")

	c.ProtoVersion = version

	var s, err = c.CreateSession()

	if err != nil {
		t.Skip(err)
	}

	if a, e := NewSession(s), (session{s: s}); a != e {
		t.Errorf("Actual session %v, expected %v", a, e)
	}
}

func TestNewSimpleSession(t *testing.T) {
	if s, err := NewSimpleSession(); err == nil {
		t.Error("Actual no error, expected error")
	} else if s != nil {
		t.Errorf("Actual session %v, expected nil", s)
		s.Close()
	}

	if a, err := NewSimpleSession("localhost"); err != nil {
		t.Skip(err)
	} else if a == nil {
		t.Errorf("Actual session nil, expected not nil")
	} else {
		a.Close()
	}
}

func TestSessionMetadata(t *testing.T) {
	var exec = func(s Session, q string) {
		if err := s.QueryExec(q); err != nil {
			t.Fatalf("Actual error %v, expected no error", err)
		}
	}

	var s = newSession(t)

	exec(s, ksDropIf)
	exec(s, ksCreate)

	defer exec(s, ksDrop)

	exec(s, tabCreate)

	defer exec(s, tabDrop)

	s = newSession(t)

	if a, err := s.Tables("gockle_test"); err == nil {
		if e := ([]string{"test"}); !reflect.DeepEqual(a, e) {
			t.Fatalf("Actual tables %v, expected %v", a, e)
		}
	} else {
		t.Fatalf("Actual error %v, expected no error", err)
	}

	s.Close()

	if _, err := s.Tables("gockle_test"); err == nil {
		t.Errorf("Actual no error, expected error")
	}

	s = newSession(t)

	if a, err := s.Columns("gockle_test", "test"); err == nil {
		var ts = map[string]gocql.Type{"id": gocql.TypeInt, "n": gocql.TypeInt}

		if la, le := len(a), len(ts); la == le {
			for n, at := range a {
				if et, ok := ts[n]; ok {
					if at.Type() != et {
						t.Fatalf("Actual type %v, expected %v", at, et)
					}
				} else {
					t.Fatalf("Actual name %v invalid, expected valid", n)
				}
			}
		} else {
			t.Fatalf("Actual count %v, expected %v", la, le)
		}
	} else {
		t.Fatalf("Actual error %v, expected no error", err)
	}

	if _, err := s.Columns("gockle_test", "invalid"); err == nil {
		t.Error("Actual no error, expected error")
	}

	s.Close()

	if _, err := s.Columns("gockle_test", "test"); err == nil {
		t.Error("Actual no error, expected error")
	}
}

func TestSessionMock(t *testing.T) {
	var m, e = &SessionMock{}, fmt.Errorf("e")

	testMock(t, m, &m.Mock, []struct {
		method    string
		arguments []interface{}
		results   []interface{}
	}{
		{"Close", nil, nil},
		{"Columns", []interface{}{"", ""}, []interface{}{map[string]gocql.TypeInfo(nil), nil}},
		{"Columns", []interface{}{"a", "b"}, []interface{}{map[string]gocql.TypeInfo{"c": gocql.NativeType{}}, e}},
		{"QueryBatch", []interface{}{BatchKind(0)}, []interface{}{(*batch)(nil)}},
		{"QueryBatch", []interface{}{BatchKind(1)}, []interface{}{&batch{}}},
		{"QueryExec", []interface{}{"", []interface{}(nil)}, []interface{}{nil}},
		{"QueryExec", []interface{}{"a", []interface{}{1}}, []interface{}{e}},
		{"QueryIterator", []interface{}{"", []interface{}(nil)}, []interface{}{(*iterator)(nil)}},
		{"QueryIterator", []interface{}{"a", []interface{}{1}}, []interface{}{iterator{}}},
		{"QueryScan", []interface{}{"", []interface{}(nil), []interface{}(nil)}, []interface{}{nil}},
		{"QueryScan", []interface{}{"a", []interface{}{1}, []interface{}{1}}, []interface{}{e}},
		{"QueryScanMap", []interface{}{"", []interface{}(nil), map[string]interface{}(nil)}, []interface{}{nil}},
		{"QueryScanMap", []interface{}{"a", []interface{}{1}, map[string]interface{}{"b": 2}}, []interface{}{e}},
		{"QueryScanMapTx", []interface{}{"", []interface{}(nil), map[string]interface{}(nil)}, []interface{}{false, nil}},
		{"QueryScanMapTx", []interface{}{"a", []interface{}{1}, map[string]interface{}{"b": 2}}, []interface{}{true, e}},
		{"QuerySliceMap", []interface{}{"", []interface{}(nil)}, []interface{}{[]map[string]interface{}(nil), nil}},
		{"QuerySliceMap", []interface{}{"a", []interface{}{1}}, []interface{}{[]map[string]interface{}{{"b": 2}}, e}},
		{"Tables", []interface{}{""}, []interface{}{[]string(nil), nil}},
		{"Tables", []interface{}{"a"}, []interface{}{[]string{"b"}, e}},
	})
}

func TestSessionQuery(t *testing.T) {
	var s = newSession(t)

	defer s.Close()

	var exec = func(q string) {
		if err := s.QueryExec(q); err != nil {
			t.Fatalf("Actual error %v, expected no error", err)
		}
	}

	exec(ksDropIf)
	exec(ksCreate)

	defer exec(ksDrop)

	exec(tabCreate)

	defer exec(tabDrop)

	exec(rowInsert)

	// QueryBatch
	if s.QueryBatch(BatchKind(0)) == nil {
		t.Error("Actual batch nil, expected not nil")
	}

	// QueryIterator
	if s.QueryIterator("select * from gockle_test.test") == nil {
		t.Error("Actual iterator nil, expected not nil")
	}

	// QueryScan
	var id, n int

	if err := s.QueryScan("select id, n from gockle_test.test", nil, []interface{}{&id, &n}); err == nil {
		if id != 1 {
			t.Errorf("Actual id %v, expected 1", id)
		}

		if n != 2 {
			t.Errorf("Actual n %v, expected 2", n)
		}
	} else {
		t.Errorf("Actual error %v, expected no error", err)
	}

	// QueryScanMap
	var am, em = map[string]interface{}{}, map[string]interface{}{"id": 1, "n": 2}

	if err := s.QueryScanMap("select id, n from gockle_test.test", nil, am); err == nil {
		if !reflect.DeepEqual(am, em) {
			t.Errorf("Actual map %v, expected %v", am, em)
		}
	} else {
		t.Errorf("Actual error %v, expected no error", err)
	}

	// QueryScanMapTx
	am = map[string]interface{}{}

	if b, err := s.QueryScanMapTx("update gockle_test.test set n = 3 where id = 1 if n = 2", nil, am); err == nil {
		if !b {
			t.Error("Actual applied false, expected true")
		}

		if l := len(am); l != 0 {
			t.Errorf("Actual length %v, expected 0", l)
		}
	} else {
		t.Errorf("Actual error %v, expected no error", err)
	}

	// QuerySliceMap
	var es = []map[string]interface{}{{"id": 1, "n": 3}}

	if as, err := s.QuerySliceMap("select * from gockle_test.test"); err == nil {
		if !reflect.DeepEqual(as, es) {
			t.Errorf("Actual rows %v, expected %v", as, es)
		}
	} else {
		t.Errorf("Actual error %v, expected no error", err)
	}
}

func newSession(t *testing.T) Session {
	var c = gocql.NewCluster("localhost")

	c.ProtoVersion = version
	c.Timeout = 5 * time.Second

	var s, err = c.CreateSession()

	if err != nil {
		t.Skip(err)
	}

	return NewSession(s)
}

func testMock(t *testing.T, i interface{}, m *mock.Mock, tests []struct {
	method    string
	arguments []interface{}
	results   []interface{}
}) {
	var v = reflect.ValueOf(i)

	for _, test := range tests {
		t.Log("Test:", test)
		m.Reset()
		m.When(test.method, test.arguments...).Return(test.results...)

		var vs []reflect.Value

		for _, a := range test.arguments {
			vs = append(vs, reflect.ValueOf(a))
		}

		var method = v.MethodByName(test.method)

		if method.Type().IsVariadic() {
			vs = method.CallSlice(vs)
		} else {
			vs = method.Call(vs)
		}

		var is []interface{}

		for _, v := range vs {
			is = append(is, v.Interface())
		}

		if !reflect.DeepEqual(is, test.results) {
			t.Errorf("Actual %v, expected %v", is, test.results)
		}
	}
}
<|endoftext|>


<commit_before>package qb

import (
	"github.com/stretchr/testify/assert"
	"testing"
)

func TestSession(t *testing.T) {

	engine, err := NewEngine("postgres", "user=root dbname=pqtest")

	assert.Equal(t, err, nil)

	session := NewSession(engine)

	assert.Equal(t, session.Engine(), engine)
}
<commit_msg>fix dbname of session tests<commit_after>package qb

import (
	"github.com/stretchr/testify/assert"
	"testing"
)

func TestSession(t *testing.T) {

	engine, err := NewEngine("postgres", "user=root dbname=qb_test")

	assert.Equal(t, err, nil)

	session := NewSession(engine)

	assert.Equal(t, session.Engine(), engine)
}
<|endoftext|>


<commit_before>package cli

import (
	"fmt"
	"os"
	"strings"

	"github.com/bitrise-io/go-utils/colorstring"
	"github.com/bitrise-io/goinp/goinp"
	"github.com/codegangsta/cli"
	"github.com/ricardopereira/go-get-youtube/youtube"
)

var (
	youTubeFlags = []cli.Flag{
		cli.StringFlag{
			Name:  "download, d",
			Value: "",
			Usage: "Download a YouTube video from url or id",
		},
	}
)

func doYouTube(c *cli.Context) {
	println(colorstring.Redf("YouTube"))

	input := c.String("download")

	if input != "" {
		println("Argument:", input)
	}

	// Check if the argument is url or id
	if strings.HasPrefix(input, "http") {
		//"https://www.youtube.com/watch?v={id}"
		//"https://youtube.com/watch?v={id}"
		//"https://youtu.be/{id}"

		// Remove uri
		input = strings.Replace(input, "https://", "", 1)
		input = strings.Replace(input, "http://", "", 1)
		input = strings.Replace(input, "www.", "", 1)
		input = strings.Replace(input, "youtube.com/watch?v=", "", 1)
		input = strings.Replace(input, "youtu.be/", "", 1)

		println("Argument is url")
	} else {
		println("Argument is video id")
	}

	println("Video:", input)

	cancel := 0
	// Get video interface and metadata
	video, err := youtube.Get(input)

	if err != nil {
		fmt.Println(colorstring.Redf("Error:", err))
		os.Exit(0)
	} else {
		fmt.Println("Metadata:")
		fmt.Println(" - title:", video.Title)
		fmt.Println(" - length:", float64(video.Length_seconds)/60.0, "min")

		fmt.Println(" - format:")
		i := 0
		for i < len(video.Formats) {
			format := video.Formats[i]
			fmt.Println("    ", i, "-", format.Quality, format.Video_type)
			i++
		}
		cancel = i
		fmt.Println("    ", cancel, "-", "Cancel")
	}

	ask := ""
	if value, err := goinp.AskForInt(ask); err != nil {
		fmt.Println(colorstring.Redf("Error:", err))
		os.Exit(0)
	} else if value == int64(cancel) {
		fmt.Println("Canceled")
	} else {
		fmt.Println(value)
	}

}
<commit_msg>Fixed name of output<commit_after>package cli

import (
	"fmt"
	"os"
	"strings"

	"github.com/bitrise-io/go-utils/colorstring"
	"github.com/bitrise-io/goinp/goinp"
	"github.com/codegangsta/cli"
	"github.com/ricardopereira/go-get-youtube/youtube"
)

var (
	youTubeFlags = []cli.Flag{
		cli.StringFlag{
			Name:  "download, d",
			Value: "",
			Usage: "Download a YouTube video from url or id",
		},
	}
)

func doYouTube(c *cli.Context) {
	println(colorstring.Redf("YouTube"))

	input := c.String("download")

	if input != "" {
		println("Argument:", input)
	}

	// Check if the argument is url or id
	if strings.HasPrefix(input, "http") {
		//"https://www.youtube.com/watch?v={id}"
		//"https://youtube.com/watch?v={id}"
		//"https://youtu.be/{id}"

		// Remove uri
		input = strings.Replace(input, "https://", "", 1)
		input = strings.Replace(input, "http://", "", 1)
		input = strings.Replace(input, "www.", "", 1)
		input = strings.Replace(input, "youtube.com/watch?v=", "", 1)
		input = strings.Replace(input, "youtu.be/", "", 1)

		println("Argument is url")
	} else {
		println("Argument is video id")
	}

	println("Video:", input)

	cancel := 0
	// Get video interface and metadata
	video, err := youtube.Get(input)

	if err != nil {
		fmt.Println(colorstring.Redf("Error:", err))
		os.Exit(0)
	} else {
		fmt.Println("Metadata:")
		fmt.Println(" - title:", video.Title)
		fmt.Println(" - length:", float64(video.Length_seconds)/60.0, "min")

		fmt.Println(" - format:")
		i := 0
		for i < len(video.Formats) {
			format := video.Formats[i]
			fmt.Println("    ", i, "-", format.Quality, format.Video_type)
			i++
		}
		cancel = i
		fmt.Println("    ", cancel, "-", "Cancel")
	}

	ask := "Select format to download"
	if option, err := goinp.AskForInt(ask); err != nil {
		fmt.Println(colorstring.Redf("Error:", err))
	} else if int(option) == cancel {
		fmt.Println(colorstring.Yellowf("Cancelled"))
	} else {
		video.Download(int(option), video.Id+"."+video.GetExtension(int(option)))
		fmt.Println(colorstring.Greenf("Success"))
	}

}
<|endoftext|>


<commit_before>package cli

import (
	"gopkg.in/alecthomas/kingpin.v2"
)

type ServerGroupsCommand struct {
	App *CliApp
	Id  string
}

func (l *ServerGroupsCommand) list(pc *kingpin.ParseContext) error {
	err := l.App.Configure()
	if err != nil {
		return err
	}
	groups, err := l.App.Client.ServerGroups()
	if err != nil {
		return err
	}
	w := tabWriter()
	defer w.Flush()
	listRec(w, "ID", "SERVER_COUNT", "NAME")
	for _, s := range *groups {
		listRec(
			w, s.Id, len(s.Servers), s.Name)
	}
	return nil
}

func ConfigureServerGroupsCommand(app *CliApp) {
	cmd := ServerGroupsCommand{App: app}
	groups := app.Command("groups", "manage server groups")
	groups.Command("list", "list server groups").Action(cmd.list)
}
<commit_msg>server groups: create, update, list, destroy, show<commit_after>package cli

import (
	"fmt"
	"github.com/brightbox/gobrightbox"
	"gopkg.in/alecthomas/kingpin.v2"
)

type ServerGroupsCommand struct {
	App         *CliApp
	Id          string
	IdList      []string
	Name        *string
	Description *string
}

func (l *ServerGroupsCommand) list(pc *kingpin.ParseContext) error {
	err := l.App.Configure()
	if err != nil {
		return err
	}
	groups, err := l.App.Client.ServerGroups()
	if err != nil {
		return err
	}
	w := tabWriter()
	defer w.Flush()
	listRec(w, "ID", "SERVER_COUNT", "FWPOLICY", "NAME")
	for _, s := range *groups {
		listRec(
			w, s.Id, len(s.Servers), s.FirewallPolicy.Id, s.Name)
	}
	return nil
}

func (l *ServerGroupsCommand) show(pc *kingpin.ParseContext) error {
	err := l.App.Configure()
	if err != nil {
		return err
	}
	w := tabWriterRight()
	defer w.Flush()
	g, err := l.App.Client.ServerGroup(l.Id)
	if err != nil {
		l.App.Fatalf(err.Error())
	}

	drawShow(w, []interface{}{
		"id", g.Id,
		"name", g.Name,
		"default", g.Default,
		"servers", collectById(g.Servers),
		"firewall_policy", g.FirewallPolicy.Id,
		"description", g.Description,
	})
	return nil

}

func (l *ServerGroupsCommand) create(pc *kingpin.ParseContext) error {
	err := l.App.Configure()
	if err != nil {
		return err
	}
	newGroup := brightbox.ServerGroupOptions{
		Name:        l.Name,
		Description: l.Description,
	}

	group, err := l.App.Client.CreateServerGroup(&newGroup)
	if err != nil {
		return err
	}
	w := tabWriter()
	defer w.Flush()
	listRec(w, "ID", "SERVER_COUNT", "FWPOLICY", "NAME")
	listRec(
		w, group.Id, len(group.Servers), group.FirewallPolicy.Id, group.Name)
	return nil
}

func (l *ServerGroupsCommand) update(pc *kingpin.ParseContext) error {
	err := l.App.Configure()
	if err != nil {
		return err
	}
	updateGroup := brightbox.ServerGroupOptions{
		Identifier:  l.Id,
		Name:        l.Name,
		Description: l.Description,
	}
	group, err := l.App.Client.UpdateServerGroup(&updateGroup)
	if err != nil {
		return err
	}
	w := tabWriter()
	defer w.Flush()
	listRec(w, "ID", "SERVER_COUNT", "FWPOLICY", "NAME")
	listRec(
		w, group.Id, len(group.Servers), group.FirewallPolicy.Id, group.Name)
	return nil
}

func (l *ServerGroupsCommand) destroy(pc *kingpin.ParseContext) error {
	err := l.App.Configure()
	if err != nil {
		return err
	}
	returnError := false
	for _, id := range l.IdList {
		fmt.Printf("Destroying server group %s\n", id)
		err := l.App.Client.DestroyServerGroup(id)
		if err != nil {
			l.App.Errorf("%s: %s", err.Error(), id)
			returnError = true
		}
	}
	if returnError {
		return genericError
	}
	return nil
}

func ConfigureServerGroupsCommand(app *CliApp) {
	cmd := ServerGroupsCommand{App: app}
	groups := app.Command("groups", "manage server groups")
	groups.Command("list", "list server groups").
		Default().Action(cmd.list)

	show := groups.Command("show", "View details of a server group").
		Action(cmd.show)
	show.Arg("identifier", "id of server group to show").
		StringVar(&cmd.Id)

	create := groups.Command("create", "Create a new server group").
		Action(cmd.create)
	create.Flag("name", "Name to give the new server group").
		Short('n').SetValue(&pStringValue{&cmd.Name})
	create.Flag("description", "Description to give the new server group").
		Short('d').SetValue(&pStringValue{&cmd.Description})

	update := groups.Command("update", "Update a new server group").
		Action(cmd.update)
	update.Arg("identifier", "id of server group to update").
		Required().StringVar(&cmd.Id)
	update.Flag("name", "Set a new name for the server group").
		Short('n').SetValue(&pStringValue{&cmd.Name})
	update.Flag("description", "Set a new description for the server group").
		Short('d').SetValue(&pStringValue{&cmd.Description})

	destroy := groups.Command("destroy", "Destroy a server group").
		Action(cmd.destroy)
	destroy.Arg("identifier", "Identifier of server groupto destroy").
		Required().StringsVar(&cmd.IdList)

}
<|endoftext|>


<commit_before>// Client interface using the official stackato client binary

package client

import (
	"fmt"
	"github.com/ActiveState/log"
	"github.com/ActiveState/run"
	"os/exec"
)

type CliClient struct {
	TargetURL string
	Token     string
	Space     string
}

func NewCliClient(targetUrl, token, space string) (*CliClient, error) {
	if token == "" {
		return nil, fmt.Errorf("Token must not be empty")
	}
	if space == "" {
		return nil, fmt.Errorf("Space must not be empty")
	}
	c := &CliClient{targetUrl, token, space}
	return c, nil
}

// PushAppNoCreate emulates `s push --no-create ...` and sends the
// output in outputCh channel.
func (c *CliClient) PushAppNoCreate(name string, dir string, autoStart bool, outputCh chan string) (bool, error) {
	options := []string{
		name,
		"--no-tail", "--no-prompt",
		"--target", c.TargetURL,
		"--token", c.Token,
		"--space", c.Space,
		"--path", dir}

	if !autoStart {
		options = append(options, "--no-start")
	}

	pushOptions := append([]string{"push", "--no-create"}, options...)

	ret, err := run.Run(exec.Command("stackato", pushOptions...), outputCh)
	if err != nil {
		log.Error("cannot read line: ", err)
		return false, err
	}
	if r, ok := ret.(*exec.ExitError); ok {
		log.Errorf("Client exited abruptly: %v", r)
		return false, nil
	} else {
		return true, ret
	}
}
<commit_msg>--no-create is implicit in the v2 client<commit_after>// Client interface using the official stackato client binary

package client

import (
	"fmt"
	"github.com/ActiveState/log"
	"github.com/ActiveState/run"
	"os/exec"
)

type CliClient struct {
	TargetURL string
	Token     string
	Space     string
}

func NewCliClient(targetUrl, token, space string) (*CliClient, error) {
	if token == "" {
		return nil, fmt.Errorf("Token must not be empty")
	}
	if space == "" {
		return nil, fmt.Errorf("Space must not be empty")
	}
	c := &CliClient{targetUrl, token, space}
	return c, nil
}

// PushAppNoCreate emulates `s push ...` and sends the
// output in outputCh channel.
func (c *CliClient) PushAppNoCreate(name string, dir string, autoStart bool, outputCh chan string) (bool, error) {
	options := []string{
		"push",
		name,
		"--no-tail", "--no-prompt",
		"--target", c.TargetURL,
		"--token", c.Token,
		"--space", c.Space,
		"--path", dir}

	if !autoStart {
		options = append(options, "--no-start")
	}

	ret, err := run.Run(exec.Command("stackato", options...), outputCh)
	if err != nil {
		log.Error("cannot read line: ", err)
		return false, err
	}
	if r, ok := ret.(*exec.ExitError); ok {
		log.Errorf("Client exited abruptly: %v", r)
		return false, nil
	} else {
		return true, ret
	}
}
<|endoftext|>