<commit_before>// Copyright (c) 2017 Pani Networks
// All Rights Reserved.
//
// 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 agent

import (
	"fmt"
	"net/http"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/romana/core/agent/enforcer"
	log "github.com/romana/rlog"
)

var (
	NumManagedRoutes = prometheus.NewGauge(
		prometheus.GaugeOpts{
			Name: "romana_managed_routes_total",
			Help: "Number of routes managed by Romana agent on the host.",
		},
	)
)

func MetricStart(port int) error {
	if port <= 0 {
		return nil
	}

	registry := prometheus.NewRegistry()
	err := enforcer.MetricsRegister(registry)
	if err != nil {
		return err
	}

	err = registry.Register(NumManagedRoutes)
	if err != nil {
		return err
	}

	handler := promhttp.HandlerFor(registry, promhttp.HandlerOpts{ErrorHandling: promhttp.HTTPErrorOnError})

	go func() {
		http.Handle("/", handler)
		log.Errorf("Metrics publishing stopped due to %s", http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
	}()

	return nil
}
<commit_msg>Fix metric naming in agent<commit_after>// Copyright (c) 2017 Pani Networks
// All Rights Reserved.
//
// 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 agent

import (
	"fmt"
	"net/http"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/romana/core/agent/enforcer"
	log "github.com/romana/rlog"
)

var (
	NumManagedRoutes = prometheus.NewGauge(
		prometheus.GaugeOpts{
			Name: "romana_managed_routes",
			Help: "Number of routes managed by Romana agent on the host.",
		},
	)
)

func MetricStart(port int) error {
	if port <= 0 {
		return nil
	}

	registry := prometheus.NewRegistry()
	err := enforcer.MetricsRegister(registry)
	if err != nil {
		return err
	}

	err = registry.Register(NumManagedRoutes)
	if err != nil {
		return err
	}

	handler := promhttp.HandlerFor(registry, promhttp.HandlerOpts{ErrorHandling: promhttp.HTTPErrorOnError})

	go func() {
		http.Handle("/", handler)
		log.Errorf("Metrics publishing stopped due to %s", http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
	}()

	return nil
}
<|endoftext|>


<commit_before>//Package amazonproduct provides methods for interacting with the Amazon Product Advertising API
package amazonproduct

import ()

/*
ItemLookup takes a product ID (ASIN) and returns the result
*/
func (api AmazonProductAPI) ItemLookup(ItemId string) (string, error) {
	params := map[string]string{
		"ItemId":        ItemId,
		"ResponseGroup": "Images,ItemAttributes,Small,EditorialReview",
	}

	return api.genSignAndFetch("ItemLookup", params)
}

/*
ItemSearchByKeyword takes a string containg keywords and returns the search results
*/
func (api AmazonProductAPI) ItemSearchByKeyword(Keywords string) (string, error) {
	params := map[string]string{
		"Keywords":      Keywords,
		"ResponseGroup": "Images,ItemAttributes,Small,EditorialReview",
	}
	return api.ItemSearch("All", params)
}

func (api AmazonProductAPI) ItemSearchByKeywordWithResponseGroup(Keywords string, ResponseGroup string) (string, error) {
	params := map[string]string{
		"Keywords":      Keywords,
		"ResponseGroup": ResponseGroup,
	}
	return api.ItemSearch("All", params)
}

func (api AmazonProductAPI) ItemSearch(SearchIndex string, Parameters map[string]string) (string, error) {
	Parameters["SearchIndex"] = SearchIndex
	return api.genSignAndFetch("ItemSearch", Parameters)
}
<commit_msg>CartCreate method<commit_after>//Package amazonproduct provides methods for interacting with the Amazon Product Advertising API
package amazonproduct

import (
	"fmt"
	"strconv"
)

/*
ItemLookup takes a product ID (ASIN) and returns the result
*/
func (api AmazonProductAPI) ItemLookup(ItemId string) (string, error) {
	params := map[string]string{
		"ItemId":        ItemId,
		"ResponseGroup": "Images,ItemAttributes,Small,EditorialReview",
	}

	return api.genSignAndFetch("ItemLookup", params)
}

/*
ItemSearchByKeyword takes a string containg keywords and returns the search results
*/
func (api AmazonProductAPI) ItemSearchByKeyword(Keywords string) (string, error) {
	params := map[string]string{
		"Keywords":      Keywords,
		"ResponseGroup": "Images,ItemAttributes,Small,EditorialReview",
	}
	return api.ItemSearch("All", params)
}

func (api AmazonProductAPI) ItemSearchByKeywordWithResponseGroup(Keywords string, ResponseGroup string) (string, error) {
	params := map[string]string{
		"Keywords":      Keywords,
		"ResponseGroup": ResponseGroup,
	}
	return api.ItemSearch("All", params)
}

func (api AmazonProductAPI) ItemSearch(SearchIndex string, Parameters map[string]string) (string, error) {
	Parameters["SearchIndex"] = SearchIndex
	return api.genSignAndFetch("ItemSearch", Parameters)
}

/*
CartCreate takes a map containing ASINs and quantities. Up to 10 items are allowed
*/
func (api AmazonProductAPI) CartCreate(items map[string]int) (string, error){

	params := make(map[string]string)

	i := 1
	for k, v := range items {
		if i < 11 {
			key := fmt.Sprintf("Item.%d.ASIN", i)
			params[key] = string(k)

			key = fmt.Sprintf("Item.%d.Quantity", i)
			params[key] = strconv.Itoa(v)

			i++
		} else {
			break
		}
	}

	return api.genSignAndFetch("CartCreate", params)
}
<|endoftext|>


<commit_before>package analysis

import (
	"bufio"
	"fmt"
	"math/rand"
	"os"
)

// Dataset struct represents a dataset object.
type Dataset struct {
	id   string
	path string
}

// NewDataset is the constructor for the Dataset struct. A random ID is assigned
// to a new dataset
func NewDataset(path string) *Dataset {
	buffer := make([]byte, 4)
	rand.Read(buffer)
	id := fmt.Sprintf("%x", buffer)
	d := Dataset{id, path}
	return &d
}

// Id getter for dataset
func (d Dataset) Id() string {
	return d.id
}

// Path getter for dataset
func (d Dataset) Path() string {
	return d.path
}

// String method for dataset object - only returns its id
func (d Dataset) String() string {
	return d.Id()
}

// Analyzer interface that expresses the Analyzer's functionality
type Analyzer interface {
	// executes the analysis - blocking process
	Analyze() bool
	// returns the status of the Analyzer
	Status() Status
	// returns the result of the analyzer - a serialized version of it
	Result() Result
	//returns the duration of the analysis
	Duration() float64
	// returns the dataset of the analysis
	Dataset() Dataset
}

// Status is the type representing the domain of the Analyzer's status
type Status uint8

// Values of the AnalyzerStatus type
const (
	PENDING Status = iota + 1
	ANALYZING
	ANALYZED
)

// String method is used to print the Status enum in a pretty manner
func (s Status) String() string {
	switch s {
	case PENDING:
		return "PENDING"
	case ANALYZING:
		return "ANALYZING"
	case ANALYZED:
		return "ANALYZED"
	}
	return "UNKNOWN"
}

// Result struct holds the results of the analysis
type Result []float64

// Utility function used to partition a dataset into multiple disjoint subsets
// in a uniform manner
func DatasetPartition(original Dataset, copies int) []Dataset {
	// init new files
	newFiles := make([]*os.File, copies)
	results := make([]Dataset, copies)
	for i := 0; i < copies; i++ {
		fileName := fmt.Sprintf("%s-split-%d", original.Path(), i)
		newFiles[i], _ = os.Create(fileName)
		results[i] = *NewDataset(fileName)
	}
	file, _ := os.Open(original.Path())
	scanner := bufio.NewScanner(file)
	scanner.Scan()
	header := scanner.Text()
	for _, f := range newFiles {
		f.WriteString(header + "\n")
	}

	for scanner.Scan() {
		fileChosen := rand.Int() % copies
		newFiles[fileChosen].WriteString(scanner.Text() + "\n")
	}
	for _, f := range newFiles {
		f.Close()
	}
	file.Close()

	return results
}

// Function used to cleanup the file partitions
func DatasetPartitionCleanup(datasets []Dataset) {
	for _, d := range datasets {
		os.Remove(d.Path())
	}
}
<commit_msg>added random time seed initialization before breaking the datasets<commit_after>package analysis

import (
	"bufio"
	"fmt"
	"math/rand"
	"os"
	"time"
)

// Dataset struct represents a dataset object.
type Dataset struct {
	id   string
	path string
}

// NewDataset is the constructor for the Dataset struct. A random ID is assigned
// to a new dataset
func NewDataset(path string) *Dataset {
	buffer := make([]byte, 4)
	rand.Read(buffer)
	id := fmt.Sprintf("%x", buffer)
	d := Dataset{id, path}
	return &d
}

// Id getter for dataset
func (d Dataset) Id() string {
	return d.id
}

// Path getter for dataset
func (d Dataset) Path() string {
	return d.path
}

// String method for dataset object - only returns its id
func (d Dataset) String() string {
	return d.Id()
}

// Analyzer interface that expresses the Analyzer's functionality
type Analyzer interface {
	// executes the analysis - blocking process
	Analyze() bool
	// returns the status of the Analyzer
	Status() Status
	// returns the result of the analyzer - a serialized version of it
	Result() Result
	//returns the duration of the analysis
	Duration() float64
	// returns the dataset of the analysis
	Dataset() Dataset
}

// Status is the type representing the domain of the Analyzer's status
type Status uint8

// Values of the AnalyzerStatus type
const (
	PENDING Status = iota + 1
	ANALYZING
	ANALYZED
)

// String method is used to print the Status enum in a pretty manner
func (s Status) String() string {
	switch s {
	case PENDING:
		return "PENDING"
	case ANALYZING:
		return "ANALYZING"
	case ANALYZED:
		return "ANALYZED"
	}
	return "UNKNOWN"
}

// Result struct holds the results of the analysis
type Result []float64

// Utility function used to partition a dataset into multiple disjoint subsets
// in a uniform manner
func DatasetPartition(original Dataset, copies int) []Dataset {
	// init new files
	newFiles := make([]*os.File, copies)
	results := make([]Dataset, copies)
	for i := 0; i < copies; i++ {
		fileName := fmt.Sprintf("%s-split-%d", original.Path(), i)
		newFiles[i], _ = os.Create(fileName)
		results[i] = *NewDataset(fileName)
	}
	file, _ := os.Open(original.Path())
	scanner := bufio.NewScanner(file)
	scanner.Scan()
	header := scanner.Text()
	for _, f := range newFiles {
		f.WriteString(header + "\n")
	}

	rand.Seed(int64(time.Now().Nanosecond()))
	for scanner.Scan() {
		fileChosen := rand.Int() % copies
		newFiles[fileChosen].WriteString(scanner.Text() + "\n")
	}
	for _, f := range newFiles {
		f.Close()
	}
	file.Close()

	return results
}

// Function used to cleanup the file partitions
func DatasetPartitionCleanup(datasets []Dataset) {
	for _, d := range datasets {
		os.Remove(d.Path())
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"errors"
	"fmt"
	// "log"
	"os"
	"strings"
)

var torrentDB *TorrentDB
var err error

const resultLimit int = 100

func main() {
	// Try to connect to the database
	torrentDB, err = NewTorrentDB("127.0.0.1")
	if err != nil {
		fmt.Println("Couldn't connect to Mongo. Please make sure it is installed and running.")
		return
	}
	defer torrentDB.Close()

	if len(os.Args) > 1 {
		importFile(os.Args[1])
	} else {
		runServer()
	}
}

func runServer() {
	fmt.Println("Starting the API server.")
	api := NewAPI()
	api.AddRoutes()
	api.Run(":1337")
}

func importFile(filename string) {
	fmt.Print("Attempting to parse ")
	fmt.Println(filename)

	file, err := os.Open(filename)
	if err != nil {
		fmt.Println("Error opening the file. Make sure it exists and is readable.")
		return
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	imported := 0
	skipped := 0
	for scanner.Scan() {
		status, _ := importLine(scanner.Text())
		if status {
			imported++
		} else {
			skipped++
		}
	}

	fmt.Println("File parsing ended.")
	fmt.Print("New: ")
	fmt.Println(imported)
	fmt.Print("Dup: ")
	fmt.Println(skipped)

	if err := scanner.Err(); err != nil {
		fmt.Println("The program encountered an error while reading the file. Ensure that the file isn't corrupted.")
		return
	}
}

func importLine(line string) (bool, error) {
	if strings.Count(line, "|") != 4 {
		return false, errors.New("Something's up with this torrent. Expected 5 values separated by |.")
	}
	data := strings.Split(line, "|")
	return torrentDB.Insert(data[0], data[1], data[2], data[3], data[4])
}
<commit_msg>Read from the config file and overwrite default mongo ip.<commit_after>package main

import (
	"bufio"
	"errors"
	"fmt"
	// "log"
	"github.com/antonholmquist/jason"
	"io/ioutil"
	"os"
	"strings"
)

var torrentDB *TorrentDB
var err error

const resultLimit int = 100

func main() {
	// Get mongo url from config.json, otherwise default to 127.0.0.1
	mongo := "127.0.0.1"
	f, err := ioutil.ReadFile("config.json")
	if err == nil {
		json, err := jason.NewObjectFromBytes(f)
		if err == nil {
			val, err := json.GetString("mongo")
			if err == nil {
				mongo = val
			}
		}
	}
	// Try to connect to the database
	fmt.Println("Connecting to Mongo at " + mongo)
	torrentDB, err = NewTorrentDB(mongo)
	if err != nil {
		fmt.Println("Couldn't connect to Mongo. Please make sure it is installed and running.")
		return
	}
	defer torrentDB.Close()

	if len(os.Args) > 1 {
		importFile(os.Args[1])
	} else {
		runServer()
	}
}

func runServer() {
	fmt.Println("Starting the API server.")
	api := NewAPI()
	api.AddRoutes()
	api.Run(":1337")
}

func importFile(filename string) {
	fmt.Print("Attempting to parse ")
	fmt.Println(filename)

	file, err := os.Open(filename)
	if err != nil {
		fmt.Println("Error opening the file. Make sure it exists and is readable.")
		return
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	imported := 0
	skipped := 0
	for scanner.Scan() {
		status, _ := importLine(scanner.Text())
		if status {
			imported++
		} else {
			skipped++
		}
	}

	fmt.Println("File parsing ended.")
	fmt.Print("New: ")
	fmt.Println(imported)
	fmt.Print("Dup: ")
	fmt.Println(skipped)

	if err := scanner.Err(); err != nil {
		fmt.Println("The program encountered an error while reading the file. Ensure that the file isn't corrupted.")
		return
	}
}

func importLine(line string) (bool, error) {
	if strings.Count(line, "|") != 4 {
		return false, errors.New("Something's up with this torrent. Expected 5 values separated by |.")
	}
	data := strings.Split(line, "|")
	return torrentDB.Insert(data[0], data[1], data[2], data[3], data[4])
}
<|endoftext|>


<commit_before>package u3

import (
	"net/http"

	"gist.github.com/7390843.git"

	"github.com/shurcooL/go/u/u1"
	"github.com/shurcooL/go/u/u4"
)

// Displays given Markdown in a new browser window/tab.
func DisplayMarkdownInBrowser(markdown []byte) {
	stopServerChan := make(chan struct{})

	handler := func(w http.ResponseWriter, req *http.Request) {
		u1.WriteMarkdownGfmAsHtmlPage(w, markdown)

		stopServerChan <- struct{}{}
	}

	http.HandleFunc("/index", handler)
	http.Handle("/favicon.ico", http.NotFoundHandler())

	// TODO: Aquire a free port similarly to using ioutil.TempFile() for files.
	// TODO: Consider using httptest.NewServer.
	u4.Open("http://localhost:7044/index")

	err := gist7390843.ListenAndServeStoppable("localhost:7044", nil, stopServerChan)
	if err != nil {
		panic(err)
	}
}

// Displays given html page in a new browser window/tab.
func DisplayHtmlInBrowser(mux *http.ServeMux, stopServerChan <-chan struct{}, query string) {
	// TODO: Aquire a free port similarly to using ioutil.TempFile() for files.
	u4.Open("http://localhost:7044/index" + query)

	err := gist7390843.ListenAndServeStoppable("localhost:7044", mux, stopServerChan)
	if err != nil {
		panic(err)
	}
}
<commit_msg>DisplayMarkdownInBrowser: Update to new API, use local GFM rendering.<commit_after>package u3

import (
	"net/http"

	"gist.github.com/7390843.git"

	"github.com/shurcooL/go/u/u1"
	"github.com/shurcooL/go/u/u4"
)

// Displays given Markdown in a new browser window/tab.
func DisplayMarkdownInBrowser(markdown []byte) {
	stopServerChan := make(chan struct{})

	handler := func(w http.ResponseWriter, req *http.Request) {
		u1.WriteGitHubFlavoredMarkdownViaLocal(w, markdown)

		stopServerChan <- struct{}{}
	}

	http.HandleFunc("/index", handler)
	http.Handle("/favicon.ico", http.NotFoundHandler())

	// TODO: Aquire a free port similarly to using ioutil.TempFile() for files.
	// TODO: Consider using httptest.NewServer.
	u4.Open("http://localhost:7044/index")

	err := gist7390843.ListenAndServeStoppable("localhost:7044", nil, stopServerChan)
	if err != nil {
		panic(err)
	}
}

// Displays given html page in a new browser window/tab.
func DisplayHtmlInBrowser(mux *http.ServeMux, stopServerChan <-chan struct{}, query string) {
	// TODO: Aquire a free port similarly to using ioutil.TempFile() for files.
	u4.Open("http://localhost:7044/index" + query)

	err := gist7390843.ListenAndServeStoppable("localhost:7044", mux, stopServerChan)
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2011 Miek Gieben. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build !linux

package dns

import (
	"net"
)

// These do nothing. See udp_linux.go for an example of how to implement this.

// We tried to adhire to some kind of naming scheme.

func setUDPSocketOptions4(conn *net.UDPConn) error                { return nil }
func setUDPSocketOptions6(conn *net.UDPConn) error                { return nil }
func getUDPSocketOptions6Only(conn *net.UDPConn) (bool, error)    { return false, nil }
func getUDPSocketName(conn *net.UDPConn) (syscall.Sockaddr, error) { return nil, nil }
<commit_msg>And add the import<commit_after>// Copyright 2011 Miek Gieben. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build !linux

package dns

import (
	"net"
	"syscall"
)

// These do nothing. See udp_linux.go for an example of how to implement this.

// We tried to adhire to some kind of naming scheme.

func setUDPSocketOptions4(conn *net.UDPConn) error                { return nil }
func setUDPSocketOptions6(conn *net.UDPConn) error                { return nil }
func getUDPSocketOptions6Only(conn *net.UDPConn) (bool, error)    { return false, nil }
func getUDPSocketName(conn *net.UDPConn) (syscall.Sockaddr, error) { return nil, nil }
<|endoftext|>


<commit_before>// package ui provides the UI components of Goed.
package ui

import (
	"fmt"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"

	"github.com/tcolar/goed/actions"
	"github.com/tcolar/goed/backend"
	"github.com/tcolar/goed/core"
	"github.com/tcolar/termbox-go"
)

// Editor is goed's main Editor pane (singleton)
type Editor struct {
	Cmdbar     *Cmdbar
	config     *core.Config
	Statusbar  *Statusbar
	Fg, Bg     core.Style
	theme      *core.Theme
	Cols       []*Col
	curView    *View
	CurCol     *Col
	cmdOn      bool
	pctw, pcth float64
	evtState   *EvtState
	term       core.Term
}

func NewEditor() *Editor {
	return &Editor{
		term:   core.NewTermBox(),
		config: core.LoadConfig(core.ConfFile),
	}
}

// Editor with Mock terminal for testing
func NewMockEditor() *Editor {
	return &Editor{
		term:   core.NewMockTerm(),
		config: core.LoadConfig("config.toml"),
	}
}

func (e *Editor) Dispatch(action core.Action) {
	core.Bus.Dispatch(action)
}

// Start starts-up the editor
func (e *Editor) Start(locs []string) {
	err := e.term.Init()
	if err != nil {
		panic(err)
	}

	defer func() {
		// TODO: should set it to original value, but how to read it ??
		e.term.SetMouseMode(termbox.MouseClick)
		e.term.Close()
	}()
	e.term.SetExtendedColors(core.Colors == 256)
	e.evtState = &EvtState{}
	e.theme, err = core.ReadTheme(core.FindResource(path.Join("themes", e.config.Theme)))
	if err != nil {
		panic(err)
	}
	e.Fg = e.theme.Fg
	e.Bg = e.theme.Bg

	h, w := e.term.Size()
	e.Cmdbar = &Cmdbar{}
	e.Cmdbar.SetBounds(0, 0, 0, w)
	e.Statusbar = &Statusbar{}
	e.Statusbar.SetBounds(h-1, 0, h-1, w)
	dirs := []string{}
	files := []string{}
	for _, loc := range locs {
		if stat, err := os.Stat(loc); err == nil && stat.IsDir() {
			dirs = append(dirs, loc)
		} else {
			files = append(files, loc)
		}
	}
	if len(dirs) == 0 {
		if len(files) > 0 {
			dirs = []string{path.Dir(locs[0])}
		} else {
			dirs = []string{"."}
		}
	}
	e.Cols = append(e.Cols, &Col{WidthRatio: 1.0})
	ratio := 1.0 / float64(len(dirs))
	for _, dir := range dirs {
		view := e.NewView(dir)
		view.HeightRatio = ratio
		e.Cols[0].Views = append(e.Cols[0].Views, view)
		e.Open(dir, view, "", true)
	}
	e.CurCol = e.Cols[0]
	e.curView = e.CurCol.Views[0]
	if len(files) > 0 {
		e.CurCol.WidthRatio = 0.2
		c := &Col{WidthRatio: 0.8}
		ratio := 1.0 / float64(len(files))
		for _, f := range files {
			view := e.NewView(f)
			view.HeightRatio = ratio
			c.Views = append(c.Views, view)
			e.Open(f, view, "", true)
		}
		e.Cols = append(e.Cols, c)
		e.CurCol = c
		e.curView = c.Views[0]
	}

	actions.EdResize(e.term.Size())

	actions.EdRender()

	go e.autoScroller()

	if !core.Testing {
		e.EventLoop()
	}
}

// Open opens a given location in the editor (in the given view)
// or new view if view is nil
func (e Editor) Open(loc string, view core.Viewable, rel string, create bool) (core.Viewable, error) {
	if len(rel) > 0 && !strings.HasPrefix(loc, string(os.PathSeparator)) {
		loc = path.Join(rel, loc)
	}
	// make it absolute
	loc, err := filepath.Abs(loc)
	if err != nil {
		return nil, err
	}
	stat, err := os.Stat(loc)
	newFile := false
	if os.IsNotExist(err) {
		if !create {
			return nil, err
		}
		newFile = true
	}
	title := filepath.Base(loc)
	if !newFile && stat.IsDir() {
		loc += string(os.PathSeparator)
		title += string(os.PathSeparator)
	}
	nv := false
	if view == nil {
		view = e.NewFileView(loc)
		nv = true
	}
	view.Reset()
	view.SetTitle(title)
	if newFile || !stat.IsDir() {
		err = e.openFile(loc, view)
	} else {
		err = e.openDir(loc, view)
	}
	if err != nil {
		return nil, err
	}
	if nv {
		e.InsertView(view.(*View), e.CurView().(*View), 0.2)
	}
	view.SetWorkDir(filepath.Dir(loc))
	return view, nil
}

// OpenDir opens a directory listing
func (e *Editor) openDir(loc string, view core.Viewable) error {
	args := []string{"ls", "-a", "--color=no"}
	title := filepath.Base(loc) + "/"
	backend, err := backend.NewMemBackendCmd(args, loc, view.Id(), &title)
	if err != nil {
		return err
	}
	view.SetBackend(backend)
	e.SetStatus(fmt.Sprintf("%v", view.WorkDir()))
	view.SetDirty(false)
	return nil
}

// OpenFile opens a file in the editor
func (e *Editor) openFile(loc string, view core.Viewable) error {
	if !core.IsTextFile(loc) {
		return fmt.Errorf("Binary file ? %s", loc)
	}
	var b core.Backend
	var err error
	if _, err := os.Stat(loc); os.IsNotExist(err) {
		b, err = backend.NewMemBackend(loc, view.Id())
	} else {
		b, err = backend.NewFileBackend(loc, view.Id())
	}
	if err != nil {
		return err
	}
	view.SetBackend(b)
	e.SetStatus(fmt.Sprintf("%v  [%d]", view.WorkDir(), view.Id()))
	view.SetDirty(false)
	return nil
}

func (e Editor) SetStatusErr(s string) {
	if e.Statusbar == nil {
		return
	}
	e.Statusbar.msg = s
	e.Statusbar.isErr = true
	e.Statusbar.Render()
}
func (e Editor) SetStatus(s string) {
	if e.Statusbar == nil {
		return
	}
	e.Statusbar.msg = s
	e.Statusbar.msg = s
	e.Statusbar.isErr = false
	e.Statusbar.Render()
}

func (e Editor) Config() core.Config {
	return *e.config
}

func (e Editor) Theme() *core.Theme {
	return e.theme
}

func (e Editor) CurView() core.Viewable {
	return e.curView
}

func (e Editor) SetCursor(y, x int) {
	e.term.SetCursor(y, x)
}

func (e Editor) CmdOn() bool {
	return e.cmdOn
}

func (e *Editor) SetCmdOn(v bool) {
	e.cmdOn = v
}

func (e *Editor) TermFlush() {
	e.term.Flush()
}

func (e *Editor) QuitCheck() bool {
	for _, c := range e.Cols {
		for _, v := range c.Views {
			if !v.canClose() {
				return false
			}
		}
	}
	return true
}

// Handle selection auto scrolling of views
func (e *Editor) autoScroller() {
	action := autoScrollAction{}
	for {
		time.Sleep(200 * time.Millisecond)
		core.Bus.Dispatch(action)
	}
}

type autoScrollAction struct {
}

func (e autoScrollAction) Run() error {
	v := core.Ed.CurView().(*View)
	if v == nil {
		return nil
	}
	x, y := v.autoScrollX, v.autoScrollY
	if x == 0 && y == 0 {
		return nil
	}
	if len(v.selections) == 0 {
		return nil
	}
	s := v.selections[0]
	ln := v.CurLine()
	v.offx += x
	v.offy += y
	if y > 0 {
		s.LineTo += y
	} else {
		s.LineFrom += y
	}
	if x > 0 {
		s.ColTo += x
	} else {
		s.ColFrom += x
	}
	// handle scroll / selection "overflows"
	lnLen := v.LineLen(v.Slice(), ln)
	if v.offy >= v.LineCount()-v.LastViewLine() {
		v.offy = v.LineCount() - v.LastViewLine()
	}
	if v.offy < 0 {
		v.offy = 0
	}
	if v.offx > lnLen-v.LastViewCol() {
		v.offx = lnLen - v.LastViewCol()
	}
	if v.offx < 0 {
		v.offx = 0
	}
	if s.LineFrom < 0 {
		s.LineFrom = 0
	} else if s.LineFrom > v.LineCount() {
		s.LineFrom = v.LineCount()
	}
	if s.LineTo < 0 {
		s.LineTo = 0
	} else if s.LineTo > v.LineCount() {
		s.LineTo = v.LineCount()
	}
	if s.ColFrom < 0 {
		s.ColFrom = 0
	} else if s.ColFrom > lnLen {
		s.ColFrom = lnLen
	}
	if s.ColTo < 0 {
		s.ColTo = 0
	} else if s.ColTo > lnLen {
		s.ColTo = lnLen
	}
	s.Normalize()
	v.selections = []core.Selection{
		s,
	}
	core.Ed.Render()
	return nil
}
<commit_msg>Fix "ls" command so it will work on OSX too.<commit_after>// package ui provides the UI components of Goed.
package ui

import (
	"fmt"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"

	"github.com/tcolar/goed/actions"
	"github.com/tcolar/goed/backend"
	"github.com/tcolar/goed/core"
	"github.com/tcolar/termbox-go"
)

// Editor is goed's main Editor pane (singleton)
type Editor struct {
	Cmdbar     *Cmdbar
	config     *core.Config
	Statusbar  *Statusbar
	Fg, Bg     core.Style
	theme      *core.Theme
	Cols       []*Col
	curView    *View
	CurCol     *Col
	cmdOn      bool
	pctw, pcth float64
	evtState   *EvtState
	term       core.Term
}

func NewEditor() *Editor {
	return &Editor{
		term:   core.NewTermBox(),
		config: core.LoadConfig(core.ConfFile),
	}
}

// Editor with Mock terminal for testing
func NewMockEditor() *Editor {
	return &Editor{
		term:   core.NewMockTerm(),
		config: core.LoadConfig("config.toml"),
	}
}

func (e *Editor) Dispatch(action core.Action) {
	core.Bus.Dispatch(action)
}

// Start starts-up the editor
func (e *Editor) Start(locs []string) {
	err := e.term.Init()
	if err != nil {
		panic(err)
	}

	defer func() {
		// TODO: should set it to original value, but how to read it ??
		e.term.SetMouseMode(termbox.MouseClick)
		e.term.Close()
	}()
	e.term.SetExtendedColors(core.Colors == 256)
	e.evtState = &EvtState{}
	e.theme, err = core.ReadTheme(core.FindResource(path.Join("themes", e.config.Theme)))
	if err != nil {
		panic(err)
	}
	e.Fg = e.theme.Fg
	e.Bg = e.theme.Bg

	h, w := e.term.Size()
	e.Cmdbar = &Cmdbar{}
	e.Cmdbar.SetBounds(0, 0, 0, w)
	e.Statusbar = &Statusbar{}
	e.Statusbar.SetBounds(h-1, 0, h-1, w)
	dirs := []string{}
	files := []string{}
	for _, loc := range locs {
		if stat, err := os.Stat(loc); err == nil && stat.IsDir() {
			dirs = append(dirs, loc)
		} else {
			files = append(files, loc)
		}
	}
	if len(dirs) == 0 {
		if len(files) > 0 {
			dirs = []string{path.Dir(locs[0])}
		} else {
			dirs = []string{"."}
		}
	}
	e.Cols = append(e.Cols, &Col{WidthRatio: 1.0})
	ratio := 1.0 / float64(len(dirs))
	for _, dir := range dirs {
		view := e.NewView(dir)
		view.HeightRatio = ratio
		e.Cols[0].Views = append(e.Cols[0].Views, view)
		e.Open(dir, view, "", true)
	}
	e.CurCol = e.Cols[0]
	e.curView = e.CurCol.Views[0]
	if len(files) > 0 {
		e.CurCol.WidthRatio = 0.2
		c := &Col{WidthRatio: 0.8}
		ratio := 1.0 / float64(len(files))
		for _, f := range files {
			view := e.NewView(f)
			view.HeightRatio = ratio
			c.Views = append(c.Views, view)
			e.Open(f, view, "", true)
		}
		e.Cols = append(e.Cols, c)
		e.CurCol = c
		e.curView = c.Views[0]
	}

	actions.EdResize(e.term.Size())

	actions.EdRender()

	go e.autoScroller()

	if !core.Testing {
		e.EventLoop()
	}
}

// Open opens a given location in the editor (in the given view)
// or new view if view is nil
func (e Editor) Open(loc string, view core.Viewable, rel string, create bool) (core.Viewable, error) {
	if len(rel) > 0 && !strings.HasPrefix(loc, string(os.PathSeparator)) {
		loc = path.Join(rel, loc)
	}
	// make it absolute
	loc, err := filepath.Abs(loc)
	if err != nil {
		return nil, err
	}
	stat, err := os.Stat(loc)
	newFile := false
	if os.IsNotExist(err) {
		if !create {
			return nil, err
		}
		newFile = true
	}
	title := filepath.Base(loc)
	if !newFile && stat.IsDir() {
		loc += string(os.PathSeparator)
		title += string(os.PathSeparator)
	}
	nv := false
	if view == nil {
		view = e.NewFileView(loc)
		nv = true
	}
	view.Reset()
	view.SetTitle(title)
	if newFile || !stat.IsDir() {
		err = e.openFile(loc, view)
	} else {
		err = e.openDir(loc, view)
	}
	if err != nil {
		return nil, err
	}
	if nv {
		e.InsertView(view.(*View), e.CurView().(*View), 0.2)
	}
	view.SetWorkDir(filepath.Dir(loc))
	return view, nil
}

// OpenDir opens a directory listing
func (e *Editor) openDir(loc string, view core.Viewable) error {
	args := []string{"ls", "-a1"}
	title := filepath.Base(loc) + "/"
	backend, err := backend.NewMemBackendCmd(args, loc, view.Id(), &title)
	if err != nil {
		return err
	}
	view.SetBackend(backend)
	e.SetStatus(fmt.Sprintf("%v", view.WorkDir()))
	view.SetDirty(false)
	return nil
}

// OpenFile opens a file in the editor
func (e *Editor) openFile(loc string, view core.Viewable) error {
	if !core.IsTextFile(loc) {
		return fmt.Errorf("Binary file ? %s", loc)
	}
	var b core.Backend
	var err error
	if _, err := os.Stat(loc); os.IsNotExist(err) {
		b, err = backend.NewMemBackend(loc, view.Id())
	} else {
		b, err = backend.NewFileBackend(loc, view.Id())
	}
	if err != nil {
		return err
	}
	view.SetBackend(b)
	e.SetStatus(fmt.Sprintf("%v  [%d]", view.WorkDir(), view.Id()))
	view.SetDirty(false)
	return nil
}

func (e Editor) SetStatusErr(s string) {
	if e.Statusbar == nil {
		return
	}
	e.Statusbar.msg = s
	e.Statusbar.isErr = true
	e.Statusbar.Render()
}
func (e Editor) SetStatus(s string) {
	if e.Statusbar == nil {
		return
	}
	e.Statusbar.msg = s
	e.Statusbar.msg = s
	e.Statusbar.isErr = false
	e.Statusbar.Render()
}

func (e Editor) Config() core.Config {
	return *e.config
}

func (e Editor) Theme() *core.Theme {
	return e.theme
}

func (e Editor) CurView() core.Viewable {
	return e.curView
}

func (e Editor) SetCursor(y, x int) {
	e.term.SetCursor(y, x)
}

func (e Editor) CmdOn() bool {
	return e.cmdOn
}

func (e *Editor) SetCmdOn(v bool) {
	e.cmdOn = v
}

func (e *Editor) TermFlush() {
	e.term.Flush()
}

func (e *Editor) QuitCheck() bool {
	for _, c := range e.Cols {
		for _, v := range c.Views {
			if !v.canClose() {
				return false
			}
		}
	}
	return true
}

// Handle selection auto scrolling of views
func (e *Editor) autoScroller() {
	action := autoScrollAction{}
	for {
		time.Sleep(200 * time.Millisecond)
		core.Bus.Dispatch(action)
	}
}

type autoScrollAction struct {
}

func (e autoScrollAction) Run() error {
	v := core.Ed.CurView().(*View)
	if v == nil {
		return nil
	}
	x, y := v.autoScrollX, v.autoScrollY
	if x == 0 && y == 0 {
		return nil
	}
	if len(v.selections) == 0 {
		return nil
	}
	s := v.selections[0]
	ln := v.CurLine()
	v.offx += x
	v.offy += y
	if y > 0 {
		s.LineTo += y
	} else {
		s.LineFrom += y
	}
	if x > 0 {
		s.ColTo += x
	} else {
		s.ColFrom += x
	}
	// handle scroll / selection "overflows"
	lnLen := v.LineLen(v.Slice(), ln)
	if v.offy >= v.LineCount()-v.LastViewLine() {
		v.offy = v.LineCount() - v.LastViewLine()
	}
	if v.offy < 0 {
		v.offy = 0
	}
	if v.offx > lnLen-v.LastViewCol() {
		v.offx = lnLen - v.LastViewCol()
	}
	if v.offx < 0 {
		v.offx = 0
	}
	if s.LineFrom < 0 {
		s.LineFrom = 0
	} else if s.LineFrom > v.LineCount() {
		s.LineFrom = v.LineCount()
	}
	if s.LineTo < 0 {
		s.LineTo = 0
	} else if s.LineTo > v.LineCount() {
		s.LineTo = v.LineCount()
	}
	if s.ColFrom < 0 {
		s.ColFrom = 0
	} else if s.ColFrom > lnLen {
		s.ColFrom = lnLen
	}
	if s.ColTo < 0 {
		s.ColTo = 0
	} else if s.ColTo > lnLen {
		s.ColTo = lnLen
	}
	s.Normalize()
	v.selections = []core.Selection{
		s,
	}
	core.Ed.Render()
	return nil
}
<|endoftext|>


<commit_before>// package ui provides the UI components of Goed.
package ui

import (
	"fmt"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"

	"github.com/tcolar/goed/actions"
	"github.com/tcolar/goed/backend"
	"github.com/tcolar/goed/core"
	"github.com/tcolar/termbox-go"
)

// Editor is goed's main Editor pane (singleton)
type Editor struct {
	Cmdbar     *Cmdbar
	config     *core.Config
	Statusbar  *Statusbar
	Fg, Bg     core.Style
	theme      *core.Theme
	Cols       []*Col
	curViewId  int64
	CurCol     *Col
	cmdOn      bool
	pctw, pcth float64
	evtState   *EvtState
	term       core.Term
	views      map[int64]*View
}

func NewEditor(gui bool) *Editor {
	var term core.Term
	if gui {
		term = NewGuiTerm(50, 160)
	} else {
		term = core.NewTermBox()
	}
	return &Editor{
		term:   term,
		config: core.LoadConfig(core.ConfFile),
		views:  map[int64]*View{},
	}
}

// Editor with Mock terminal for testing
func NewMockEditor() *Editor {
	return &Editor{
		term:   core.NewMockTerm(),
		config: core.LoadConfig("config.toml"),
		views:  map[int64]*View{},
	}
}

func (e *Editor) Dispatch(action core.Action) {
	core.Bus.Dispatch(action)
}

// Start starts-up the editor
func (e *Editor) Start(locs []string) {
	err := e.term.Init()
	if err != nil {
		panic(err)
	}

	defer func() {
		// TODO: should set it to original value, but how to read it ??
		e.term.SetMouseMode(termbox.MouseClick)
		e.term.Close()
	}()
	e.term.SetExtendedColors(core.Colors == 256)
	e.evtState = &EvtState{}
	e.theme, err = core.ReadTheme(core.FindResource(path.Join("themes", e.config.Theme)))
	if err != nil {
		panic(err)
	}
	e.Fg = e.theme.Fg
	e.Bg = e.theme.Bg

	h, w := e.term.Size()
	e.Cmdbar = &Cmdbar{}
	e.Cmdbar.SetBounds(0, 0, 0, w)
	e.Statusbar = &Statusbar{}
	e.Statusbar.SetBounds(h-1, 0, h-1, w)
	dirs := []string{}
	files := []string{}
	for _, loc := range locs {
		if stat, err := os.Stat(loc); err == nil && stat.IsDir() {
			dirs = append(dirs, loc)
		} else {
			files = append(files, loc)
		}
	}
	if len(dirs) == 0 {
		if len(files) > 0 {
			dirs = []string{path.Dir(locs[0])}
		} else {
			dirs = []string{"."}
		}
	}
	e.Cols = append(e.Cols, &Col{WidthRatio: 1.0})
	ratio := 1.0 / float64(len(dirs))
	for _, dir := range dirs {
		view := e.NewView(dir)
		view.HeightRatio = ratio
		e.Cols[0].Views = append(e.Cols[0].Views, view.Id())
		e.Open(dir, view.Id(), "", true)
	}
	e.CurCol = e.Cols[0]
	e.curViewId = e.CurCol.Views[0]
	if len(files) > 0 {
		e.CurCol.WidthRatio = 0.2
		c := &Col{WidthRatio: 0.8}
		ratio := 1.0 / float64(len(files))
		for _, f := range files {
			view := e.NewView(f)
			view.HeightRatio = ratio
			c.Views = append(c.Views, view.Id())
			e.Open(f, view.Id(), "", true)
		}
		e.Cols = append(e.Cols, c)
		e.CurCol = c
		e.curViewId = c.Views[0]
	}

	actions.EdResize(e.term.Size())

	actions.EdRender()

	go e.autoScroller()

	if !core.Testing {
		e.EventLoop()
	}
}

// Open opens a given location in the editor (in the given view)
// or new view if viewId < 0
func (e *Editor) Open(loc string, viewId int64, rel string, create bool) (int64, error) {
	loc = strings.TrimSpace(loc)
	rel = strings.TrimSpace(rel)
	if len(rel) > 0 && !strings.HasPrefix(loc, string(os.PathSeparator)) {
		loc = path.Join(rel, loc)
	}
	// make it absolute
	loc, err := filepath.Abs(loc)
	if err != nil {
		return -1, err
	}
	stat, err := os.Stat(loc)
	newFile := false
	if os.IsNotExist(err) {
		if !create {
			return -1, err
		}
		newFile = true
	}
	title := filepath.Base(loc)
	if !newFile && stat.IsDir() {
		loc += string(os.PathSeparator)
		title += string(os.PathSeparator)
	}
	nv := false
	var view core.Viewable
	if viewId < 0 {
		view = e.NewFileView(loc)
		nv = true
	} else {
		view = e.ViewById(viewId)
	}
	view.Reset()
	view.SetTitle(title)
	if newFile || !stat.IsDir() {
		err = e.openFile(loc, view)
	} else {
		err = e.openDir(loc, view)
	}
	if err != nil {
		return -1, err
	}
	if nv {
		if stat != nil && stat.IsDir() {
			e.AddDirViewSmart(view.(*View))
		} else {
			e.InsertViewSmart(view.(*View))
		}
	}
	view.Reset()
	view.SetWorkDir(filepath.Dir(loc))
	return view.Id(), nil
}

// OpenDir opens a directory listing
func (e *Editor) openDir(loc string, view core.Viewable) error {
	view.(*View).highlighter = &TermHighlighter{}
	args := append([]string{"ls"}, core.OsLsArgs...)
	title := filepath.Base(loc) + "/"
	backend, err := backend.NewMemBackendCmd(args, loc, view.Id(), &title, true)
	if err != nil {
		return err
	}
	view.SetBackend(backend)
	e.SetStatus(fmt.Sprintf("%v", view.WorkDir()))
	return nil
}

// OpenFile opens a file in the editor
func (e *Editor) openFile(loc string, view core.Viewable) error {
	if !core.IsTextFile(loc) {
		return fmt.Errorf("Binary file ? %s", loc)
	}
	b, err := backend.NewFileBackend(loc, view.Id())
	if err != nil {
		return err
	}
	view.SetBackend(b)
	e.SetStatus(fmt.Sprintf("%v  [%d]", view.WorkDir(), view.Id()))
	view.SetDirty(false)
	return nil
}

func (e *Editor) SetStatusErr(s string) {
	if e.Statusbar == nil {
		return
	}
	e.Statusbar.msg = s
	e.Statusbar.isErr = true
	e.Statusbar.Render()
}
func (e *Editor) SetStatus(s string) {
	if e.Statusbar == nil {
		return
	}
	e.Statusbar.msg = s
	e.Statusbar.msg = s
	e.Statusbar.isErr = false
	e.Statusbar.Render()
}

func (e *Editor) Config() core.Config {
	return *e.config
}

func (e *Editor) Theme() *core.Theme {
	return e.theme
}

func (e *Editor) CurView() core.Viewable {
	v, found := e.views[e.curViewId]
	if !found {
		return e.views[e.Cols[0].Views[0]]
	}
	return v
}

func (e *Editor) CurViewId() int64 {
	return e.curViewId
}

func (e *Editor) SetCursor(y, x int) {
	e.term.SetCursor(x, y)
}

func (e *Editor) CmdOn() bool {
	return e.cmdOn
}

func (e *Editor) SetCmdOn(v bool) {
	e.cmdOn = v
}

func (e *Editor) TermFlush() {
	e.term.Flush()
}

func (e *Editor) QuitCheck() bool {
	for _, c := range e.Cols {
		for _, vi := range c.Views {
			v, found := e.views[vi]
			if found && !v.canClose() {
				return false
			}
		}
	}
	return true
}

// Handle selection auto scrolling of views
func (e *Editor) autoScroller() {
	action := autoScrollAction{}
	for {
		time.Sleep(200 * time.Millisecond)
		core.Bus.Dispatch(action)
	}
}

type autoScrollAction struct {
}

func (e autoScrollAction) Run() error {
	v := core.Ed.ViewById(core.Ed.CurViewId()).(*View)
	if v == nil {
		return nil
	}
	x, y := v.autoScrollX, v.autoScrollY
	if x == 0 && y == 0 {
		return nil
	}
	if len(v.selections) == 0 {
		return nil
	}
	s := v.selections[0]
	ln := v.CurLine()
	v.offx += x
	v.offy += y
	if y > 0 {
		s.LineTo += y
	} else {
		s.LineFrom += y
	}
	if x > 0 {
		s.ColTo += x
	} else {
		s.ColFrom += x
	}
	// handle scroll / selection "overflows"
	lnLen := v.LineLen(v.Slice(), ln)
	if v.offy >= v.LineCount()-v.LastViewLine() {
		v.offy = v.LineCount() - v.LastViewLine()
	}
	if v.offy < 0 {
		v.offy = 0
	}
	if v.offx > lnLen-v.LastViewCol() {
		v.offx = lnLen - v.LastViewCol()
	}
	if v.offx < 0 {
		v.offx = 0
	}
	if s.LineFrom < 0 {
		s.LineFrom = 0
	} else if s.LineFrom > v.LineCount() {
		s.LineFrom = v.LineCount()
	}
	if s.LineTo < 0 {
		s.LineTo = 0
	} else if s.LineTo > v.LineCount() {
		s.LineTo = v.LineCount()
	}
	if s.ColFrom < 0 {
		s.ColFrom = 0
	} else if s.ColFrom > lnLen {
		s.ColFrom = lnLen
	}
	if s.ColTo < 0 {
		s.ColTo = 0
	} else if s.ColTo > lnLen {
		s.ColTo = lnLen
	}
	s.Normalize()
	v.selections = []core.Selection{
		s,
	}
	core.Ed.Render()
	return nil
}
<commit_msg>Wip starting separating UI from eventing<commit_after>// package ui provides the UI components of Goed.
package ui

import (
	"fmt"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"

	"github.com/tcolar/goed/actions"
	"github.com/tcolar/goed/backend"
	"github.com/tcolar/goed/core"
	"github.com/tcolar/goed/event"
	termbox "github.com/tcolar/termbox-go"
)

// Editor is goed's main Editor pane (singleton)
type Editor struct {
	Cmdbar     *Cmdbar
	config     *core.Config
	Statusbar  *Statusbar
	Fg, Bg     core.Style
	theme      *core.Theme
	Cols       []*Col
	curViewId  int64
	CurCol     *Col
	cmdOn      bool
	pctw, pcth float64
	evtState   *EvtState
	term       core.Term
	views      map[int64]*View
}

func NewEditor(gui bool) *Editor {
	var term core.Term
	if gui {
		term = NewGuiTerm(50, 160)
	} else {
		term = core.NewTermBox()
	}
	return &Editor{
		term:   term,
		config: core.LoadConfig(core.ConfFile),
		views:  map[int64]*View{},
	}
}

// Editor with Mock terminal for testing
func NewMockEditor() *Editor {
	return &Editor{
		term:   core.NewMockTerm(),
		config: core.LoadConfig("config.toml"),
		views:  map[int64]*View{},
	}
}

func (e *Editor) Dispatch(action core.Action) {
	core.Bus.Dispatch(action)
}

// Start starts-up the editor
func (e *Editor) Start(locs []string) {
	err := e.term.Init()
	if err != nil {
		panic(err)
	}

	defer func() {
		// TODO: should set it to original value, but how to read it ??
		e.term.SetMouseMode(termbox.MouseClick)
		e.term.Close()
	}()
	e.term.SetExtendedColors(core.Colors == 256)
	e.evtState = &EvtState{}
	e.theme, err = core.ReadTheme(core.FindResource(path.Join("themes", e.config.Theme)))
	if err != nil {
		panic(err)
	}
	e.Fg = e.theme.Fg
	e.Bg = e.theme.Bg

	h, w := e.term.Size()
	e.Cmdbar = &Cmdbar{}
	e.Cmdbar.SetBounds(0, 0, 0, w)
	e.Statusbar = &Statusbar{}
	e.Statusbar.SetBounds(h-1, 0, h-1, w)
	dirs := []string{}
	files := []string{}
	for _, loc := range locs {
		if stat, err := os.Stat(loc); err == nil && stat.IsDir() {
			dirs = append(dirs, loc)
		} else {
			files = append(files, loc)
		}
	}
	if len(dirs) == 0 {
		if len(files) > 0 {
			dirs = []string{path.Dir(locs[0])}
		} else {
			dirs = []string{"."}
		}
	}
	e.Cols = append(e.Cols, &Col{WidthRatio: 1.0})
	ratio := 1.0 / float64(len(dirs))
	for _, dir := range dirs {
		view := e.NewView(dir)
		view.HeightRatio = ratio
		e.Cols[0].Views = append(e.Cols[0].Views, view.Id())
		e.Open(dir, view.Id(), "", true)
	}
	e.CurCol = e.Cols[0]
	e.curViewId = e.CurCol.Views[0]
	if len(files) > 0 {
		e.CurCol.WidthRatio = 0.2
		c := &Col{WidthRatio: 0.8}
		ratio := 1.0 / float64(len(files))
		for _, f := range files {
			view := e.NewView(f)
			view.HeightRatio = ratio
			c.Views = append(c.Views, view.Id())
			e.Open(f, view.Id(), "", true)
		}
		e.Cols = append(e.Cols, c)
		e.CurCol = c
		e.curViewId = c.Views[0]
	}

	actions.EdResize(e.term.Size())

	actions.EdRender()

	go e.autoScroller()

	go event.Listen()
	defer event.Shutdown()

	if !core.Testing {
		e.EventLoop()
	}
}

// Open opens a given location in the editor (in the given view)
// or new view if viewId < 0
func (e *Editor) Open(loc string, viewId int64, rel string, create bool) (int64, error) {
	loc = strings.TrimSpace(loc)
	rel = strings.TrimSpace(rel)
	if len(rel) > 0 && !strings.HasPrefix(loc, string(os.PathSeparator)) {
		loc = path.Join(rel, loc)
	}
	// make it absolute
	loc, err := filepath.Abs(loc)
	if err != nil {
		return -1, err
	}
	stat, err := os.Stat(loc)
	newFile := false
	if os.IsNotExist(err) {
		if !create {
			return -1, err
		}
		newFile = true
	}
	title := filepath.Base(loc)
	if !newFile && stat.IsDir() {
		loc += string(os.PathSeparator)
		title += string(os.PathSeparator)
	}
	nv := false
	var view core.Viewable
	if viewId < 0 {
		view = e.NewFileView(loc)
		nv = true
	} else {
		view = e.ViewById(viewId)
	}
	view.Reset()
	view.SetTitle(title)
	if newFile || !stat.IsDir() {
		err = e.openFile(loc, view)
	} else {
		err = e.openDir(loc, view)
	}
	if err != nil {
		return -1, err
	}
	if nv {
		if stat != nil && stat.IsDir() {
			e.AddDirViewSmart(view.(*View))
		} else {
			e.InsertViewSmart(view.(*View))
		}
	}
	view.Reset()
	view.SetWorkDir(filepath.Dir(loc))
	return view.Id(), nil
}

// OpenDir opens a directory listing
func (e *Editor) openDir(loc string, view core.Viewable) error {
	view.(*View).highlighter = &TermHighlighter{}
	args := append([]string{"ls"}, core.OsLsArgs...)
	title := filepath.Base(loc) + "/"
	backend, err := backend.NewMemBackendCmd(args, loc, view.Id(), &title, true)
	if err != nil {
		return err
	}
	view.SetBackend(backend)
	e.SetStatus(fmt.Sprintf("%v", view.WorkDir()))
	return nil
}

// OpenFile opens a file in the editor
func (e *Editor) openFile(loc string, view core.Viewable) error {
	if !core.IsTextFile(loc) {
		return fmt.Errorf("Binary file ? %s", loc)
	}
	b, err := backend.NewFileBackend(loc, view.Id())
	if err != nil {
		return err
	}
	view.SetBackend(b)
	e.SetStatus(fmt.Sprintf("%v  [%d]", view.WorkDir(), view.Id()))
	view.SetDirty(false)
	return nil
}

func (e *Editor) SetStatusErr(s string) {
	if e.Statusbar == nil {
		return
	}
	e.Statusbar.msg = s
	e.Statusbar.isErr = true
	e.Statusbar.Render()
}
func (e *Editor) SetStatus(s string) {
	if e.Statusbar == nil {
		return
	}
	e.Statusbar.msg = s
	e.Statusbar.msg = s
	e.Statusbar.isErr = false
	e.Statusbar.Render()
}

func (e *Editor) Config() core.Config {
	return *e.config
}

func (e *Editor) Theme() *core.Theme {
	return e.theme
}

func (e *Editor) CurView() core.Viewable {
	v, found := e.views[e.curViewId]
	if !found {
		return e.views[e.Cols[0].Views[0]]
	}
	return v
}

func (e *Editor) CurViewId() int64 {
	return e.curViewId
}

func (e *Editor) SetCursor(y, x int) {
	e.term.SetCursor(x, y)
}

func (e *Editor) CmdOn() bool {
	return e.cmdOn
}

func (e *Editor) SetCmdOn(v bool) {
	e.cmdOn = v
}

func (e *Editor) TermFlush() {
	e.term.Flush()
}

func (e *Editor) QuitCheck() bool {
	for _, c := range e.Cols {
		for _, vi := range c.Views {
			v, found := e.views[vi]
			if found && !v.canClose() {
				return false
			}
		}
	}
	return true
}

// Handle selection auto scrolling of views
func (e *Editor) autoScroller() {
	action := autoScrollAction{}
	for {
		time.Sleep(200 * time.Millisecond)
		core.Bus.Dispatch(action)
	}
}

type autoScrollAction struct {
}

func (e autoScrollAction) Run() error {
	v := core.Ed.ViewById(core.Ed.CurViewId()).(*View)
	if v == nil {
		return nil
	}
	x, y := v.autoScrollX, v.autoScrollY
	if x == 0 && y == 0 {
		return nil
	}
	if len(v.selections) == 0 {
		return nil
	}
	s := v.selections[0]
	ln := v.CurLine()
	v.offx += x
	v.offy += y
	if y > 0 {
		s.LineTo += y
	} else {
		s.LineFrom += y
	}
	if x > 0 {
		s.ColTo += x
	} else {
		s.ColFrom += x
	}
	// handle scroll / selection "overflows"
	lnLen := v.LineLen(v.Slice(), ln)
	if v.offy >= v.LineCount()-v.LastViewLine() {
		v.offy = v.LineCount() - v.LastViewLine()
	}
	if v.offy < 0 {
		v.offy = 0
	}
	if v.offx > lnLen-v.LastViewCol() {
		v.offx = lnLen - v.LastViewCol()
	}
	if v.offx < 0 {
		v.offx = 0
	}
	if s.LineFrom < 0 {
		s.LineFrom = 0
	} else if s.LineFrom > v.LineCount() {
		s.LineFrom = v.LineCount()
	}
	if s.LineTo < 0 {
		s.LineTo = 0
	} else if s.LineTo > v.LineCount() {
		s.LineTo = v.LineCount()
	}
	if s.ColFrom < 0 {
		s.ColFrom = 0
	} else if s.ColFrom > lnLen {
		s.ColFrom = lnLen
	}
	if s.ColTo < 0 {
		s.ColTo = 0
	} else if s.ColTo > lnLen {
		s.ColTo = lnLen
	}
	s.Normalize()
	v.selections = []core.Selection{
		s,
	}
	core.Ed.Render()
	return nil
}
<|endoftext|>


<commit_before>package harness

import (
	"github.com/urfave/cli"
	"os"
)

func MakeApp(opts *ExporterOpts) *cli.App {
	exp := &exporter{opts}

	app := cli.NewApp()
	app.Name = opts.Name
	app.Version = opts.Version
	app.Usage = "A prometheus " + opts.Name
	app.UsageText = opts.Usage
	app.Action = exp.main
	app.Flags = append(opts.Flags,
		cli.StringFlag{
			Name:  "log-level",
			Usage: "Set Logging level",
			Value: "info",
		},
	)

	var portFlagExists bool
	for _, flag := range opts.Flags {
		if flag.GetName() == "port" {
			portFlagExists = true
			break
		}
	}
	if !portFlagExists {
		app.Flags = append(app.Flags,
			cli.IntFlag{
				Name:  "port",
				Usage: "The port number used to expose metrics via http",
				Value: 7979,
			},
		)
	}

	if opts.Tick {
		app.Flags = append(app.Flags,
			cli.IntFlag{
				Name:  "interval",
				Usage: "Interval to fetch metrics from the endpoint in second",
				Value: 60,
			},
		)
	}

	return app
}

func Main(opts *ExporterOpts) {
	err := MakeApp(opts).Run(os.Args)
	if err != nil {
		os.Exit(1)
	}
}
<commit_msg>Generate app.Flags from opts.Flags and defaultOpts<commit_after>package harness

import (
	"github.com/urfave/cli"
	"os"
)

var (
	defaultOpts = []cli.Flag{
		cli.StringFlag{
			Name:  "log-level",
			Usage: "Set Logging level",
			Value: "info",
		},
		cli.IntFlag{
			Name:  "port",
			Usage: "The port number used to expose metrics via http",
			Value: 7979,
		},
	}

	defaultTickOpt = cli.IntFlag{
		Name:  "interval",
		Usage: "Interval to fetch metrics from the endpoint in second",
		Value: 60,
	}
)

func MakeApp(opts *ExporterOpts) *cli.App {
	exp := &exporter{opts}

	app := cli.NewApp()
	app.Name = opts.Name
	app.Version = opts.Version
	app.Usage = "A prometheus " + opts.Name
	app.UsageText = opts.Usage
	app.Action = exp.main
	app.Flags = buildOptsWithDefault(opts.Flags, defaultOpts)

	if opts.Tick && !contains(app.Flags, defaultTickOpt) {
		app.Flags = append(app.Flags, defaultTickOpt)
	}

	return app
}

func buildOptsWithDefault(opts []cli.Flag, defaultOpts []cli.Flag) []cli.Flag {
	for _, opt := range defaultOpts {
		if !contains(opts, opt) {
			opts = append(opts, opt)
		}
	}
	return opts
}

func contains(opts []cli.Flag, opt cli.Flag) bool {
	for _, o := range opts {
		if o.GetName() == opt.GetName() {
			return true
		}
	}
	return false
}

func Main(opts *ExporterOpts) {
	err := MakeApp(opts).Run(os.Args)
	if err != nil {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
)

func main(){
    fmt.Println("Hello World, 你好 Golang！");
}<commit_msg>格式化代码<commit_after>package main

import (
	"fmt"
)

func main() {
	fmt.Println("Hello World, 你好 Golang！")
}
<|endoftext|>


<commit_before>package api

const (
settings_yml = `denvhome: ~/.denv
infofile: .denvinfo
ignorefile: .denvignore
restoredenv: .restore
prescript: .denvpre
postscript: .denvpost
`
_default_denvignore = `.bash_history
.gnupg
.npm
.nvm
.rvm
.gimme
.cache
.gem
.bundle
.erlang.cookie
.git
.denv*
.ssh
.viminfo
`
Version = "v0.0.5-a"
)
<commit_msg>include<commit_after>package api

const (
settings_yml = `denvhome: ~/.denv
infofile: .denvinfo
ignorefile: .denvignore
restoredenv: .restore
prescript: .denvpre
postscript: .denvpost
`
_default_denvignore = `.bash_history
.gnupg
.npm
.nvm
.rvm
.gimme
.cache
.gem
.bundle
.erlang.cookie
.git
.denv*
.ssh
.viminfo
`
Version = "v0.0.6-a"
)
<|endoftext|>


<commit_before>package peg

import (
	"fmt"
	"strings"
)

var (
	// True always matches, but consumes no text.
	True Pattern = &patternBoolean{true}

	// False always dismatch.
	False Pattern = &patternBoolean{false}

	// SOL predicates start of line.
	SOL Pattern = &patternLineAnchorPredicate{true}

	// EOL predicates end of line.
	EOL Pattern = &patternLineAnchorPredicate{false}

	// EOF predicates end of file.
	EOF Pattern = patternEOFPredicate{}
)

// Underlying types implemented Pattern interface.
type (
	patternBoolean struct {
		ok bool
	}

	patternLineAnchorPredicate struct {
		linestart bool
	}

	patternEOFPredicate struct{}

	patternPredicate struct {
		not bool
		pat Pattern
	}

	patternAndPredicate struct {
		pats []Pattern
	}

	patternOrPredicate struct {
		pats []Pattern
	}

	patternIf struct {
		cond Pattern
		yes  Pattern
		no   Pattern
	}

	patternSwitch struct {
		cases []struct {
			cond Pattern
			then Pattern
		}
		otherwise Pattern
	}
)

// Test predicates if pattern is matched, consuming no text.
func Test(pat Pattern) Pattern {
	return &patternPredicate{not: false, pat: pat}
}

// Not predicates if pattern is dismatched, consuming no text.
func Not(pat Pattern) Pattern {
	return &patternPredicate{not: true, pat: pat}
}

// And searches the patterns in order to predicate if all the pattern
// is matched at current position. It consumes no text.
func And(pats ...Pattern) Pattern {
	if len(pats) == 0 {
		return True
	}
	return &patternAndPredicate{pats}
}

// Or searches the patterns in order to predicate if any the pattern
// is matched at current position. It consumes no text.
func Or(pats ...Pattern) Pattern {
	if len(pats) == 0 {
		return False
	}
	return &patternOrPredicate{pats}
}

// When tests the given condition but consumes no text, then determines to
// execute then-branch or just predicates false.
func When(cond, then Pattern) Pattern {
	return &patternIf{cond: cond, yes: then, no: False}
}

// If tests the given condition but consumes no text, then determines to
// execute yes-branch or no-branch.
func If(cond, yes, no Pattern) Pattern {
	return &patternIf{cond: cond, yes: yes, no: no}
}

// Switch tests cond-then pairs in order, executes then-branch if cond is true.
// If there is no true cond, executes the optional otherwise-branch,
// or just predicates false if there is no otherwise-branch.
func Switch(cond, then Pattern, rest ...Pattern) Pattern {
	pat := &patternSwitch{}
	pat.cases = append(pat.cases, struct {
		cond Pattern
		then Pattern
	}{cond, then})

	if len(rest)%2 != 0 {
		pat.otherwise = rest[len(rest)-1]
		rest = rest[:len(rest)-1]
	} else {
		pat.otherwise = False
	}

	for len(rest) > 0 {
		cond, then = rest[0], rest[1]
		rest = rest[2:]
		pat.cases = append(pat.cases, struct {
			cond Pattern
			then Pattern
		}{cond, then})
	}
	return pat
}

// Matches empty string if true, dismatches if false.
func (pat *patternBoolean) match(ctx *context) error {
	return ctx.returnsPredication(pat.ok)
}

// Predicates SOL/EOL.
func (pat *patternLineAnchorPredicate) match(ctx *context) error {
	p, n := ctx.readPrev(1), ctx.readNext(1)

	if pat.linestart {
		// SOL matches start of file or just after a "\n"|"\r"|"\r\n".
		if p == "" {
			return ctx.returnsPredication(true)
		}
		return ctx.returnsPredication(
			p == "\n" || (p == "\r" && n != "\n"))
	}

	// EOL matches end of file or just before a "\n"|"\r"|"\r\n".
	if n == "" {
		return ctx.returnsPredication(true)
	}
	return ctx.returnsPredication(n == "\r" || (n == "\n" && p != "\r"))
}

// Predicates EOF.
func (patternEOFPredicate) match(ctx *context) error {
	return ctx.returnsPredication(ctx.readNext(1) == "")
}

// Predicates if sub-pattern matches.
func (pat *patternPredicate) match(ctx *context) error {
	if !ctx.justReturned() {
		return ctx.call(pat.pat)
	}

	ret := ctx.ret
	if pat.not {
		ret.ok = !ret.ok
	}
	return ctx.returnsPredication(ret.ok)
}

// Predicates if all the sub-patterns match.
func (pat *patternAndPredicate) match(ctx *context) error {
	for ctx.locals.i < len(pat.pats) {
		if !ctx.justReturned() {
			return ctx.call(pat.pats[ctx.locals.i])
		}

		if !ctx.ret.ok {
			return ctx.returnsPredication(false)
		}
		ctx.locals.i++
	}
	return ctx.returnsPredication(true)
}

// Predicates if any sub-pattern matches.
func (pat *patternOrPredicate) match(ctx *context) error {
	for ctx.locals.i < len(pat.pats) {
		if !ctx.justReturned() {
			return ctx.call(pat.pats[ctx.locals.i])
		}

		if ctx.ret.ok {
			return ctx.returnsPredication(true)
		}
		ctx.locals.i++
	}
	return ctx.returnsPredication(false)
}

// Branch `if'.
func (pat *patternIf) match(ctx *context) error {
	if !ctx.justReturned() {
		return ctx.call(pat.cond)
	}

	if ctx.ret.ok {
		return ctx.execute(pat.yes)
	}
	return ctx.execute(pat.no)
}

// Branch `switch'.
func (pat *patternSwitch) match(ctx *context) error {
	for ctx.locals.i < len(pat.cases) {
		if !ctx.justReturned() {
			return ctx.call(pat.cases[ctx.locals.i].cond)
		}

		if ctx.ret.ok {
			return ctx.execute(pat.cases[ctx.locals.i].then)
		}
		ctx.locals.i++
	}
	return ctx.execute(pat.otherwise)
}

func (pat *patternBoolean) String() string {
	if pat.ok {
		return "true"
	}
	return "false"
}

func (pat *patternLineAnchorPredicate) String() string {
	if pat.linestart {
		return "sol?"
	}
	return "eol?"
}

func (patternEOFPredicate) String() string {
	return "eof?"
}

func (pat *patternPredicate) String() string {
	if pat.not {
		return fmt.Sprintf("!%s", pat.pat)
	}
	return fmt.Sprintf("?%s", pat.pat)
}

func (pat *patternAndPredicate) String() string {
	strs := make([]string, len(pat.pats))
	for i, pat := range pat.pats {
		strs[i] = fmt.Sprint(pat)
	}
	return fmt.Sprintf("(%s)", strings.Join(strs, " && "))
}

func (pat *patternOrPredicate) String() string {
	strs := make([]string, len(pat.pats))
	for i, pat := range pat.pats {
		strs[i] = fmt.Sprint(pat)
	}
	return fmt.Sprintf("(%s)", strings.Join(strs, " || "))
}

func (pat *patternIf) String() string {
	if b, ok := pat.no.(*patternBoolean); ok && b.ok == false {
		return fmt.Sprintf("switch(%s: %s)", pat.cond, pat.yes)
	}
	return fmt.Sprintf("switch(%s: %s; %s)", pat.cond, pat.yes, pat.no)
}

func (pat *patternSwitch) String() string {
	strs := make([]string, len(pat.cases))
	for i := range pat.cases {
		strs[i] = fmt.Sprintf("%s: %s", pat.cases[i].cond, pat.cases[i].then)
	}
	if b, ok := pat.otherwise.(*patternBoolean); ok && b.ok == false {
		return fmt.Sprintf("switch(%s)", strings.Join(strs, "; "))
	}
	return fmt.Sprintf("switch(%s; %s)", strings.Join(strs, "; "), pat.otherwise)
}
<commit_msg>refine: documents for predicators<commit_after>package peg

import (
	"fmt"
	"strings"
)

var (
	// True always matches, but consumes no text.
	True Pattern = &patternBoolean{true}

	// False always dismatch.
	False Pattern = &patternBoolean{false}

	// SOL predicates start of line.
	SOL Pattern = &patternLineAnchorPredicate{true}

	// EOL predicates end of line.
	EOL Pattern = &patternLineAnchorPredicate{false}

	// EOF predicates end of file.
	EOF Pattern = patternEOFPredicate{}
)

// Underlying types implemented Pattern interface.
type (
	patternBoolean struct {
		ok bool
	}

	patternLineAnchorPredicate struct {
		linestart bool
	}

	patternEOFPredicate struct{}

	patternPredicate struct {
		not bool
		pat Pattern
	}

	patternAndPredicate struct {
		pats []Pattern
	}

	patternOrPredicate struct {
		pats []Pattern
	}

	patternIf struct {
		cond Pattern
		yes  Pattern
		no   Pattern
	}

	patternSwitch struct {
		cases []struct {
			cond Pattern
			then Pattern
		}
		otherwise Pattern
	}
)

// Test predicates if pattern is matched, consuming no text.
//
// Note that, if predicates true, groups/parse captures won't be discarded.
func Test(pat Pattern) Pattern {
	return &patternPredicate{not: false, pat: pat}
}

// Not predicates if pattern is dismatched, consuming no text.
//
// Note that, if predicates true, groups/parse captures won't be discarded.
func Not(pat Pattern) Pattern {
	return &patternPredicate{not: true, pat: pat}
}

// And searches the patterns in order to predicate if all the pattern
// is matched at current position. It consumes no text.
//
// Note that, if predicates true, groups/parse captures won't be discarded.
func And(pats ...Pattern) Pattern {
	if len(pats) == 0 {
		return True
	}
	return &patternAndPredicate{pats}
}

// Or searches the patterns in order to predicate if any the pattern
// is matched at current position. It consumes no text.
//
// Note that, if predicates true, groups/parse captures won't be discarded.
func Or(pats ...Pattern) Pattern {
	if len(pats) == 0 {
		return False
	}
	return &patternOrPredicate{pats}
}

// When tests the given condition but consumes no text, then determines to
// execute then-branch or just predicates false.
//
// Note that, if cond predicates true, groups/parse captures won't be
// discarded.
func When(cond, then Pattern) Pattern {
	return &patternIf{cond: cond, yes: then, no: False}
}

// If tests the given condition but consumes no text, then determines to
// execute yes-branch or no-branch.
//
// Note that, if cond predicates true, groups/parse captures won't be
// discarded.
func If(cond, yes, no Pattern) Pattern {
	return &patternIf{cond: cond, yes: yes, no: no}
}

// Switch tests cond-then pairs in order, executes then-branch if cond is true.
// If there is no true cond, executes the optional otherwise-branch,
// or just predicates false if there is no otherwise-branch.
//
// Note that, if cond predicates true, groups/parse captures won't be
// discarded.
func Switch(cond, then Pattern, rest ...Pattern) Pattern {
	pat := &patternSwitch{}
	pat.cases = append(pat.cases, struct {
		cond Pattern
		then Pattern
	}{cond, then})

	if len(rest)%2 != 0 {
		pat.otherwise = rest[len(rest)-1]
		rest = rest[:len(rest)-1]
	} else {
		pat.otherwise = False
	}

	for len(rest) > 0 {
		cond, then = rest[0], rest[1]
		rest = rest[2:]
		pat.cases = append(pat.cases, struct {
			cond Pattern
			then Pattern
		}{cond, then})
	}
	return pat
}

// Matches empty string if true, dismatches if false.
func (pat *patternBoolean) match(ctx *context) error {
	return ctx.returnsPredication(pat.ok)
}

// Predicates SOL/EOL.
func (pat *patternLineAnchorPredicate) match(ctx *context) error {
	p, n := ctx.readPrev(1), ctx.readNext(1)

	if pat.linestart {
		// SOL matches start of file or just after a "\n"|"\r"|"\r\n".
		if p == "" {
			return ctx.returnsPredication(true)
		}
		return ctx.returnsPredication(
			p == "\n" || (p == "\r" && n != "\n"))
	}

	// EOL matches end of file or just before a "\n"|"\r"|"\r\n".
	if n == "" {
		return ctx.returnsPredication(true)
	}
	return ctx.returnsPredication(n == "\r" || (n == "\n" && p != "\r"))
}

// Predicates EOF.
func (patternEOFPredicate) match(ctx *context) error {
	return ctx.returnsPredication(ctx.readNext(1) == "")
}

// Predicates if sub-pattern matches.
func (pat *patternPredicate) match(ctx *context) error {
	if !ctx.justReturned() {
		return ctx.call(pat.pat)
	}

	ret := ctx.ret
	if pat.not {
		ret.ok = !ret.ok
	}
	return ctx.returnsPredication(ret.ok)
}

// Predicates if all the sub-patterns match.
func (pat *patternAndPredicate) match(ctx *context) error {
	for ctx.locals.i < len(pat.pats) {
		if !ctx.justReturned() {
			return ctx.call(pat.pats[ctx.locals.i])
		}

		if !ctx.ret.ok {
			return ctx.returnsPredication(false)
		}
		ctx.locals.i++
	}
	return ctx.returnsPredication(true)
}

// Predicates if any sub-pattern matches.
func (pat *patternOrPredicate) match(ctx *context) error {
	for ctx.locals.i < len(pat.pats) {
		if !ctx.justReturned() {
			return ctx.call(pat.pats[ctx.locals.i])
		}

		if ctx.ret.ok {
			return ctx.returnsPredication(true)
		}
		ctx.locals.i++
	}
	return ctx.returnsPredication(false)
}

// Branch `if'.
func (pat *patternIf) match(ctx *context) error {
	if !ctx.justReturned() {
		return ctx.call(pat.cond)
	}

	if ctx.ret.ok {
		return ctx.execute(pat.yes)
	}
	return ctx.execute(pat.no)
}

// Branch `switch'.
func (pat *patternSwitch) match(ctx *context) error {
	for ctx.locals.i < len(pat.cases) {
		if !ctx.justReturned() {
			return ctx.call(pat.cases[ctx.locals.i].cond)
		}

		if ctx.ret.ok {
			return ctx.execute(pat.cases[ctx.locals.i].then)
		}
		ctx.locals.i++
	}
	return ctx.execute(pat.otherwise)
}

func (pat *patternBoolean) String() string {
	if pat.ok {
		return "true"
	}
	return "false"
}

func (pat *patternLineAnchorPredicate) String() string {
	if pat.linestart {
		return "sol?"
	}
	return "eol?"
}

func (patternEOFPredicate) String() string {
	return "eof?"
}

func (pat *patternPredicate) String() string {
	if pat.not {
		return fmt.Sprintf("!%s", pat.pat)
	}
	return fmt.Sprintf("?%s", pat.pat)
}

func (pat *patternAndPredicate) String() string {
	strs := make([]string, len(pat.pats))
	for i, pat := range pat.pats {
		strs[i] = fmt.Sprint(pat)
	}
	return fmt.Sprintf("(%s)", strings.Join(strs, " && "))
}

func (pat *patternOrPredicate) String() string {
	strs := make([]string, len(pat.pats))
	for i, pat := range pat.pats {
		strs[i] = fmt.Sprint(pat)
	}
	return fmt.Sprintf("(%s)", strings.Join(strs, " || "))
}

func (pat *patternIf) String() string {
	if b, ok := pat.no.(*patternBoolean); ok && b.ok == false {
		return fmt.Sprintf("switch(%s: %s)", pat.cond, pat.yes)
	}
	return fmt.Sprintf("switch(%s: %s; %s)", pat.cond, pat.yes, pat.no)
}

func (pat *patternSwitch) String() string {
	strs := make([]string, len(pat.cases))
	for i := range pat.cases {
		strs[i] = fmt.Sprintf("%s: %s", pat.cases[i].cond, pat.cases[i].then)
	}
	if b, ok := pat.otherwise.(*patternBoolean); ok && b.ok == false {
		return fmt.Sprintf("switch(%s)", strings.Join(strs, "; "))
	}
	return fmt.Sprintf("switch(%s; %s)", strings.Join(strs, "; "), pat.otherwise)
}
<|endoftext|>


<commit_before>package logpeck

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httputil"
)

func logRequest(r *http.Request, prefix string) {
	r_str, _ := httputil.DumpRequest(r, true)
	log.Printf("[%s] req_len[%d] req[%s]", prefix, len(r_str), r_str)
}

func NewAddTaskHandler(pecker *Pecker, db *DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		logRequest(r, "AddTaskHandler")
		defer r.Body.Close()

		var config PeckTaskConfig
		raw, _ := ioutil.ReadAll(r.Body)
		err := json.Unmarshal(raw, &config)
		if err != nil {
			log.Printf("Parse PeckTaskConfig error, %s", err)
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Bad Request\n"))
			return
		}

		err = pecker.AddPeckTask(&config)
		if err != nil {
			log.Printf("AddTaskConfig error, %s", err)
			w.WriteHeader(http.StatusNotAcceptable)
			w.Write([]byte("Add failed, " + err.Error() + "\n"))
			return
		}

		err = db.SaveConfig(&config)
		if err != nil {
			log.Printf("AddTaskConfig error, save config error, %s", err)
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte(err.Error() + "\n"))
			return
		}

		w.WriteHeader(http.StatusOK)
		w.Write([]byte("OK\n"))
		return
	}
}

func NewUpdateTaskHandler(pecker *Pecker, db *DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		logRequest(r, "UpdateTaskHandler")
		defer r.Body.Close()

		var config PeckTaskConfig
		raw, _ := ioutil.ReadAll(r.Body)
		err := json.Unmarshal(raw, &config)
		if err != nil {
			log.Printf("Parse PeckTaskConfig error, %s", err)
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Bad Request\n"))
			return
		}

		err = pecker.UpdatePeckTask(&config)
		if err != nil {
			w.WriteHeader(http.StatusNotAcceptable)
			w.Write([]byte("Update failed, " + err.Error() + "\n"))
			return
		}

		err = db.SaveConfig(&config)
		if err != nil {
			log.Printf("UpdateTaskConfig error, save config error, %s", err)
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte(err.Error() + "\n"))
			return
		}

		w.WriteHeader(http.StatusOK)
		w.Write([]byte("UpdateTaskHandler Success\n"))
	}
}

func NewStartTaskHandler(pecker *Pecker, db *DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		logRequest(r, "StartTaskHandler")
		defer r.Body.Close()

		var config PeckTaskConfig
		raw, _ := ioutil.ReadAll(r.Body)
		err := json.Unmarshal(raw, &config)
		if err != nil {
			log.Printf("Start PeckTaskConfig error, %s", err)
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Bad Request\n"))
			return
		}

		config_w, c_err := db.GetConfig(&config)
		if c_err != nil {
			w.WriteHeader(http.StatusNotAcceptable)
			w.Write([]byte("Start failed, " + c_err.Error() + "\n"))
			return
		}

		err = pecker.StartPeckTask(config_w)
		if err != nil {
			w.WriteHeader(http.StatusNotAcceptable)
			w.Write([]byte("Update failed, " + err.Error() + "\n"))
			return
		}

		err = db.SaveConfig(&config)
		if err != nil {
			log.Printf("UpdateTaskConfig error, save config error, %s", err)
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte(err.Error() + "\n"))
			return
		}

		w.WriteHeader(http.StatusOK)
		w.Write([]byte("PauseTaskHandler Success\n"))
	}
}

func NewPauseTaskHandler(pecker *Pecker, db *DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		logRequest(r, "PauseTaskHandler")
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("PauseTaskHandler Success\n"))
	}
}

func NewRemoveTaskHandler(pecker *Pecker, db *DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		logRequest(r, "RemoveTaskHandler")
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("RemoveTaskHandler Success\n"))
	}
}
<commit_msg>remove db from http handler<commit_after>package logpeck

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httputil"
)

func logRequest(r *http.Request, prefix string) {
	r_str, _ := httputil.DumpRequest(r, true)
	log.Printf("[%s] req_len[%d] req[%s]", prefix, len(r_str), r_str)
}

func NewAddTaskHandler(pecker *Pecker, db *DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		logRequest(r, "AddTaskHandler")
		defer r.Body.Close()

		var config PeckTaskConfig
		raw, _ := ioutil.ReadAll(r.Body)
		err := json.Unmarshal(raw, &config)
		if err != nil {
			log.Printf("Parse PeckTaskConfig error, %s", err)
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Bad Request\n"))
			return
		}

		err = pecker.AddPeckTask(&config)
		if err != nil {
			log.Printf("AddTaskConfig error, %s", err)
			w.WriteHeader(http.StatusNotAcceptable)
			w.Write([]byte("Add failed, " + err.Error() + "\n"))
			return
		}

		w.WriteHeader(http.StatusOK)
		w.Write([]byte("OK\n"))
		return
	}
}

func NewUpdateTaskHandler(pecker *Pecker, db *DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		logRequest(r, "UpdateTaskHandler")
		defer r.Body.Close()

		var config PeckTaskConfig
		raw, _ := ioutil.ReadAll(r.Body)
		err := json.Unmarshal(raw, &config)
		if err != nil {
			log.Printf("Parse PeckTaskConfig error, %s", err)
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Bad Request\n"))
			return
		}

		err = pecker.UpdatePeckTask(&config)
		if err != nil {
			w.WriteHeader(http.StatusNotAcceptable)
			w.Write([]byte("Update failed, " + err.Error() + "\n"))
			return
		}

		err = db.SaveConfig(&config)
		if err != nil {
			log.Printf("UpdateTaskConfig error, save config error, %s", err)
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte(err.Error() + "\n"))
			return
		}

		w.WriteHeader(http.StatusOK)
		w.Write([]byte("UpdateTaskHandler Success\n"))
	}
}

func NewStartTaskHandler(pecker *Pecker, db *DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		logRequest(r, "StartTaskHandler")
		defer r.Body.Close()

		var config PeckTaskConfig
		raw, _ := ioutil.ReadAll(r.Body)
		err := json.Unmarshal(raw, &config)
		if err != nil {
			log.Printf("Start PeckTaskConfig error, %s", err)
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Bad Request\n"))
			return
		}

		config_w, c_err := db.GetConfig(&config)
		if c_err != nil {
			w.WriteHeader(http.StatusNotAcceptable)
			w.Write([]byte("Start failed, " + c_err.Error() + "\n"))
			return
		}

		err = pecker.StartPeckTask(config_w)
		if err != nil {
			w.WriteHeader(http.StatusNotAcceptable)
			w.Write([]byte("Update failed, " + err.Error() + "\n"))
			return
		}

		err = db.SaveConfig(&config)
		if err != nil {
			log.Printf("UpdateTaskConfig error, save config error, %s", err)
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte(err.Error() + "\n"))
			return
		}

		w.WriteHeader(http.StatusOK)
		w.Write([]byte("PauseTaskHandler Success\n"))
	}
}

func NewPauseTaskHandler(pecker *Pecker, db *DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		logRequest(r, "PauseTaskHandler")
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("PauseTaskHandler Success\n"))
	}
}

func NewRemoveTaskHandler(pecker *Pecker, db *DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		logRequest(r, "RemoveTaskHandler")
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("RemoveTaskHandler Success\n"))
	}
}
<|endoftext|>


<commit_before>package probe

import (
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/gophergala/goffee/data"
	"github.com/gophergala/goffee/queue"
	"github.com/gophergala/goffee/tor"
)

const ipReflector = "http://stephensykes.com/ip_reflection.html"

var exit = make(chan bool)
var currentIP string
var lastIPChange time.Time

func Run() {
	go run()
}

func run() {
	var wg sync.WaitGroup
	newip()

	for { // ever
		fmt.Println("Redis fetch")
		batch := queue.FetchBatch()
		fmt.Println(batch)
		for _, item := range batch {
			wg.Add(1)
			go check(item, &wg)
		}

		wg.Wait()

		if time.Since(lastIPChange) > time.Minute {
			newip()
		}

	}
}

func newip() {
	tor.NewIP()
	body, err := tor.TorGet(ipReflector)
	var result string
	if err != nil {
		result = err.Error()
	} else {
		result = body
	}
	currentIP = result
	fmt.Println("New IP obtained " + result)
	lastIPChange = time.Now()
}

func check(address string, wg *sync.WaitGroup) {
	defer wg.Done()

	status, err := tor.TorGetStatus(address)

	var statusCode int
	if err != nil {
		statusCode = -1
	} else {
		statusCode, err = strconv.Atoi(strings.Split(status, " ")[0])
		if err != nil {
			statusCode = -2
		}
	}

	result := &data.Result{
		CreatedAt: time.Now(),
		Status:    statusCode,
		Success:   statusCode >= 200 && statusCode < 300,
		URL:       address,
		IP:        currentIP,
	}

	data, err := json.Marshal(result)
	if err != nil {
		return
	}

	queue.WriteResult(string(data))
}

func Wait() {
	<-exit
}
<commit_msg>Let’s try refreshing IPs every 5 minutes instead<commit_after>package probe

import (
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/gophergala/goffee/data"
	"github.com/gophergala/goffee/queue"
	"github.com/gophergala/goffee/tor"
)

const ipReflector = "http://stephensykes.com/ip_reflection.html"
const ipRefreshInterval = 5 * time.Minute

var exit = make(chan bool)
var currentIP string
var lastIPChange time.Time

func Run() {
	go run()
}

func run() {
	var wg sync.WaitGroup
	newip()

	for { // ever
		fmt.Println("Redis fetch")
		batch := queue.FetchBatch()
		fmt.Println(batch)
		for _, item := range batch {
			wg.Add(1)
			go check(item, &wg)
		}

		wg.Wait()

		if time.Since(lastIPChange) > ipRefreshInterval {
			newip()
		}

	}
}

func newip() {
	tor.NewIP()
	body, err := tor.TorGet(ipReflector)
	var result string
	if err != nil {
		result = err.Error()
	} else {
		result = body
	}
	currentIP = result
	fmt.Println("New IP obtained " + result)
	lastIPChange = time.Now()
}

func check(address string, wg *sync.WaitGroup) {
	defer wg.Done()

	status, err := tor.TorGetStatus(address)

	var statusCode int
	if err != nil {
		statusCode = -1
	} else {
		statusCode, err = strconv.Atoi(strings.Split(status, " ")[0])
		if err != nil {
			statusCode = -2
		}
	}

	result := &data.Result{
		CreatedAt: time.Now(),
		Status:    statusCode,
		Success:   statusCode >= 200 && statusCode < 300,
		URL:       address,
		IP:        currentIP,
	}

	data, err := json.Marshal(result)
	if err != nil {
		return
	}

	queue.WriteResult(string(data))
}

func Wait() {
	<-exit
}
<|endoftext|>


<commit_before>package api

import (
	"testing"
)

func assertQueryMeta(t *testing.T, qm *QueryMeta) {
	if qm.LastIndex == 0 {
		t.Fatalf("bad index: %d", qm.LastIndex)
	}
	if qm.RequestTime == 0 {
		t.Fatalf("bad request time: %d", qm.RequestTime)
	}
	if !qm.KnownLeader {
		t.Fatalf("expected known leader, got none")
	}
}

func assertWriteMeta(t *testing.T, wm *WriteMeta) {
	if wm.LastIndex == 0 {
		t.Fatalf("bad index: %d", wm.LastIndex)
	}
	if wm.RequestTime == 0 {
		t.Fatalf("bad request time: %d", wm.RequestTime)
	}
}

func testJob() *Job {
	return &Job{
		ID:       "job1",
		Name:     "redis",
		Type:     JobTypeService,
		Priority: 1,
	}
}
<commit_msg>api: fix tests after struct validations<commit_after>package api

import (
	"testing"
)

func assertQueryMeta(t *testing.T, qm *QueryMeta) {
	if qm.LastIndex == 0 {
		t.Fatalf("bad index: %d", qm.LastIndex)
	}
	if qm.RequestTime == 0 {
		t.Fatalf("bad request time: %d", qm.RequestTime)
	}
	if !qm.KnownLeader {
		t.Fatalf("expected known leader, got none")
	}
}

func assertWriteMeta(t *testing.T, wm *WriteMeta) {
	if wm.LastIndex == 0 {
		t.Fatalf("bad index: %d", wm.LastIndex)
	}
	if wm.RequestTime == 0 {
		t.Fatalf("bad request time: %d", wm.RequestTime)
	}
}

func testJob() *Job {
	return &Job{
		Region:      "region1",
		ID:          "job1",
		Name:        "redis",
		Type:        JobTypeService,
		Datacenters: []string{"dc1"},
		TaskGroups: []*TaskGroup{
			&TaskGroup{
				Name:  "group1",
				Count: 1,
				Tasks: []*Task{
					&Task{
						Name:   "task1",
						Driver: "exec",
						Resources: &Resources{
							MemoryMB: 256,
						},
					},
				},
			},
		},
		Priority: 1,
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"fmt"
	"net/http"
	"testing"

	lpxgen "github.com/heroku/lumbermill/Godeps/_workspace/src/github.com/apg/lpxgen"
	metrics "github.com/heroku/lumbermill/Godeps/_workspace/src/github.com/rcrowley/go-metrics"
)

func TestLumbermillDrain(t *testing.T) {
	sendBatchCount := int64(100)
	sendPointPerBatchCount := int64(10)

	influxdb := setupInfluxDBTestServer(newSleepyHandler(defaultTestClientTimeout / 4))
	influxHost := extractHostPort(influxdb.URL)

	// snapshot old values
	routerErrorsBefore := routerErrorLinesCounter.Count()
	routerLinesBefore := routerLinesCounter.Count()
	batchBefore := batchCounter.Count()
	pointSuccessBefore := int64(0)

	deliverySizeHistogram.Clear()

	// Get the before count, in case it was registered already
	if psc := metrics.DefaultRegistry.Get("lumbermill.poster.deliver.points." + influxHost); psc != nil {
		pointSuccessBefore = psc.(metrics.Counter).Count()
	}

	defer func() {
		routerErrors := routerErrorLinesCounter.Count() - routerErrorsBefore
		routerLines := routerLinesCounter.Count() - routerLinesBefore
		batches := batchCounter.Count() - batchBefore

		totalExpectedPoints := sendBatchCount * sendPointPerBatchCount

		// This is a bit wonky, but we don't have a *total* points delivered metric.
		// We can determine how many deliveries happened. Empircally, this is 1 for this
		// test. We try to ship 1000 points, so check that 1000 were shipped in that 1
		// delivery.
		psc := metrics.DefaultRegistry.Get("lumbermill.poster.deliver.points." + influxHost)
		if psc != nil {
			pointSuccess := psc.(metrics.Counter).Count() - pointSuccessBefore
			if pointSuccess == 0 {
				t.Errorf("Expected at least one delivery")
			}

			if pointSuccess == 1 && deliverySizeHistogram.Max() != totalExpectedPoints {
				t.Errorf("1 delivery happened, but not all points were published in that delivery. %d/%d", deliverySizeHistogram.Max(), totalExpectedPoints)
			}
		} else {
			t.Errorf("No pointSuccessBefore counter registered")
		}

		if routerErrors > 0 {
			t.Errorf("Some router errors were reported during the test: %d errors", routerErrors)
		}
		if routerLines == 0 {
			t.Errorf("No router lines processed")
		}
		if batches != sendBatchCount {
			t.Errorf("%d lost batches not accounted for", sendBatchCount-batches)
		}
	}()

	lumbermill, testServer, destinations, waitGroup := setupLumbermillTestServer(influxHost, "user:pass")
	shutdownChan := make(shutdownChan)

	defer func() {
		influxdb.Close()
		testServer.Close()
	}()

	go lumbermill.awaitShutdown()
	go func() {
		client := &http.Client{
			Transport: &http.Transport{
				TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
			},
		}

		gen := lpxgen.NewGenerator(int(sendPointPerBatchCount),
			int(sendPointPerBatchCount)+1, lpxgen.Router)

		drainURL := fmt.Sprintf("%s/drain", testServer.URL)

		for i := 0; i < int(sendBatchCount); i++ {
			req := gen.Generate(drainURL)
			req.SetBasicAuth("foo", "foo")
			if _, err := client.Do(req); err != nil {
				t.Errorf("Got an error during client.Do: %q", err)
			}
		}

		// Shutdown by calling Close() on both shutdownChan and lumbermill
		shutdownChan.Close()
		lumbermill.Close()
		for _, d := range destinations {
			d.Close()
		}
	}()

	awaitShutdown(shutdownChan, lumbermill, waitGroup)
}
<commit_msg>Drain tests: Turn 'em off<commit_after>package main

/*
import (
	"crypto/tls"
	"fmt"
	"net/http"
	"testing"

	lpxgen "github.com/heroku/lumbermill/Godeps/_workspace/src/github.com/apg/lpxgen"
)

func TestLumbermillDrain(t *testing.T) {
	sendBatchCount := int64(100)
	sendPointPerBatchCount := int64(10)

	influxdb := setupInfluxDBTestServer(newSleepyHandler(defaultTestClientTimeout / 4))
	influxHost := extractHostPort(influxdb.URL)

	// snapshot old values
	routerErrorsBefore := routerErrorLinesCounter.Count()
	routerLinesBefore := routerLinesCounter.Count()
	batchBefore := batchCounter.Count()
	pointSuccessBefore := int64(0)

	deliverySizeHistogram.Clear()

	// Get the before count, in case it was registered already
	if psc := metrics.DefaultRegistry.Get("lumbermill.poster.deliver.points." + influxHost); psc != nil {
		pointSuccessBefore = psc.(metrics.Counter).Count()
	}

	defer func() {
		routerErrors := routerErrorLinesCounter.Count() - routerErrorsBefore
		routerLines := routerLinesCounter.Count() - routerLinesBefore
		batches := batchCounter.Count() - batchBefore

		totalExpectedPoints := sendBatchCount * sendPointPerBatchCount

		// This is a bit wonky, but we don't have a *total* points delivered metric.
		// We can determine how many deliveries happened. Empircally, this is 1 for this
		// test. We try to ship 1000 points, so check that 1000 were shipped in that 1
		// delivery.
		psc := metrics.DefaultRegistry.Get("lumbermill.poster.deliver.points." + influxHost)
		if psc != nil {
			pointSuccess := psc.(metrics.Counter).Count() - pointSuccessBefore
			if pointSuccess == 0 {
				t.Errorf("Expected at least one delivery")
			}

			if pointSuccess == 1 && deliverySizeHistogram.Max() != totalExpectedPoints {
				t.Errorf("1 delivery happened, but not all points were published in that delivery. %d/%d", deliverySizeHistogram.Max(), totalExpectedPoints)
			}
		} else {
			t.Errorf("No pointSuccessBefore counter registered")
		}

		if routerErrors > 0 {
			t.Errorf("Some router errors were reported during the test: %d errors", routerErrors)
		}
		if routerLines == 0 {
			t.Errorf("No router lines processed")
		}
		if batches != sendBatchCount {
			t.Errorf("%d lost batches not accounted for", sendBatchCount-batches)
		}
	}()

	lumbermill, testServer, destinations, waitGroup := setupLumbermillTestServer(influxHost, "user:pass")
	shutdownChan := make(shutdownChan)

	defer func() {
		influxdb.Close()
		testServer.Close()
	}()

	go lumbermill.awaitShutdown()
	go func() {
		client := &http.Client{
			Transport: &http.Transport{
				TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
			},
		}

		gen := lpxgen.NewGenerator(int(sendPointPerBatchCount),
			int(sendPointPerBatchCount)+1, lpxgen.Router)

		drainURL := fmt.Sprintf("%s/drain", testServer.URL)

		for i := 0; i < int(sendBatchCount); i++ {
			req := gen.Generate(drainURL)
			req.SetBasicAuth("foo", "foo")
			if _, err := client.Do(req); err != nil {
				t.Errorf("Got an error during client.Do: %q", err)
			}
		}

		// Shutdown by calling Close() on both shutdownChan and lumbermill
		shutdownChan.Close()
		lumbermill.Close()
		for _, d := range destinations {
			d.Close()
		}
	}()

	awaitShutdown(shutdownChan, lumbermill, waitGroup)
}
*/
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"math"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"syscall"
	"time"
)

type updateJob struct {
	progress   *Progress
	onProgress chan *Progress
}

func (u *updateJob) start() {

	u.progress = &Progress{
		Running:   true,
		startTime: time.Now(),
	}

	u.updateProgress(0, "Updating cache", "")

	log.Infof("Updating from repositories")

	err := u.updateCache(45, 0, 25)
	if err != nil {
		u.updateProgress(0, "Failed", fmt.Sprintf("Error: %s", err))
		return
	}

	u.updateProgress(27, "Finding available updates", "")

	updates, err := u.getAvailableUpdates()

	if err != nil {
		u.updateProgress(0, "Failed", fmt.Sprintf("Error: %s", err))
		return
	}

	log.Infof("%d packages to update: %v", len(updates), updates)

	if len(updates) > 0 {

		u.updateProgress(30, "Installing updates", "")

		err = u.installUpdates(updates)

		if err != nil {
			u.updateProgress(0, "Failed", fmt.Sprintf("Error: %s", err))
			return
		}
	}

	u.updateProgress(100, "Finished", "")
}

func (u *updateJob) updateProgress(percent float64, description, err string) {

	if percent == 100 || err != "" {
		u.progress.Running = false
	}

	if percent > u.progress.Percent {
		u.progress.Percent = percent
	}

	if err != "" {
		u.progress.Error = err
	}

	if description != "" {
		u.progress.Description = description
	}

	u.onProgress <- u.progress
}

func (u *updateJob) updateCache(expectedLines float64, startPercent float64, totalPercent float64) error {

	if runtime.GOOS != "linux" {
		return nil
	}

	updateLines := 0.0

	cmd := exec.Command("apt-get", "update", "-q")

	reader, err := cmd.StdoutPipe()
	if err != nil {
		return err
	}

	bufReader := bufio.NewReader(reader)

	err = cmd.Start()

	if err != nil {
		return err
	}

	for {
		_, _, err := bufReader.ReadLine()

		if err != nil {
			//log.Infof("ERR:%s", err)
			break
		}

		updateLines++
		//cleaned := invalidChar.ReplaceAll([]byte(x[0:n]), []byte(""))

		u.updateProgress(startPercent+math.Min(totalPercent, (updateLines/expectedLines)*totalPercent), "", "")
		//	log.Infof("GOT: |%s| %t", line, isPrefix)
	}

	if err := cmd.Wait(); err != nil {
		if exiterr, ok := err.(*exec.ExitError); ok {
			// The program has exited with an exit code != 0
			// There is no plattform independent way to retrieve
			// the exit code, but the following will work on Unix
			if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
				log.Infof("Bad Exit Status: %d", status.ExitStatus())
				return fmt.Errorf("Failed to update cache. Code: %d", status.ExitStatus())
			}
		} else {
			log.Infof("Update cache : cmd.Wait: %v", err)
		}
	}

	return nil
}

func (u *updateJob) getAvailableUpdates() ([]AvailableUpdate, error) {
	var err error
	var available []byte

	ioutil.WriteFile("./available-updates.sh", []byte(`#!/bin/bash
	  apt-get -s dist-upgrade| awk -F'[][() ]+' '/^Inst/{printf "%s\t%s\t%s\n", $2,$3,$4}'`), os.FileMode(755))

	cmd := exec.Command("./available-updates.sh")

	if runtime.GOOS == "linux" {
		available, err = cmd.Output()
	} else {
		available, err = ioutil.ReadFile("./updates.txt")
	}

	if err != nil {
		return nil, fmt.Errorf("Failed to get updatable packages. Error: %s", err)
	}

	var updates []AvailableUpdate

	for _, line := range strings.Split(string(available), "\n") {
		s := strings.Split(line, "\t")
		if len(s) == 3 && strings.Contains(line, "spheramid") {
			updates = append(updates, AvailableUpdate{s[0], s[1], s[2]})
		}
	}

	if runtime.GOOS == "linux" {
		if err := cmd.Wait(); err != nil {
			if exiterr, ok := err.(*exec.ExitError); ok {
				// The program has exited with an exit code != 0
				// There is no plattform independent way to retrieve
				// the exit code, but the following will work on Unix
				if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
					log.Infof("Bad Exit Status: %d", status.ExitStatus())
					return nil, fmt.Errorf("Failed to get updatable packages. Code: %d", status.ExitStatus())
				}
			} else {
				log.Infof("Get updatable : cmd.Wait: %v", err)
			}
		}
	}

	return updates, nil
}

func (u *updateJob) installUpdates(updates []AvailableUpdate) error {

	var cmd *exec.Cmd
	if runtime.GOOS == "linux" {
		args := []string{"install", "-yy", "-q"}
		for _, update := range updates {
			args = append(args, update.Name)
		}

		log.Infof("Running update command : apt-get %s", strings.Join(args, " "))

		cmd = exec.Command("apt-get", args...)
		cmd.Stderr = os.Stderr
	} else {
		cmd = exec.Command("cat", "./upgrade.txt")
	}

	os.Setenv("DEBIAN_FRONTEND", "noninteractive")

	reader, err := cmd.StdoutPipe()

	bufReader := bufio.NewReader(reader)

	err = cmd.Start()

	if err != nil {
		return err
	}

	pointsPerPackage := float64(10) / float64(len(updates))

	percent := 30.0

	go func() {
		for {
			line, _, err := bufReader.ReadLine()

			log.Debugf("apt: " + string(line))

			if err != nil {
				//log.Infof("ERR:%s", err)
				break
			}

			if strings.HasPrefix(string(line), "Reading package lists") {
				percent = percent + 5.0
			}

			if strings.HasPrefix(string(line), "Building dependency tree") {
				percent = percent + 5.0
			}

			if strings.HasPrefix(string(line), "Reading state information") {
				percent = percent + 5.0
			}

			if strings.HasPrefix(string(line), "Need to get") {
				percent = percent + 5.0
			}

			if strings.HasPrefix(string(line), "Get:") {
				percent = percent + (pointsPerPackage * float64(2))
			}

			if strings.HasPrefix(string(line), "Unpacking ") {
				percent = percent + (pointsPerPackage * float64(2))
			}

			if strings.HasPrefix(string(line), "Setting up ") {
				percent = percent + pointsPerPackage
			}

			u.updateProgress(math.Min(99, percent), "Installing updates", "")

		}
	}()

	if err := cmd.Wait(); err != nil {
		if exiterr, ok := err.(*exec.ExitError); ok {
			// The program has exited with an exit code != 0
			// There is no plattform independent way to retrieve
			// the exit code, but the following will work on Unix
			if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
				log.Infof("Bad Exit Status: %d", status.ExitStatus())
				return fmt.Errorf("Failed to install updates. Code:%d", status.ExitStatus())
			}
		} else {
			log.Infof("cmd.Wait: %v", err)
		}
	}

	return nil
}
<commit_msg>Update description of update events<commit_after>package main

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"math"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"syscall"
	"time"
)

type updateJob struct {
	progress   *Progress
	onProgress chan *Progress
}

func (u *updateJob) start() {

	u.progress = &Progress{
		Running:   true,
		startTime: time.Now(),
	}

	u.updateProgress(0, "Looking for updates", "")

	log.Infof("Updating from repositories")

	err := u.updateCache(45, 0, 25)
	if err != nil {
		u.updateProgress(0, "Failed", fmt.Sprintf("Error: %s", err))
		return
	}

	u.updateProgress(27, "Processing available updates", "")

	updates, err := u.getAvailableUpdates()

	if err != nil {
		u.updateProgress(0, "Failed", fmt.Sprintf("Error: %s", err))
		return
	}

	log.Infof("%d packages to update: %v", len(updates), updates)

	if len(updates) > 0 {

		u.updateProgress(30, "Installing updates", "")

		err = u.installUpdates(updates)

		if err != nil {
			u.updateProgress(0, "Failed", fmt.Sprintf("Error: %s", err))
			return
		}
	}

	u.updateProgress(100, "Finished", "")
}

func (u *updateJob) updateProgress(percent float64, description, err string) {

	if percent == 100 || err != "" {
		u.progress.Running = false
	}

	if percent > u.progress.Percent {
		u.progress.Percent = percent
	}

	if err != "" {
		u.progress.Error = err
	}

	if description != "" {
		u.progress.Description = description
	}

	u.onProgress <- u.progress
}

func (u *updateJob) updateCache(expectedLines float64, startPercent float64, totalPercent float64) error {

	if runtime.GOOS != "linux" {
		return nil
	}

	updateLines := 0.0

	cmd := exec.Command("apt-get", "update", "-q")

	reader, err := cmd.StdoutPipe()
	if err != nil {
		return err
	}

	bufReader := bufio.NewReader(reader)

	err = cmd.Start()

	if err != nil {
		return err
	}

	for {
		_, _, err := bufReader.ReadLine()

		if err != nil {
			//log.Infof("ERR:%s", err)
			break
		}

		updateLines++
		//cleaned := invalidChar.ReplaceAll([]byte(x[0:n]), []byte(""))

		u.updateProgress(startPercent+math.Min(totalPercent, (updateLines/expectedLines)*totalPercent), "", "")
		//	log.Infof("GOT: |%s| %t", line, isPrefix)
	}

	if err := cmd.Wait(); err != nil {
		if exiterr, ok := err.(*exec.ExitError); ok {
			// The program has exited with an exit code != 0
			// There is no plattform independent way to retrieve
			// the exit code, but the following will work on Unix
			if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
				log.Infof("Bad Exit Status: %d", status.ExitStatus())
				return fmt.Errorf("Failed to update cache. Code: %d", status.ExitStatus())
			}
		} else {
			log.Infof("Update cache : cmd.Wait: %v", err)
		}
	}

	return nil
}

func (u *updateJob) getAvailableUpdates() ([]AvailableUpdate, error) {
	var err error
	var available []byte

	ioutil.WriteFile("./available-updates.sh", []byte(`#!/bin/bash
	  apt-get -s dist-upgrade| awk -F'[][() ]+' '/^Inst/{printf "%s\t%s\t%s\n", $2,$3,$4}'`), os.FileMode(755))

	cmd := exec.Command("./available-updates.sh")

	if runtime.GOOS == "linux" {
		available, err = cmd.Output()
	} else {
		available, err = ioutil.ReadFile("./updates.txt")
	}

	if err != nil {
		return nil, fmt.Errorf("Failed to get updatable packages. Error: %s", err)
	}

	var updates []AvailableUpdate

	for _, line := range strings.Split(string(available), "\n") {
		s := strings.Split(line, "\t")
		if len(s) == 3 && strings.Contains(line, "spheramid") {
			updates = append(updates, AvailableUpdate{s[0], s[1], s[2]})
		}
	}

	if runtime.GOOS == "linux" {
		if err := cmd.Wait(); err != nil {
			if exiterr, ok := err.(*exec.ExitError); ok {
				// The program has exited with an exit code != 0
				// There is no plattform independent way to retrieve
				// the exit code, but the following will work on Unix
				if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
					log.Infof("Bad Exit Status: %d", status.ExitStatus())
					return nil, fmt.Errorf("Failed to get updatable packages. Code: %d", status.ExitStatus())
				}
			} else {
				log.Infof("Get updatable : cmd.Wait: %v", err)
			}
		}
	}

	return updates, nil
}

func (u *updateJob) installUpdates(updates []AvailableUpdate) error {

	var cmd *exec.Cmd
	if runtime.GOOS == "linux" {
		args := []string{"install", "-yy", "-q"}
		for _, update := range updates {
			args = append(args, update.Name)
		}

		log.Infof("Running update command : apt-get %s", strings.Join(args, " "))

		cmd = exec.Command("apt-get", args...)
		cmd.Stderr = os.Stderr
	} else {
		cmd = exec.Command("cat", "./upgrade.txt")
	}

	os.Setenv("DEBIAN_FRONTEND", "noninteractive")

	reader, err := cmd.StdoutPipe()

	bufReader := bufio.NewReader(reader)

	err = cmd.Start()

	if err != nil {
		return err
	}

	pointsPerPackage := float64(10) / float64(len(updates))

	percent := 30.0

	go func() {
		for {
			line, _, err := bufReader.ReadLine()

			log.Debugf("apt: " + string(line))

			if err != nil {
				//log.Infof("ERR:%s", err)
				break
			}

			if strings.HasPrefix(string(line), "Reading package lists") {
				percent = percent + 5.0
			}

			if strings.HasPrefix(string(line), "Building dependency tree") {
				percent = percent + 5.0
			}

			if strings.HasPrefix(string(line), "Reading state information") {
				percent = percent + 5.0
			}

			if strings.HasPrefix(string(line), "Need to get") {
				percent = percent + 5.0
			}

			if strings.HasPrefix(string(line), "Get:") {
				percent = percent + (pointsPerPackage * float64(2))
			}

			if strings.HasPrefix(string(line), "Unpacking ") {
				percent = percent + (pointsPerPackage * float64(2))
			}

			if strings.HasPrefix(string(line), "Setting up ") {
				percent = percent + pointsPerPackage
			}

			u.updateProgress(math.Min(99, percent), "Installing updates", "")

		}
	}()

	if err := cmd.Wait(); err != nil {
		if exiterr, ok := err.(*exec.ExitError); ok {
			// The program has exited with an exit code != 0
			// There is no plattform independent way to retrieve
			// the exit code, but the following will work on Unix
			if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
				log.Infof("Bad Exit Status: %d", status.ExitStatus())
				return fmt.Errorf("Failed to install updates. Code:%d", status.ExitStatus())
			}
		} else {
			log.Infof("cmd.Wait: %v", err)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>//
// Copyright 2014-2016 Cristian Maglie. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//

package serial // import "go.bug.st/serial.v1"

func nativeGetDetailedPortsList() ([]*PortDetails, error) {
	// TODO
	return nil, &PortError{code: FunctionNotImplemented}
}
<commit_msg>Added USB discovery for Linux<commit_after>//
// Copyright 2014-2016 Cristian Maglie. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//

package serial // import "go.bug.st/serial.v1"

import (
	"bufio"
	"fmt"
	"os"
	"path/filepath"
)

func nativeGetDetailedPortsList() ([]*PortDetails, error) {
	// Retrieve the port list
	ports, err := nativeGetPortsList()
	if err != nil {
		return nil, &PortError{code: ErrorEnumeratingPorts, causedBy: err}
	}

	var res []*PortDetails
	for _, port := range ports {
		details, err := nativeGetPortDetails(port)
		if err != nil {
			return nil, &PortError{code: ErrorEnumeratingPorts, causedBy: err}
		}
		res = append(res, details)
	}
	return res, nil
}

func nativeGetPortDetails(portPath string) (*PortDetails, error) {
	portName := filepath.Base(portPath)
	devicePath := fmt.Sprintf("/sys/class/tty/%s/device", portName)
	if _, err := os.Stat(devicePath); err != nil {
		return &PortDetails{}, nil
	}
	realDevicePath, err := filepath.EvalSymlinks(devicePath)
	if err != nil {
		return nil, fmt.Errorf("Can't determine real path of %s: %s", devicePath, err.Error())
	}
	subSystemPath, err := filepath.EvalSymlinks(filepath.Join(realDevicePath, "subsystem"))
	if err != nil {
		return nil, fmt.Errorf("Can't determine real path of %s: %s", filepath.Join(realDevicePath, "subsystem"), err.Error())
	}
	subSystem := filepath.Base(subSystemPath)

	result := &PortDetails{Name: portPath}
	switch subSystem {
	case "usb-serial":
		err := parseUSBSysFS(filepath.Dir(filepath.Dir(realDevicePath)), result)
		return result, err
	case "usb":
		err := parseUSBSysFS(filepath.Dir(realDevicePath), result)
		return result, err
	// TODO: other cases?
	default:
		return result, nil
	}
}

func parseUSBSysFS(usbDevicePath string, details *PortDetails) error {
	vid, err := readLine(filepath.Join(usbDevicePath, "idVendor"))
	if err != nil {
		return err
	}
	pid, err := readLine(filepath.Join(usbDevicePath, "idProduct"))
	if err != nil {
		return err
	}
	serial, err := readLine(filepath.Join(usbDevicePath, "serial"))
	if err != nil {
		return err
	}
	manufacturer, err := readLine(filepath.Join(usbDevicePath, "manufacturer"))
	if err != nil {
		return err
	}
	product, err := readLine(filepath.Join(usbDevicePath, "product"))
	if err != nil {
		return err
	}

	details.IsUSB = true
	details.VID = vid
	details.PID = pid
	details.SerialNumber = serial
	details.Manufacturer = manufacturer
	details.Product = product
	return nil
}

func readLine(filename string) (string, error) {
	file, err := os.Open(filename)
	if os.IsNotExist(err) {
		return "", nil
	}
	if err != nil {
		return "", err
	}
	defer file.Close()
	reader := bufio.NewReader(file)
	line, _, err := reader.ReadLine()
	return string(line), err
}
<|endoftext|>