<commit_before>package godet

import (
	"encoding/base64"
	"encoding/json"
	"log"
	"sync"

	"github.com/gobs/httpclient"
	"github.com/gorilla/websocket"
)

func decode(resp *httpclient.HttpResponse, v interface{}) error {
	err := json.NewDecoder(resp.Body).Decode(v)
	resp.Close()

	return err
}

func unmarshal(payload []byte) (map[string]interface{}, error) {
	var response map[string]interface{}
	err := json.Unmarshal(payload, &response)
	if err != nil {
		log.Println("error unmarshaling", string(payload), len(payload), err)
	}
	return response, err
}

//
// DevTools version info
//
type Version struct {
	Browser         string `json:"Browser"`
	ProtocolVersion string `json:"Protocol-Version"`
	UserAgent       string `json:"User-Agent"`
	V8Version       string `json:"V8-Version"`
	WebKitVersion   string `json:"WebKit-Version"`
}

//
// Chrome open tab or page
//
type Tab struct {
	Id          string `json:"id"`
	Type        string `json:"type"`
	Description string `json:"description"`
	Title       string `json:"title"`
	Url         string `json:"url"`
	WsUrl       string `json:"webSocketDebuggerUrl"`
	DevUrl      string `json:"devtoolsFrontendUrl"`
}

//
// RemoteDebugger
//
type RemoteDebugger struct {
	http    *httpclient.HttpClient
	ws      *websocket.Conn
	reqid   int
	verbose bool

	sync.Mutex
	closed chan bool

	requests  chan Params
	responses map[int]chan json.RawMessage
	callbacks map[string]EventCallback
	events    chan wsMessage
}

type Params map[string]interface{}
type EventCallback func(params Params)

//
// Connect to the remote debugger and return `RemoteDebugger` object
//
func Connect(port string, verbose bool) (*RemoteDebugger, error) {
	remote := &RemoteDebugger{
		http:      httpclient.NewHttpClient("http://" + port),
		requests:  make(chan Params),
		responses: map[int]chan json.RawMessage{},
		callbacks: map[string]EventCallback{},
		events:    make(chan wsMessage, 256),
		closed:    make(chan bool),
		verbose:   verbose,
	}

	remote.http.Verbose = verbose

	// check http connection
	tabs, err := remote.TabList("")
	if err != nil {
		return nil, err
	}

	getWsUrl := func() string {
		for _, tab := range tabs {
			if tab.WsUrl != "" {
				return tab.WsUrl
			}
		}

		return "ws://" + port + "/devtools/page/00000000-0000-0000-0000-000000000000"
	}

	wsUrl := getWsUrl()

	// check websocket connection
	if remote.ws, _, err = websocket.DefaultDialer.Dial(wsUrl, nil); err != nil {
		if verbose {
			log.Println("dial", wsUrl, "error", err)
		}
		return nil, err
	}

	go remote.readMessages()
	go remote.sendMessages()
	go remote.processEvents()
	return remote, nil
}

func (remote *RemoteDebugger) Close() error {
	close(remote.closed)
	err := remote.ws.Close()
	return err
}

type wsMessage struct {
	Id     int             `json:"id"`
	Result json.RawMessage `json:"result"`

	Method string          `json:"Method"`
	Params json.RawMessage `json:"Params"`
}

func (remote *RemoteDebugger) sendRequest(method string, params Params) (map[string]interface{}, error) {
	remote.Lock()
	reqid := remote.reqid
	remote.responses[reqid] = make(chan json.RawMessage, 1)
	remote.reqid++
	remote.Unlock()

	command := Params{
		"id":     reqid,
		"method": method,
		"params": params,
	}

	remote.requests <- command

	reply := <-remote.responses[reqid]
	remote.Lock()
	remote.responses[reqid] = nil
	remote.Unlock()

	if reply != nil {
		return unmarshal(reply)
	}

	return nil, nil
}

func (remote *RemoteDebugger) sendMessages() {
	for message := range remote.requests {
		bytes, err := json.Marshal(message)
		if err != nil {
			log.Println("error marshaling message", err)
			continue
		}

		if remote.verbose {
			log.Println("SEND", string(bytes))
		}

		err = remote.ws.WriteMessage(websocket.TextMessage, bytes)
		if err != nil {
			log.Println("error sending message", err)
		}
	}
}

func (remote *RemoteDebugger) readMessages() {
loop:
	for {
		select {
		case <-remote.closed:
			break loop

		default:
			_, bytes, err := remote.ws.ReadMessage()
			if err != nil {
				log.Println("read error", err)
				if websocket.IsUnexpectedCloseError(err) {
					break loop
				}
			} else {
				var message wsMessage

				//
				// unmarshall message
				//
				if err := json.Unmarshal(bytes, &message); err != nil {
					log.Println("error unmarshaling", string(bytes), len(bytes), err)
				} else if message.Method != "" {
					if remote.verbose {
						log.Println("EVENT", message.Method, string(message.Params))
						log.Println(len(remote.events))
					}

					select {
					case remote.events <- message:

					case <-remote.closed:
						break loop
					}
				} else {
					//
					// should be a method reply
					//
					if remote.verbose {
						log.Println("REPLY", message.Id, string(message.Result))
					}

					remote.Lock()
					ch := remote.responses[message.Id]
					remote.Unlock()

					if ch != nil {
						ch <- message.Result
					}
				}
			}
		}
	}

	close(remote.events)
}

func (remote *RemoteDebugger) processEvents() {
	for ev := range remote.events {
		remote.Lock()
		cb := remote.callbacks[ev.Method]
		remote.Unlock()

		if cb != nil {
			var params Params
			if err := json.Unmarshal(ev.Params, &params); err != nil {
				log.Println("error unmarshaling", string(ev.Params), len(ev.Params), err)
			} else {
				cb(params)
			}
		}
	}
}

//
// Return various version info (protocol, browser, etc.)
//
func (remote *RemoteDebugger) Version() (*Version, error) {
	resp, err := remote.http.Get("/json/version", nil, nil)
	if err != nil {
		return nil, err
	}

	var version Version

	if err = decode(resp, &version); err != nil {
		return nil, err
	}

	return &version, nil
}

//
// Return the list of open tabs/page
//
// If filter is not empty only tabs of the specified type are returned (i.e. "page")
//
func (remote *RemoteDebugger) TabList(filter string) ([]*Tab, error) {
	resp, err := remote.http.Get("/json/list", nil, nil)
	if err != nil {
		return nil, err
	}

	var tabs []*Tab

	if err = decode(resp, &tabs); err != nil {
		return nil, err
	}

	if filter == "" {
		return tabs, nil
	}

	var filtered []*Tab

	for _, t := range tabs {
		if t.Type == filter {
			filtered = append(filtered, t)
		}
	}

	return filtered, nil
}

//
// Activate specified tab
//
func (remote *RemoteDebugger) ActivateTab(tab *Tab) error {
	resp, err := remote.http.Get("/json/activate/"+tab.Id, nil, nil)
	resp.Close()
	return err
}

//
// Close specified tab
//
func (remote *RemoteDebugger) CloseTab(tab *Tab) error {
	resp, err := remote.http.Get("/json/close/"+tab.Id, nil, nil)
	resp.Close()
	return err
}

//
// Create a new tab
//
func (remote *RemoteDebugger) NewTab(url string) (*Tab, error) {
	params := Params{}
	if url != "" {
		params["url"] = url
	}
	resp, err := remote.http.Get("/json/new", params, nil)
	if err != nil {
		return nil, err
	}

	var tab Tab
	if err = decode(resp, &tab); err != nil {
		return nil, err
	}

	return &tab, nil
}

func (remote *RemoteDebugger) GetDomains() (map[string]interface{}, error) {
	res, err := remote.sendRequest("Schema.getDomains", nil)
	return res, err
}

func (remote *RemoteDebugger) Navigate(url string) error {
	_, err := remote.sendRequest("Page.navigate", Params{
		"url": url,
	})

	return err
}

func (remote *RemoteDebugger) GetResponseBody(req string) ([]byte, error) {
	res, err := remote.sendRequest("Network.getResponseBody", Params{
		"requestId": req,
	})

	if err != nil {
		return nil, err
	} else if res["base64Encoded"].(bool) {
		return base64.StdEncoding.DecodeString(res["body"].(string))
	} else {
		return []byte(res["body"].(string)), nil
	}
}

func (remote *RemoteDebugger) GetDocument() (map[string]interface{}, error) {
	return remote.sendRequest("DOM.getDocument", nil)
}

func (remote *RemoteDebugger) QuerySelector(nodeId int, selector string) (map[string]interface{}, error) {
	return remote.sendRequest("DOM.querySelector", Params{
		"nodeId":   nodeId,
		"selector": selector,
	})
}

func (remote *RemoteDebugger) QuerySelectorAll(nodeId int, selector string) (map[string]interface{}, error) {
	return remote.sendRequest("DOM.querySelectorAll", Params{
		"nodeId":   nodeId,
		"selector": selector,
	})
}

func (remote *RemoteDebugger) ResolveNode(nodeId int) (map[string]interface{}, error) {
	return remote.sendRequest("DOM.resolveNode", Params{
		"nodeId": nodeId,
	})
}

func (remote *RemoteDebugger) CallbackEvent(method string, cb EventCallback) {
	remote.Lock()
	remote.callbacks[method] = cb
	remote.Unlock()
}

func (remote *RemoteDebugger) domainEvents(domain string, enable bool) error {
	method := domain

	if enable {
		method += ".enable"
	} else {
		method += ".disable"
	}

	_, err := remote.sendRequest(method, nil)
	return err
}

func (remote *RemoteDebugger) DOMEvents(enable bool) error {
	return remote.domainEvents("DOM", enable)
}

func (remote *RemoteDebugger) PageEvents(enable bool) error {
	return remote.domainEvents("Page", enable)
}

func (remote *RemoteDebugger) NetworkEvents(enable bool) error {
	return remote.domainEvents("Network", enable)
}

func (remote *RemoteDebugger) RuntimeEvents(enable bool) error {
	return remote.domainEvents("Runtime", enable)
}
<commit_msg>don't push events that are not requested<commit_after>package godet

import (
	"encoding/base64"
	"encoding/json"
	"log"
	"sync"

	"github.com/gobs/httpclient"
	"github.com/gorilla/websocket"
)

func decode(resp *httpclient.HttpResponse, v interface{}) error {
	err := json.NewDecoder(resp.Body).Decode(v)
	resp.Close()

	return err
}

func unmarshal(payload []byte) (map[string]interface{}, error) {
	var response map[string]interface{}
	err := json.Unmarshal(payload, &response)
	if err != nil {
		log.Println("error unmarshaling", string(payload), len(payload), err)
	}
	return response, err
}

//
// DevTools version info
//
type Version struct {
	Browser         string `json:"Browser"`
	ProtocolVersion string `json:"Protocol-Version"`
	UserAgent       string `json:"User-Agent"`
	V8Version       string `json:"V8-Version"`
	WebKitVersion   string `json:"WebKit-Version"`
}

//
// Chrome open tab or page
//
type Tab struct {
	Id          string `json:"id"`
	Type        string `json:"type"`
	Description string `json:"description"`
	Title       string `json:"title"`
	Url         string `json:"url"`
	WsUrl       string `json:"webSocketDebuggerUrl"`
	DevUrl      string `json:"devtoolsFrontendUrl"`
}

//
// RemoteDebugger
//
type RemoteDebugger struct {
	http    *httpclient.HttpClient
	ws      *websocket.Conn
	reqid   int
	verbose bool

	sync.Mutex
	closed chan bool

	requests  chan Params
	responses map[int]chan json.RawMessage
	callbacks map[string]EventCallback
	events    chan wsMessage
}

type Params map[string]interface{}
type EventCallback func(params Params)

//
// Connect to the remote debugger and return `RemoteDebugger` object
//
func Connect(port string, verbose bool) (*RemoteDebugger, error) {
	remote := &RemoteDebugger{
		http:      httpclient.NewHttpClient("http://" + port),
		requests:  make(chan Params),
		responses: map[int]chan json.RawMessage{},
		callbacks: map[string]EventCallback{},
		events:    make(chan wsMessage, 256),
		closed:    make(chan bool),
		verbose:   verbose,
	}

	remote.http.Verbose = verbose

	// check http connection
	tabs, err := remote.TabList("")
	if err != nil {
		return nil, err
	}

	getWsUrl := func() string {
		for _, tab := range tabs {
			if tab.WsUrl != "" {
				return tab.WsUrl
			}
		}

		return "ws://" + port + "/devtools/page/00000000-0000-0000-0000-000000000000"
	}

	wsUrl := getWsUrl()

	// check websocket connection
	if remote.ws, _, err = websocket.DefaultDialer.Dial(wsUrl, nil); err != nil {
		if verbose {
			log.Println("dial", wsUrl, "error", err)
		}
		return nil, err
	}

	go remote.readMessages()
	go remote.sendMessages()
	go remote.processEvents()
	return remote, nil
}

func (remote *RemoteDebugger) Close() error {
	close(remote.closed)
	err := remote.ws.Close()
	return err
}

type wsMessage struct {
	Id     int             `json:"id"`
	Result json.RawMessage `json:"result"`

	Method string          `json:"Method"`
	Params json.RawMessage `json:"Params"`
}

func (remote *RemoteDebugger) sendRequest(method string, params Params) (map[string]interface{}, error) {
	remote.Lock()
	reqid := remote.reqid
	remote.responses[reqid] = make(chan json.RawMessage, 1)
	remote.reqid++
	remote.Unlock()

	command := Params{
		"id":     reqid,
		"method": method,
		"params": params,
	}

	remote.requests <- command

	reply := <-remote.responses[reqid]
	remote.Lock()
	remote.responses[reqid] = nil
	remote.Unlock()

	if reply != nil {
		return unmarshal(reply)
	}

	return nil, nil
}

func (remote *RemoteDebugger) sendMessages() {
	for message := range remote.requests {
		bytes, err := json.Marshal(message)
		if err != nil {
			log.Println("error marshaling message", err)
			continue
		}

		if remote.verbose {
			log.Println("SEND", string(bytes))
		}

		err = remote.ws.WriteMessage(websocket.TextMessage, bytes)
		if err != nil {
			log.Println("error sending message", err)
		}
	}
}

func (remote *RemoteDebugger) readMessages() {
loop:
	for {
		select {
		case <-remote.closed:
			break loop

		default:
			_, bytes, err := remote.ws.ReadMessage()
			if err != nil {
				log.Println("read error", err)
				if websocket.IsUnexpectedCloseError(err) {
					break loop
				}
			} else {
				var message wsMessage

				//
				// unmarshall message
				//
				if err := json.Unmarshal(bytes, &message); err != nil {
					log.Println("error unmarshaling", string(bytes), len(bytes), err)
				} else if message.Method != "" {
					if remote.verbose {
						log.Println("EVENT", message.Method, string(message.Params))
						log.Println(len(remote.events))
					}

					remote.Lock()
					_, ok := remote.callbacks[message.Method]
					remote.Unlock()

					if !ok {
						continue // don't queue unrequested events
					}

					select {
					case remote.events <- message:

					case <-remote.closed:
						break loop
					}
				} else {
					//
					// should be a method reply
					//
					if remote.verbose {
						log.Println("REPLY", message.Id, string(message.Result))
					}

					remote.Lock()
					ch := remote.responses[message.Id]
					remote.Unlock()

					if ch != nil {
						ch <- message.Result
					}
				}
			}
		}
	}

	close(remote.events)
}

func (remote *RemoteDebugger) processEvents() {
	for ev := range remote.events {
		remote.Lock()
		cb := remote.callbacks[ev.Method]
		remote.Unlock()

		if cb != nil {
			var params Params
			if err := json.Unmarshal(ev.Params, &params); err != nil {
				log.Println("error unmarshaling", string(ev.Params), len(ev.Params), err)
			} else {
				cb(params)
			}
		}
	}
}

//
// Return various version info (protocol, browser, etc.)
//
func (remote *RemoteDebugger) Version() (*Version, error) {
	resp, err := remote.http.Get("/json/version", nil, nil)
	if err != nil {
		return nil, err
	}

	var version Version

	if err = decode(resp, &version); err != nil {
		return nil, err
	}

	return &version, nil
}

//
// Return the list of open tabs/page
//
// If filter is not empty only tabs of the specified type are returned (i.e. "page")
//
func (remote *RemoteDebugger) TabList(filter string) ([]*Tab, error) {
	resp, err := remote.http.Get("/json/list", nil, nil)
	if err != nil {
		return nil, err
	}

	var tabs []*Tab

	if err = decode(resp, &tabs); err != nil {
		return nil, err
	}

	if filter == "" {
		return tabs, nil
	}

	var filtered []*Tab

	for _, t := range tabs {
		if t.Type == filter {
			filtered = append(filtered, t)
		}
	}

	return filtered, nil
}

//
// Activate specified tab
//
func (remote *RemoteDebugger) ActivateTab(tab *Tab) error {
	resp, err := remote.http.Get("/json/activate/"+tab.Id, nil, nil)
	resp.Close()
	return err
}

//
// Close specified tab
//
func (remote *RemoteDebugger) CloseTab(tab *Tab) error {
	resp, err := remote.http.Get("/json/close/"+tab.Id, nil, nil)
	resp.Close()
	return err
}

//
// Create a new tab
//
func (remote *RemoteDebugger) NewTab(url string) (*Tab, error) {
	params := Params{}
	if url != "" {
		params["url"] = url
	}
	resp, err := remote.http.Get("/json/new", params, nil)
	if err != nil {
		return nil, err
	}

	var tab Tab
	if err = decode(resp, &tab); err != nil {
		return nil, err
	}

	return &tab, nil
}

func (remote *RemoteDebugger) GetDomains() (map[string]interface{}, error) {
	res, err := remote.sendRequest("Schema.getDomains", nil)
	return res, err
}

func (remote *RemoteDebugger) Navigate(url string) error {
	_, err := remote.sendRequest("Page.navigate", Params{
		"url": url,
	})

	return err
}

func (remote *RemoteDebugger) GetResponseBody(req string) ([]byte, error) {
	res, err := remote.sendRequest("Network.getResponseBody", Params{
		"requestId": req,
	})

	if err != nil {
		return nil, err
	} else if res["base64Encoded"].(bool) {
		return base64.StdEncoding.DecodeString(res["body"].(string))
	} else {
		return []byte(res["body"].(string)), nil
	}
}

func (remote *RemoteDebugger) GetDocument() (map[string]interface{}, error) {
	return remote.sendRequest("DOM.getDocument", nil)
}

func (remote *RemoteDebugger) QuerySelector(nodeId int, selector string) (map[string]interface{}, error) {
	return remote.sendRequest("DOM.querySelector", Params{
		"nodeId":   nodeId,
		"selector": selector,
	})
}

func (remote *RemoteDebugger) QuerySelectorAll(nodeId int, selector string) (map[string]interface{}, error) {
	return remote.sendRequest("DOM.querySelectorAll", Params{
		"nodeId":   nodeId,
		"selector": selector,
	})
}

func (remote *RemoteDebugger) ResolveNode(nodeId int) (map[string]interface{}, error) {
	return remote.sendRequest("DOM.resolveNode", Params{
		"nodeId": nodeId,
	})
}

func (remote *RemoteDebugger) CallbackEvent(method string, cb EventCallback) {
	remote.Lock()
	remote.callbacks[method] = cb
	remote.Unlock()
}

func (remote *RemoteDebugger) domainEvents(domain string, enable bool) error {
	method := domain

	if enable {
		method += ".enable"
	} else {
		method += ".disable"
	}

	_, err := remote.sendRequest(method, nil)
	return err
}

func (remote *RemoteDebugger) DOMEvents(enable bool) error {
	return remote.domainEvents("DOM", enable)
}

func (remote *RemoteDebugger) PageEvents(enable bool) error {
	return remote.domainEvents("Page", enable)
}

func (remote *RemoteDebugger) NetworkEvents(enable bool) error {
	return remote.domainEvents("Network", enable)
}

func (remote *RemoteDebugger) RuntimeEvents(enable bool) error {
	return remote.domainEvents("Runtime", enable)
}
<|endoftext|>


<commit_before>package muta

import (
	"io/ioutil"
	"os"
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func TestSrcStreamer(t *testing.T) {
	Convey("Should pipe incoming chunks", t, func() {
		s := SrcStreamer([]string{}, SrcOpts{})
		fi := &FileInfo{}
		b := []byte("chunk")
		rfi, rb, err := s(fi, b)
		So(err, ShouldBeNil)
		So(rfi, ShouldEqual, fi)
		So(rb, ShouldResemble, b)
		s(fi, b)
	})

	Convey("Should return an error if the file cannot be found", t, func() {
		s := SrcStreamer([]string{"_test/fixtures/404"}, SrcOpts{})
		_, _, err := s(nil, nil)
		So(err, ShouldNotBeNil)
	})

	Convey("Should load the given file and", t, func() {
		Convey("Populate FileInfo with the file info", func() {
			s := SrcStreamer([]string{"_test/fixtures/hello"}, SrcOpts{})
			fi, _, err := s(nil, nil)
			So(err, ShouldBeNil)
			So(fi, ShouldResemble, &FileInfo{
				Name:         "hello",
				Path:         "_test/fixtures",
				OriginalName: "hello",
				OriginalPath: "_test/fixtures",
				Ctx:          map[string]interface{}{},
			})
			// flush for defer file close
			s(nil, nil)
		})

		Convey("Return chunks of the file", func() {
			s := SrcStreamer([]string{"_test/fixtures/hello"}, SrcOpts{
				ReadSize: 5,
			})
			_, b, err := s(nil, nil)
			So(err, ShouldBeNil)
			So(b, ShouldResemble, []byte("hello"))
			// flush for defer file close
			s(nil, nil)
		})

		Convey("Return multiple chunks of the file", func() {
			s := SrcStreamer([]string{"_test/fixtures/hello"}, SrcOpts{
				ReadSize: 3,
			})
			_, b, err := s(nil, nil)
			So(err, ShouldBeNil)
			So(b, ShouldResemble, []byte("hel"))
			_, b, err = s(nil, nil)
			So(err, ShouldBeNil)
			So(b, ShouldResemble, []byte("lo"))
			// flush for defer file close
			s(nil, nil)
		})

		Convey("Return a valid FileInfo at EOF", func() {
			s := SrcStreamer([]string{"_test/fixtures/hello"}, SrcOpts{
				ReadSize: 5,
			})
			s(nil, nil)
			fi, _, err := s(nil, nil)
			So(err, ShouldBeNil)
			So(fi, ShouldResemble, &FileInfo{
				Name:         "hello",
				Path:         "_test/fixtures",
				OriginalName: "hello",
				OriginalPath: "_test/fixtures",
				Ctx:          map[string]interface{}{},
			})
		})

		Convey("Return a nil chunk at EOF", func() {
			s := SrcStreamer([]string{"_test/fixtures/hello"}, SrcOpts{
				ReadSize: 5,
			})
			s(nil, nil)
			_, b, err := s(nil, nil)
			So(err, ShouldBeNil)
			So(b, ShouldBeNil)
		})

		Convey("Trim byte array to length of data", func() {
			s := SrcStreamer([]string{"_test/fixtures/hello"}, SrcOpts{
				ReadSize: 4,
			})
			_, b, _ := s(nil, nil)
			So(b, ShouldResemble, []byte("hell"))
			_, b, _ = s(nil, nil)
			So(b, ShouldResemble, []byte("o"))
			// flush for defer file close
			s(nil, nil)
		})
	})

	Convey("Should stream any number of files", t, func() {
		s := SrcStreamer([]string{
			"_test/fixtures/hello",
			"_test/fixtures/world",
		}, SrcOpts{})
		helloFi := &FileInfo{
			Name:         "hello",
			Path:         "_test/fixtures",
			OriginalName: "hello",
			OriginalPath: "_test/fixtures",
			Ctx:          map[string]interface{}{},
		}
		worldFi := &FileInfo{
			Name:         "world",
			Path:         "_test/fixtures",
			OriginalName: "world",
			OriginalPath: "_test/fixtures",
			Ctx:          map[string]interface{}{},
		}
		fi, chunk, err := s(nil, nil)
		So(err, ShouldBeNil)
		So(fi, ShouldResemble, helloFi)
		So(chunk, ShouldResemble, []byte("hello"))

		fi, chunk, err = s(nil, nil)
		So(err, ShouldBeNil)
		So(fi, ShouldResemble, helloFi)
		So(chunk, ShouldBeNil) // EOF

		fi, chunk, err = s(nil, nil)
		So(err, ShouldBeNil)
		So(fi, ShouldResemble, worldFi)
		So(chunk, ShouldResemble, []byte("world"))

		fi, chunk, err = s(nil, nil)
		So(err, ShouldBeNil)
		So(fi, ShouldResemble, worldFi)
		So(chunk, ShouldBeNil) // EOF

		fi, chunk, err = s(nil, nil)
		So(err, ShouldBeNil)
		So(fi, ShouldBeNil) // EOS
	})

	Convey("Should support globbing", t, func() {
		s := SrcStreamer([]string{"_test/fixtures/*.md"}, SrcOpts{})
		files := []string{}
		var err error
		for true {
			fi, chunk, serr := s(nil, nil)
			err = serr
			if err != nil || fi == nil {
				break
			}
			if chunk == nil {
				// Only add the file when the Streamer signals EOF
				files = append(files, fi.Name)
			}
		}
		So(err, ShouldBeNil)
		So(files, ShouldResemble, []string{"hello.md", "world.md"})
	})

	Convey("Should instantiate the Ctx map", t, func() {
		s := SrcStreamer([]string{"_test/fixtures/hello"}, SrcOpts{})
		fi, _, err := s(nil, nil)
		So(err, ShouldBeNil)
		So(fi.Ctx, ShouldNotBeNil)
	})
}

func TestDest(t *testing.T) {
	os.RemoveAll("_test/tmp/dest")

	Convey("Should create the the destination if needed", t, func() {
		s := Dest("_test/tmp/dest")
		f := &FileInfo{
			Name: "file",
			Path: ".",
		}
		c := []byte("chunk")
		s(f, c)
		s(nil, nil)
		osFi, err := os.Stat("_test/tmp/dest")
		So(err, ShouldBeNil)
		So(osFi.IsDir(), ShouldBeTrue)
	})

	os.RemoveAll("_test/tmp/path")

	Convey("Should create the path in the dest if needed", t, func() {
		s := Dest("_test/tmp")
		f := &FileInfo{
			Name: "file",
			Path: "path/foo/bar",
		}
		c := []byte("chunk")
		_, _, err := s(f, c)
		So(err, ShouldBeNil)
		osFi, err := os.Stat("_test/tmp/path/foo/bar")
		So(err, ShouldBeNil)
		So(osFi.IsDir(), ShouldBeTrue)
	})

	os.Remove("_test/tmp/file")

	Convey("Should create the file in the destination", t, func() {
		s := Dest("_test/tmp")
		f := &FileInfo{
			Name: "file",
			Path: ".",
		}
		c := []byte("foo")
		_, _, err := s(f, c)
		So(err, ShouldBeNil)
		// Signal EOF
		_, _, err = s(nil, nil)
		So(err, ShouldBeNil)
		// Test the file
		_, err = os.Stat("_test/tmp/file")
		So(err, ShouldBeNil)
	})

	os.Remove("_test/tmp/file")

	Convey("Should write incoming bytes to the given file", t, func() {
		s := Dest("_test/tmp")
		f := &FileInfo{
			Name: "file",
			Path: ".",
		}
		_, _, err := s(f, []byte("foo"))
		So(err, ShouldBeNil)
		_, _, err = s(f, []byte("bar"))
		So(err, ShouldBeNil)
		_, _, err = s(f, []byte("baz"))
		So(err, ShouldBeNil)
		_, _, err = s(nil, nil)
		So(err, ShouldBeNil)

		b, err := ioutil.ReadFile("_test/tmp/file")
		So(err, ShouldBeNil)
		So(b, ShouldResemble, []byte("foobarbaz"))
	})

	Convey("Should not allow writing outside of the destination", t, nil)
}
<commit_msg>Added Streamer test description (not implemented)<commit_after>package muta

import (
	"io/ioutil"
	"os"
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func TestSrcStreamer(t *testing.T) {
	Convey("Should pipe incoming chunks", t, func() {
		s := SrcStreamer([]string{}, SrcOpts{})
		fi := &FileInfo{}
		b := []byte("chunk")
		rfi, rb, err := s(fi, b)
		So(err, ShouldBeNil)
		So(rfi, ShouldEqual, fi)
		So(rb, ShouldResemble, b)
		s(fi, b)
	})

	Convey("Should return an error if the file cannot be found", t, func() {
		s := SrcStreamer([]string{"_test/fixtures/404"}, SrcOpts{})
		_, _, err := s(nil, nil)
		So(err, ShouldNotBeNil)
	})

	Convey("Should load the given file and", t, func() {
		Convey("Populate FileInfo with the file info", func() {
			s := SrcStreamer([]string{"_test/fixtures/hello"}, SrcOpts{})
			fi, _, err := s(nil, nil)
			So(err, ShouldBeNil)
			So(fi, ShouldResemble, &FileInfo{
				Name:         "hello",
				Path:         "_test/fixtures",
				OriginalName: "hello",
				OriginalPath: "_test/fixtures",
				Ctx:          map[string]interface{}{},
			})
			// flush for defer file close
			s(nil, nil)
		})

		Convey("Return chunks of the file", func() {
			s := SrcStreamer([]string{"_test/fixtures/hello"}, SrcOpts{
				ReadSize: 5,
			})
			_, b, err := s(nil, nil)
			So(err, ShouldBeNil)
			So(b, ShouldResemble, []byte("hello"))
			// flush for defer file close
			s(nil, nil)
		})

		Convey("Return multiple chunks of the file", func() {
			s := SrcStreamer([]string{"_test/fixtures/hello"}, SrcOpts{
				ReadSize: 3,
			})
			_, b, err := s(nil, nil)
			So(err, ShouldBeNil)
			So(b, ShouldResemble, []byte("hel"))
			_, b, err = s(nil, nil)
			So(err, ShouldBeNil)
			So(b, ShouldResemble, []byte("lo"))
			// flush for defer file close
			s(nil, nil)
		})

		Convey("Return a valid FileInfo at EOF", func() {
			s := SrcStreamer([]string{"_test/fixtures/hello"}, SrcOpts{
				ReadSize: 5,
			})
			s(nil, nil)
			fi, _, err := s(nil, nil)
			So(err, ShouldBeNil)
			So(fi, ShouldResemble, &FileInfo{
				Name:         "hello",
				Path:         "_test/fixtures",
				OriginalName: "hello",
				OriginalPath: "_test/fixtures",
				Ctx:          map[string]interface{}{},
			})
		})

		Convey("Return a nil chunk at EOF", func() {
			s := SrcStreamer([]string{"_test/fixtures/hello"}, SrcOpts{
				ReadSize: 5,
			})
			s(nil, nil)
			_, b, err := s(nil, nil)
			So(err, ShouldBeNil)
			So(b, ShouldBeNil)
		})

		Convey("Trim byte array to length of data", func() {
			s := SrcStreamer([]string{"_test/fixtures/hello"}, SrcOpts{
				ReadSize: 4,
			})
			_, b, _ := s(nil, nil)
			So(b, ShouldResemble, []byte("hell"))
			_, b, _ = s(nil, nil)
			So(b, ShouldResemble, []byte("o"))
			// flush for defer file close
			s(nil, nil)
		})
	})

	Convey("Should stream any number of files", t, func() {
		s := SrcStreamer([]string{
			"_test/fixtures/hello",
			"_test/fixtures/world",
		}, SrcOpts{})
		helloFi := &FileInfo{
			Name:         "hello",
			Path:         "_test/fixtures",
			OriginalName: "hello",
			OriginalPath: "_test/fixtures",
			Ctx:          map[string]interface{}{},
		}
		worldFi := &FileInfo{
			Name:         "world",
			Path:         "_test/fixtures",
			OriginalName: "world",
			OriginalPath: "_test/fixtures",
			Ctx:          map[string]interface{}{},
		}
		fi, chunk, err := s(nil, nil)
		So(err, ShouldBeNil)
		So(fi, ShouldResemble, helloFi)
		So(chunk, ShouldResemble, []byte("hello"))

		fi, chunk, err = s(nil, nil)
		So(err, ShouldBeNil)
		So(fi, ShouldResemble, helloFi)
		So(chunk, ShouldBeNil) // EOF

		fi, chunk, err = s(nil, nil)
		So(err, ShouldBeNil)
		So(fi, ShouldResemble, worldFi)
		So(chunk, ShouldResemble, []byte("world"))

		fi, chunk, err = s(nil, nil)
		So(err, ShouldBeNil)
		So(fi, ShouldResemble, worldFi)
		So(chunk, ShouldBeNil) // EOF

		fi, chunk, err = s(nil, nil)
		So(err, ShouldBeNil)
		So(fi, ShouldBeNil) // EOS
	})

	Convey("Should support globbing", t, func() {
		s := SrcStreamer([]string{"_test/fixtures/*.md"}, SrcOpts{})
		files := []string{}
		var err error
		for true {
			fi, chunk, serr := s(nil, nil)
			err = serr
			if err != nil || fi == nil {
				break
			}
			if chunk == nil {
				// Only add the file when the Streamer signals EOF
				files = append(files, fi.Name)
			}
		}
		So(err, ShouldBeNil)
		So(files, ShouldResemble, []string{"hello.md", "world.md"})
	})

	Convey("Should instantiate the Ctx map", t, func() {
		s := SrcStreamer([]string{"_test/fixtures/hello"}, SrcOpts{})
		fi, _, err := s(nil, nil)
		So(err, ShouldBeNil)
		So(fi.Ctx, ShouldNotBeNil)
	})
}

func TestDest(t *testing.T) {
	os.RemoveAll("_test/tmp/dest")

	Convey("Should create the the destination if needed", t, func() {
		s := Dest("_test/tmp/dest")
		f := &FileInfo{
			Name: "file",
			Path: ".",
		}
		c := []byte("chunk")
		s(f, c)
		s(nil, nil)
		osFi, err := os.Stat("_test/tmp/dest")
		So(err, ShouldBeNil)
		So(osFi.IsDir(), ShouldBeTrue)
	})

	os.RemoveAll("_test/tmp/path")

	Convey("Should create the path in the dest if needed", t, func() {
		s := Dest("_test/tmp")
		f := &FileInfo{
			Name: "file",
			Path: "path/foo/bar",
		}
		c := []byte("chunk")
		_, _, err := s(f, c)
		So(err, ShouldBeNil)
		osFi, err := os.Stat("_test/tmp/path/foo/bar")
		So(err, ShouldBeNil)
		So(osFi.IsDir(), ShouldBeTrue)
	})

	os.Remove("_test/tmp/file")

	Convey("Should create the file in the destination", t, func() {
		s := Dest("_test/tmp")
		f := &FileInfo{
			Name: "file",
			Path: ".",
		}
		c := []byte("foo")
		_, _, err := s(f, c)
		So(err, ShouldBeNil)
		// Signal EOF
		_, _, err = s(nil, nil)
		So(err, ShouldBeNil)
		// Test the file
		_, err = os.Stat("_test/tmp/file")
		So(err, ShouldBeNil)
	})

	os.Remove("_test/tmp/file")

	Convey("Should write incoming bytes to the given file", t, func() {
		s := Dest("_test/tmp")
		f := &FileInfo{
			Name: "file",
			Path: ".",
		}
		_, _, err := s(f, []byte("foo"))
		So(err, ShouldBeNil)
		_, _, err = s(f, []byte("bar"))
		So(err, ShouldBeNil)
		_, _, err = s(f, []byte("baz"))
		So(err, ShouldBeNil)
		_, _, err = s(nil, nil)
		So(err, ShouldBeNil)

		b, err := ioutil.ReadFile("_test/tmp/file")
		So(err, ShouldBeNil)
		So(b, ShouldResemble, []byte("foobarbaz"))
	})

	Convey("Should not allow writing outside of the destination", t, nil)

	Convey("Should write to the given file even if the filename "+
		"changes after opening the writer", t, nil)
}
<|endoftext|>


<commit_before>package misc

import (
	"fmt"
	"math"
	"strconv"
	"strings"
)

type EpisodeContainer interface {
	// Returns true if this EpisodeContainer is equivalent or a superset of the given EpisodeContainer
	ContainsEpisodes(EpisodeContainer) bool
	// Returns a channel meant for iterating with for/range.
	// Sends all contained episodes in order.
	Episodes() chan Episode
}

type Formatter interface {
	// Returns a string where the number portion is 0-padded to fit 'width' digits
	Format(width int) string

	// Returns a string where the number portion is 0-padded to be the same length
	// as max.
	FormatLog(max int) string
}

type EpisodeType int

const (
	EpisodeTypeRegular = EpisodeType(1 + iota)
	EpisodeTypeSpecial // "S" episode
	EpisodeTypeCredits // "C" episode
	EpisodeTypeTrailer // "T" episode
	EpisodeTypeParody  // "P" episode
	EpisodeTypeOther   // "O" episode
)

func parseEpisodeType(typ string) EpisodeType {
	switch typ {
	case "":
		return EpisodeTypeRegular
	case "S":
		return EpisodeTypeSpecial
	case "C":
		return EpisodeTypeCredits
	case "T":
		return EpisodeTypeTrailer
	case "P":
		return EpisodeTypeParody
	case "O":
		return EpisodeTypeOther
	}
	return 0
}

func (et EpisodeType) String() string {
	switch et {
	case EpisodeTypeRegular:
		return ""
	case EpisodeTypeSpecial:
		return "S"
	case EpisodeTypeCredits:
		return "C"
	case EpisodeTypeTrailer:
		return "T"
	case EpisodeTypeParody:
		return "P"
	case EpisodeTypeOther:
		return "O"
	default:
		return "!"
	}
}

// An episode (duh).
type Episode struct {
	Type   EpisodeType
	Number int
	Part   int
	Parts  int
}

// returns how many digits are needed to represent this int
func scale(i int) int {
	return 1 + int(math.Floor(math.Log10(float64(i))))
}

// Converts the Episode into AniDB API episode format.
func (ep *Episode) String() string {
	return ep.Format(1)
}

// returns how many digits are needed to represent this episode
func (ep *Episode) scale() int {
	if ep == nil {
		return 1
	}
	return scale(ep.Number)
}

func (ep *Episode) Episodes() chan Episode {
	ch := make(chan Episode, 1)
	if ep != nil {
		ch <- *ep
	}
	close(ch)
	return ch
}

// Returns true if ec is an Episode and is identical to this episode,
// or if ec is a single episode EpisodeRange / EpisodeList that
// contain only this episode.
func (ep *Episode) ContainsEpisodes(ec EpisodeContainer) bool {
	switch e := ec.(type) {
	case *Episode:
		if ep == nil {
			return false
		}
		basic := ep.Type == e.Type && ep.Number == e.Number
		if ep.Part < 0 { // a whole episode contains any partial episodes
			return basic
		}
		return basic && ep.Part == e.Part
	case *EpisodeRange:
	case *EpisodeList:
		return EpisodeList{&EpisodeRange{Type: ep.Type, Start: ep, End: ep}}.ContainsEpisodes(ep)
	default:
	}
	return false
}

func (ep *Episode) Format(width int) string {
	if ep.Part < 0 { // whole episode
		return fmt.Sprintf("%s%0"+strconv.Itoa(width)+"d", ep.Type, ep.Number)
	}
	if ep.Parts != 0 { // part X of Y
		frac := float64(ep.Number) + float64(ep.Part)/float64(ep.Parts)

		return fmt.Sprintf("%s%0"+strconv.Itoa(width)+".2f", ep.Type, frac)
	}
	// part N
	return fmt.Sprintf("%s%0"+strconv.Itoa(width)+"d.%d", ep.Type, ep.Number, ep.Part)
}

func (ep *Episode) FormatLog(max int) string {
	return ep.Format(scale(max))
}

func (ep *Episode) IncPart() {
	if ep.Parts > 0 && ep.Part == ep.Parts-1 {
		ep.IncNumber()
	} else {
		ep.Part++
	}
}

func (ep *Episode) IncNumber() {
	ep.Part = -1
	ep.Parts = 0
	ep.Number++
}

func (ep *Episode) DecPart() {
	if ep.Part > 0 {
		ep.Part--
	} else {
		ep.DecNumber()
	}
}

func (ep *Episode) DecNumber() {
	ep.Part = -1
	ep.Parts = 0
	ep.Number--
}

// Parses a string in the usual AniDB API episode format and converts into
// an Episode.
func ParseEpisode(s string) *Episode {
	p := int64(-1)

	parts := strings.Split(s, ".")
	switch len(parts) {
	case 1: // no worries
	case 2:
		s = parts[0]
		p, _ = strconv.ParseInt(parts[1], 10, 32)
	default: // too many dots
		return nil
	}

	if no, err := strconv.ParseInt(s, 10, 32); err == nil {
		return &Episode{Type: EpisodeTypeRegular, Number: int(no), Part: int(p)}
	} else if len(s) < 1 {
		// s too short
	} else if no, err = strconv.ParseInt(s[1:], 10, 30); err == nil {
		return &Episode{Type: parseEpisodeType(s[:1]), Number: int(no), Part: int(p)}
	}
	return nil
}
<commit_msg>misc: Make String() and Format() not pointer methods<commit_after>package misc

import (
	"fmt"
	"math"
	"strconv"
	"strings"
)

type EpisodeContainer interface {
	// Returns true if this EpisodeContainer is equivalent or a superset of the given EpisodeContainer
	ContainsEpisodes(EpisodeContainer) bool
	// Returns a channel meant for iterating with for/range.
	// Sends all contained episodes in order.
	Episodes() chan Episode
}

type Formatter interface {
	// Returns a string where the number portion is 0-padded to fit 'width' digits
	Format(width int) string

	// Returns a string where the number portion is 0-padded to be the same length
	// as max.
	FormatLog(max int) string
}

type EpisodeType int

const (
	EpisodeTypeRegular = EpisodeType(1 + iota)
	EpisodeTypeSpecial // "S" episode
	EpisodeTypeCredits // "C" episode
	EpisodeTypeTrailer // "T" episode
	EpisodeTypeParody  // "P" episode
	EpisodeTypeOther   // "O" episode
)

func parseEpisodeType(typ string) EpisodeType {
	switch typ {
	case "":
		return EpisodeTypeRegular
	case "S":
		return EpisodeTypeSpecial
	case "C":
		return EpisodeTypeCredits
	case "T":
		return EpisodeTypeTrailer
	case "P":
		return EpisodeTypeParody
	case "O":
		return EpisodeTypeOther
	}
	return 0
}

func (et EpisodeType) String() string {
	switch et {
	case EpisodeTypeRegular:
		return ""
	case EpisodeTypeSpecial:
		return "S"
	case EpisodeTypeCredits:
		return "C"
	case EpisodeTypeTrailer:
		return "T"
	case EpisodeTypeParody:
		return "P"
	case EpisodeTypeOther:
		return "O"
	default:
		return "!"
	}
}

// An episode (duh).
type Episode struct {
	Type   EpisodeType
	Number int
	Part   int
	Parts  int
}

// returns how many digits are needed to represent this int
func scale(i int) int {
	return 1 + int(math.Floor(math.Log10(float64(i))))
}

// Converts the Episode into AniDB API episode format.
func (ep Episode) String() string {
	return ep.Format(1)
}

// returns how many digits are needed to represent this episode
func (ep *Episode) scale() int {
	if ep == nil {
		return 1
	}
	return scale(ep.Number)
}

func (ep *Episode) Episodes() chan Episode {
	ch := make(chan Episode, 1)
	if ep != nil {
		ch <- *ep
	}
	close(ch)
	return ch
}

// Returns true if ec is an Episode and is identical to this episode,
// or if ec is a single episode EpisodeRange / EpisodeList that
// contain only this episode.
func (ep *Episode) ContainsEpisodes(ec EpisodeContainer) bool {
	switch e := ec.(type) {
	case *Episode:
		if ep == nil {
			return false
		}
		basic := ep.Type == e.Type && ep.Number == e.Number
		if ep.Part < 0 { // a whole episode contains any partial episodes
			return basic
		}
		return basic && ep.Part == e.Part
	case *EpisodeRange:
	case *EpisodeList:
		return EpisodeList{&EpisodeRange{Type: ep.Type, Start: ep, End: ep}}.ContainsEpisodes(ep)
	default:
	}
	return false
}

func (ep Episode) Format(width int) string {
	if ep.Part < 0 { // whole episode
		return fmt.Sprintf("%s%0"+strconv.Itoa(width)+"d", ep.Type, ep.Number)
	}
	if ep.Parts != 0 { // part X of Y
		frac := float64(ep.Number) + float64(ep.Part)/float64(ep.Parts)

		return fmt.Sprintf("%s%0"+strconv.Itoa(width)+".2f", ep.Type, frac)
	}
	// part N
	return fmt.Sprintf("%s%0"+strconv.Itoa(width)+"d.%d", ep.Type, ep.Number, ep.Part)
}

func (ep *Episode) FormatLog(max int) string {
	return ep.Format(scale(max))
}

func (ep *Episode) IncPart() {
	if ep.Parts > 0 && ep.Part == ep.Parts-1 {
		ep.IncNumber()
	} else {
		ep.Part++
	}
}

func (ep *Episode) IncNumber() {
	ep.Part = -1
	ep.Parts = 0
	ep.Number++
}

func (ep *Episode) DecPart() {
	if ep.Part > 0 {
		ep.Part--
	} else {
		ep.DecNumber()
	}
}

func (ep *Episode) DecNumber() {
	ep.Part = -1
	ep.Parts = 0
	ep.Number--
}

// Parses a string in the usual AniDB API episode format and converts into
// an Episode.
func ParseEpisode(s string) *Episode {
	p := int64(-1)

	parts := strings.Split(s, ".")
	switch len(parts) {
	case 1: // no worries
	case 2:
		s = parts[0]
		p, _ = strconv.ParseInt(parts[1], 10, 32)
	default: // too many dots
		return nil
	}

	if no, err := strconv.ParseInt(s, 10, 32); err == nil {
		return &Episode{Type: EpisodeTypeRegular, Number: int(no), Part: int(p)}
	} else if len(s) < 1 {
		// s too short
	} else if no, err = strconv.ParseInt(s[1:], 10, 30); err == nil {
		return &Episode{Type: parseEpisodeType(s[:1]), Number: int(no), Part: int(p)}
	}
	return nil
}
<|endoftext|>


<commit_before>package tracing

import (
	"fmt"
	"io"
	"net/http"

	"github.com/containous/traefik/log"
	"github.com/containous/traefik/middlewares/tracing/jaeger"
	"github.com/containous/traefik/middlewares/tracing/zipkin"
	"github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/ext"
)

// Tracing middleware
type Tracing struct {
	Backend     string         `description:"Selects the tracking backend ('jaeger','zipkin')." export:"true"`
	ServiceName string         `description:"Set the name for this service" export:"true"`
	Jaeger      *jaeger.Config `description:"Settings for jaeger"`
	Zipkin      *zipkin.Config `description:"Settings for zipkin"`

	opentracing.Tracer
	closer io.Closer
}

// Backend describes things we can use to setup tracing
type Backend interface {
	Setup(serviceName string) (opentracing.Tracer, io.Closer, error)
}

// Setup Tracing middleware
func (t *Tracing) Setup() {
	var err error

	switch t.Backend {
	case jaeger.Name:
		t.Tracer, t.closer, err = t.Jaeger.Setup(t.ServiceName)
	case zipkin.Name:
		t.Tracer, t.closer, err = t.Zipkin.Setup(t.ServiceName)
	default:
		log.Warnf("Unknown tracer %q", t.Backend)
		return
	}

	if err != nil {
		log.Warnf("Could not initialize %s tracing: %v", t.Backend, err)
		return
	}

	return
}

// IsEnabled determines if tracing was successfully activated
func (t *Tracing) IsEnabled() bool {
	if t == nil || t.Tracer == nil {
		return false
	}
	return true
}

// Close tracer
func (t *Tracing) Close() {
	if t.closer != nil {
		t.closer.Close()
	}
}

// LogRequest used to create span tags from the request
func LogRequest(span opentracing.Span, r *http.Request) {
	if span != nil && r != nil {
		ext.HTTPMethod.Set(span, r.Method)
		ext.HTTPUrl.Set(span, r.URL.String())
		span.SetTag("http.host", r.Host)
	}
}

// LogResponseCode used to log response code in span
func LogResponseCode(span opentracing.Span, code int) {
	if span != nil {
		ext.HTTPStatusCode.Set(span, uint16(code))
		if code >= 400 {
			ext.Error.Set(span, true)
		}
	}
}

// GetSpan used to retrieve span from request context
func GetSpan(r *http.Request) opentracing.Span {
	return opentracing.SpanFromContext(r.Context())
}

// InjectRequestHeaders used to inject OpenTracing headers into the request
func InjectRequestHeaders(r *http.Request) {
	if span := GetSpan(r); span != nil {
		opentracing.GlobalTracer().Inject(
			span.Context(),
			opentracing.HTTPHeaders,
			opentracing.HTTPHeadersCarrier(r.Header))
	}
}

// LogEventf logs an event to the span in the request context.
func LogEventf(r *http.Request, format string, args ...interface{}) {
	if span := GetSpan(r); span != nil {
		span.LogKV("event", fmt.Sprintf(format, args...))
	}
}

// StartSpan starts a new span from the one in the request context
func StartSpan(r *http.Request, operationName string, spanKinClient bool, opts ...opentracing.StartSpanOption) (opentracing.Span, *http.Request, func()) {
	span, ctx := opentracing.StartSpanFromContext(r.Context(), operationName, opts...)
	if spanKinClient {
		ext.SpanKindRPCClient.Set(span)
	}
	r = r.WithContext(ctx)
	return span, r, func() {
		span.Finish()
	}
}

// SetError flags the span associated with this request as in error
func SetError(r *http.Request) {
	if span := GetSpan(r); span != nil {
		ext.Error.Set(span, true)
	}
}

// SetErrorAndDebugLog flags the span associated with this request as in error and create a debug log
func SetErrorAndDebugLog(r *http.Request, format string, args ...interface{}) {
	SetError(r)
	log.Debugf(format, args...)
	LogEventf(r, format, args...)
}

// SetErrorAndWarnLog flags the span associated with this request as in error and create a debug log
func SetErrorAndWarnLog(r *http.Request, format string, args ...interface{}) {
	SetError(r)
	log.Warnf(format, args...)
	LogEventf(r, format, args...)
}
<commit_msg>Remove unnecessary returns in tracing setup<commit_after>package tracing

import (
	"fmt"
	"io"
	"net/http"

	"github.com/containous/traefik/log"
	"github.com/containous/traefik/middlewares/tracing/jaeger"
	"github.com/containous/traefik/middlewares/tracing/zipkin"
	"github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/ext"
)

// Tracing middleware
type Tracing struct {
	Backend     string         `description:"Selects the tracking backend ('jaeger','zipkin')." export:"true"`
	ServiceName string         `description:"Set the name for this service" export:"true"`
	Jaeger      *jaeger.Config `description:"Settings for jaeger"`
	Zipkin      *zipkin.Config `description:"Settings for zipkin"`

	opentracing.Tracer
	closer io.Closer
}

// Backend describes things we can use to setup tracing
type Backend interface {
	Setup(serviceName string) (opentracing.Tracer, io.Closer, error)
}

// Setup Tracing middleware
func (t *Tracing) Setup() {
	var err error

	switch t.Backend {
	case jaeger.Name:
		t.Tracer, t.closer, err = t.Jaeger.Setup(t.ServiceName)
	case zipkin.Name:
		t.Tracer, t.closer, err = t.Zipkin.Setup(t.ServiceName)
	default:
		log.Warnf("Unknown tracer %q", t.Backend)
		return
	}

	if err != nil {
		log.Warnf("Could not initialize %s tracing: %v", t.Backend, err)
	}
}

// IsEnabled determines if tracing was successfully activated
func (t *Tracing) IsEnabled() bool {
	if t == nil || t.Tracer == nil {
		return false
	}
	return true
}

// Close tracer
func (t *Tracing) Close() {
	if t.closer != nil {
		t.closer.Close()
	}
}

// LogRequest used to create span tags from the request
func LogRequest(span opentracing.Span, r *http.Request) {
	if span != nil && r != nil {
		ext.HTTPMethod.Set(span, r.Method)
		ext.HTTPUrl.Set(span, r.URL.String())
		span.SetTag("http.host", r.Host)
	}
}

// LogResponseCode used to log response code in span
func LogResponseCode(span opentracing.Span, code int) {
	if span != nil {
		ext.HTTPStatusCode.Set(span, uint16(code))
		if code >= 400 {
			ext.Error.Set(span, true)
		}
	}
}

// GetSpan used to retrieve span from request context
func GetSpan(r *http.Request) opentracing.Span {
	return opentracing.SpanFromContext(r.Context())
}

// InjectRequestHeaders used to inject OpenTracing headers into the request
func InjectRequestHeaders(r *http.Request) {
	if span := GetSpan(r); span != nil {
		opentracing.GlobalTracer().Inject(
			span.Context(),
			opentracing.HTTPHeaders,
			opentracing.HTTPHeadersCarrier(r.Header))
	}
}

// LogEventf logs an event to the span in the request context.
func LogEventf(r *http.Request, format string, args ...interface{}) {
	if span := GetSpan(r); span != nil {
		span.LogKV("event", fmt.Sprintf(format, args...))
	}
}

// StartSpan starts a new span from the one in the request context
func StartSpan(r *http.Request, operationName string, spanKinClient bool, opts ...opentracing.StartSpanOption) (opentracing.Span, *http.Request, func()) {
	span, ctx := opentracing.StartSpanFromContext(r.Context(), operationName, opts...)
	if spanKinClient {
		ext.SpanKindRPCClient.Set(span)
	}
	r = r.WithContext(ctx)
	return span, r, func() {
		span.Finish()
	}
}

// SetError flags the span associated with this request as in error
func SetError(r *http.Request) {
	if span := GetSpan(r); span != nil {
		ext.Error.Set(span, true)
	}
}

// SetErrorAndDebugLog flags the span associated with this request as in error and create a debug log
func SetErrorAndDebugLog(r *http.Request, format string, args ...interface{}) {
	SetError(r)
	log.Debugf(format, args...)
	LogEventf(r, format, args...)
}

// SetErrorAndWarnLog flags the span associated with this request as in error and create a debug log
func SetErrorAndWarnLog(r *http.Request, format string, args ...interface{}) {
	SetError(r)
	log.Warnf(format, args...)
	LogEventf(r, format, args...)
}
<|endoftext|>


<commit_before>package cloudfunctions

import (
	"encoding/json"
	"fmt"
	"log"
	"math/rand"
)

// Entry defines a log entry.
type LogEntry struct {
	Message  string `json:"message"`
	Severity string `json:"severity,omitempty"`
	// Trace will be the same for one function call, you can use it for filetering in logs
	Trace  string            `json:"logging.googleapis.com/trace,omitempty"`
	Labels map[string]string `json:"logging.googleapis.com/operation,omitempty"`
	// Cloud Log Viewer allows filtering and display of this as `jsonPayload.component`.
	Component string `json:"component,omitempty"`
}

// String renders an entry structure to the JSON format expected by Cloud Logging.
func (e LogEntry) String() string {
	if e.Severity == "" {
		e.Severity = "INFO"
	}
	out, err := json.Marshal(e)
	if err != nil {
		log.Printf("json.Marshal: %v", err)
	}
	return string(out)
}

func NewLogger() *LogEntry {
	return &LogEntry{}
}
func (e *LogEntry) GenerateTraceValue(projectID, traceFunctionName string) *LogEntry {
	randomInt := rand.Int()
	e.Trace = fmt.Sprintf("projects/%s/traces/%s/%d", projectID, traceFunctionName, randomInt)
	return e
}

func (e *LogEntry) WithLabel(key, value string) *LogEntry {
	e.Labels[key] = value
	return e
}

func (e *LogEntry) WithTrace(trace string) *LogEntry {
	e.Trace = trace
	return e
}

func (e *LogEntry) WithComponent(component string) *LogEntry {
	e.Component = component
	return e
}

func (e LogEntry) LogCritical(message string) {
	e.Severity = "CRITICAL"
	e.Message = message
	log.Println(e)
	panic(message)
}

func (e LogEntry) LogError(message string) {
	e.Severity = "ERROR"
	e.Message = message
	log.Println(e)
}

func (e LogEntry) LogInfo(message string) {
	e.Severity = "INFO"
	e.Message = message
	log.Println(e)
}
<commit_msg>init LogEntry.Labels map if nil (#3997)<commit_after>package cloudfunctions

import (
	"encoding/json"
	"fmt"
	"log"
	"math/rand"
)

// Entry defines a log entry.
type LogEntry struct {
	Message  string `json:"message"`
	Severity string `json:"severity,omitempty"`
	// Trace will be the same for one function call, you can use it for filetering in logs
	Trace  string            `json:"logging.googleapis.com/trace,omitempty"`
	Labels map[string]string `json:"logging.googleapis.com/operation,omitempty"`
	// Cloud Log Viewer allows filtering and display of this as `jsonPayload.component`.
	Component string `json:"component,omitempty"`
}

// String renders an entry structure to the JSON format expected by Cloud Logging.
func (e LogEntry) String() string {
	if e.Severity == "" {
		e.Severity = "INFO"
	}
	out, err := json.Marshal(e)
	if err != nil {
		log.Printf("json.Marshal: %v", err)
	}
	return string(out)
}

func NewLogger() *LogEntry {
	return &LogEntry{}
}
func (e *LogEntry) GenerateTraceValue(projectID, traceFunctionName string) *LogEntry {
	randomInt := rand.Int()
	e.Trace = fmt.Sprintf("projects/%s/traces/%s/%d", projectID, traceFunctionName, randomInt)
	return e
}

func (e *LogEntry) WithLabel(key, value string) *LogEntry {
	if e.Labels == nil {
		e.Labels = make(map[string]string)
	}
	e.Labels[key] = value
	return e
}

func (e *LogEntry) WithTrace(trace string) *LogEntry {
	e.Trace = trace
	return e
}

func (e *LogEntry) WithComponent(component string) *LogEntry {
	e.Component = component
	return e
}

func (e LogEntry) LogCritical(message string) {
	e.Severity = "CRITICAL"
	e.Message = message
	log.Println(e)
	panic(message)
}

func (e LogEntry) LogError(message string) {
	e.Severity = "ERROR"
	e.Message = message
	log.Println(e)
}

func (e LogEntry) LogInfo(message string) {
	e.Severity = "INFO"
	e.Message = message
	log.Println(e)
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"gopkg.in/alecthomas/kingpin.v2"
	"fmt"
	"github.com/sandreas/graft/pattern"
	"github.com/sandreas/graft/file"
	"strconv"
	"regexp"
	"path"
	"strings"
	"math"
	"time"
)

var (
	app = kingpin.New("graft", "A command-line tool to locate and transfer files")
	sourcePatternParameter = app.Arg("source-pattern", "source pattern - used to locate files (e.g. src/*)").Required().String()
	destinationPatternParameter = app.Arg("destination-pattern", "destination pattern for transfer (e.g. dst/$1)").Default("").String()

	exportTo = app.Flag("export-to", "export source listing to file, one line per found item").Default("").String()
	filesFrom = app.Flag("files-from", "import source listing from file, one line per item").Default("").String()

	minAge = app.Flag("min-age", " minimum age (e.g. -2 days, -8 weeks, 2015-10-10, etc.)").Default("").String()
	maxAge = app.Flag("max-age", "maximum age (e.g. 2 days, 8 weeks, 2015-10-10, etc.)").Default("").String()

	caseSensitive = app.Flag("case-sensitive", "be case sensitive when matching files and folders").Bool()
	dryRun = app.Flag("dry-run", "dry-run / simulation mode").Bool()
	hideMatches = app.Flag("hide-matches", "hide matches in search mode ($1: ...)").Bool()
	move = app.Flag("move", "move / rename files - do not make a copy").Bool()
	quiet = app.Flag("quiet", "quiet mode - do not show any output").Bool()
	regex = app.Flag("regex", "use a real regex instead of glob patterns (e.g. src/.*\\.jpg)").Bool()
	times = app.Flag("times", "transfer source modify times to destination").Bool()
)

var dirsToRemove = make([]string, 0)

func main() {
	kingpin.MustParse(app.Parse(os.Args[1:]))
	sourcePattern := *sourcePatternParameter
	destinationPattern := *destinationPatternParameter

	patternPath, pat := pattern.ParsePathPattern(sourcePattern)
	if destinationPattern == "" {
		searchIn := patternPath
		if patternPath == "" {
			searchIn = "./"
		}

		searchFor := ""
		if pat != "" {
			searchFor = pat
		}
		prntln("search in '" + searchIn + "': " + searchFor)

	} else if (*move) {
		prntln("move: " + sourcePattern + " => " + destinationPattern)
	} else {
		prntln("copy: " + sourcePattern + " => " + destinationPattern)
	}
	prntln("")

	if ! *regex {
		pat = pattern.GlobToRegex(pat)
	}

	caseInsensitiveQualifier := "(?i)"
	if *caseSensitive {
		caseInsensitiveQualifier = ""
	}

	compiledPattern, err := pattern.CompileNormalizedPathPattern(patternPath, caseInsensitiveQualifier + pat)
	if err == nil && compiledPattern.NumSubexp() == 0 && pat != "" {
		compiledPattern, err = pattern.CompileNormalizedPathPattern(patternPath, caseInsensitiveQualifier + "(" + pat + ")")
	}

	if err != nil {
		prntln("could not compile source pattern, please use slashes to qualify paths (recognized path: " + patternPath + ", pattern" + pat + ")")
		return
	}

	var matchingPaths []string

	if *filesFrom != "" {
		if ! file.Exists(*filesFrom) {
			prntln("Could not load files from " + *filesFrom)
			return
		}
		matchingPaths, err = file.ReadAllLinesFunc(*filesFrom, file.SkipEmptyLines)
	} else {
		 //matchingPaths, err = file.WalkPathByPattern(patternPath, compiledPattern, progressHandlerWalkPathByPattern)
		matchingFiles, _ := file.WalkPathFiltered(patternPath, func(f file.File, err error)(bool) {
			if ! compiledPattern.MatchString(f.Path) {
				return false
			}

			return minAgeFilter(f) && maxAgeFilter(f)
		}, progressHandlerWalkPathByPattern)

		for _, element := range matchingFiles {
			matchingPaths = append(matchingPaths, element.Path)
		}

		if *exportTo != "" {
			exportFile(*exportTo, matchingPaths)
		}
	}

	if err != nil {
		prntln("Could not load sources path " + patternPath + ":", err.Error())
		return
	}

	if destinationPattern == "" {
		for _, element := range matchingPaths {
			findElementHandler(element, compiledPattern)
		}
		return
	}

	dstPath, dstPatt := pattern.ParsePathPattern(destinationPattern)
	var dst string
	for _, element := range matchingPaths {
		if dstPatt == "" {
			dst = pattern.NormalizeDirSep(dstPath + element[len(patternPath)+1:])
		} else {
			dst = compiledPattern.ReplaceAllString(pattern.NormalizeDirSep(element), pattern.NormalizeDirSep(destinationPattern))
		}
		transferElementHandler(element, dst)
	}

	if *move {
		for _, dirToRemove := range dirsToRemove {
			os.Remove(dirToRemove)
		}
	}
	return
}

func minAgeFilter(f file.File)(bool) {
	if *minAge == "" {
		return true
	}

	minAgeTime, err := pattern.StrToAge(*minAge, time.Now())
	if err != nil {
		return false
	}
	return minAgeTime.UnixNano() > f.ModTime().UnixNano()
}

func maxAgeFilter(f file.File)(bool) {
	if *maxAge == "" {
		return true
	}

	maxAgeTime, err := pattern.StrToAge(*maxAge, time.Now())
	if err != nil {
		return false
	}
	return maxAgeTime.UnixNano() < f.ModTime().UnixNano()
}

func progressHandlerWalkPathByPattern(entriesWalked, entriesMatched int64, finished bool) (int64) {
	var progress string;
	if entriesMatched == 0 {
		progress = fmt.Sprintf("scanning - total: %d", entriesWalked)
	} else {
		progress = fmt.Sprintf("scanning - total: %d,  matches: %d", entriesWalked, entriesMatched)
	}
	// prnt("\x0c" + progressBar)
	prnt("\r" + progress)
	if finished {
		prntln("")
		prntln("")
	}
	if(entriesWalked > 1000) {
		return 500
	}
	return 100
}

func exportFile(file string, lines []string) {
	f, err := os.Create(*exportTo)
	if err != nil {
		prntln("could not create export file " + file + ": " + err.Error())
		return;
	}
	_, err = f.WriteString(strings.Join(lines, "\n"))
	defer f.Close()
	if err != nil {
		prntln("could not write export file " + file + ": " + err.Error())
	}

}

func appendRemoveDir(dir string) {
	if (*move) {
		dirsToRemove = append(dirsToRemove, dir)
	}
}

func handleProgress(bytesTransferred, size, chunkSize int64) (int64) {

	if size <= 0 {
		return chunkSize
	}

	percent := float64(bytesTransferred) / float64(size)
	charCountWhenFullyTransmitted := 20
	progressChars := int(math.Floor(percent * float64(charCountWhenFullyTransmitted)))
	normalizedInt :=percent * 100
	progressBar := fmt.Sprintf("[%-" + strconv.Itoa(charCountWhenFullyTransmitted + 1)+ "s] %3d%%", strings.Repeat("=", progressChars) + ">", normalizedInt)

	prnt("\r" + progressBar)
	if bytesTransferred == size {
		prntln("")
	}
	// fmt.Print("\r" + progressBar)
	return chunkSize
}

func prntln(a ...interface{}) (n int, err error) {
	if ! *quiet {
		return fmt.Println(a...)
	}
	return n, err
}

func prnt(a...interface{}) (n int, err error) {
	if ! *quiet {
		return fmt.Print(a...)
	}
	return n, err
}

func findElementHandler(element string, compiledPattern *regexp.Regexp) {
	prntln(element)
	if *hideMatches {
		return
	}
	elementMatches := pattern.BuildMatchList(compiledPattern, element)
	for i := 0; i < len(elementMatches); i++ {
		prntln("    $" + strconv.Itoa(i + 1) + ": " + elementMatches[i])
	}

}

func transferElementHandler(src, dst string) {

	prntln(src + " => " + dst)

	if *dryRun {
		return
	}

	srcStat, srcErr := os.Stat(src)

	if srcErr != nil {
		prntln("could not read source: ", srcErr)
		return
	}

	dstStat, _ := os.Stat(dst)
	dstExists := file.Exists(dst)
	if srcStat.IsDir() {
		if ! dstExists {
			if os.MkdirAll(dst, srcStat.Mode()) != nil {
				prntln("Could not create destination directory")
			}
			appendRemoveDir(dst)
			fixTimes(dst, srcStat)
			return
		}

		if dstStat.IsDir() {
			appendRemoveDir(dst)
			fixTimes(dst, srcStat)
			return
		}

		prntln("destination already exists as file, source is a directory")
		return
	}

	if dstExists && dstStat.IsDir() {
		prntln("destination already exists as directory, source is a file")
		return
	}

	srcDir := path.Dir(src)
	srcDirStat, _ := os.Stat(srcDir)

	dstDir := path.Dir(dst)
	if ! file.Exists(dstDir) {
		os.MkdirAll(dstDir, srcDirStat.Mode())
	}

	if *move {
		renameErr := os.Rename(src, dst)
		if renameErr == nil {
			appendRemoveDir(srcDir)
			fixTimes(dst, srcStat)
			return
		}
		prntln("Could not rename source")
		return
	}

	srcPointer, srcPointerErr := os.Open(src)
	if srcPointerErr != nil {
		prntln("Could not open source file")
		return
	}
	dstPointer, dstPointerErr := os.OpenFile(dst, os.O_WRONLY | os.O_CREATE, srcStat.Mode())

	if dstPointerErr != nil {
		prntln("Could not create destination file", dstPointerErr.Error())
		return
	}

	file.CopyResumed(srcPointer, dstPointer, handleProgress)
	fixTimes(dst, srcStat)
}

func fixTimes(dst string, inStats os.FileInfo) {
	if *times {
		os.Chtimes(dst, inStats.ModTime(), inStats.ModTime())
	}
}<commit_msg>fixed file walker...<commit_after>package main

import (
	"os"
	"gopkg.in/alecthomas/kingpin.v2"
	"fmt"
	"github.com/sandreas/graft/pattern"
	"github.com/sandreas/graft/file"
	"strconv"
	"regexp"
	"path"
	"strings"
	"math"
	"time"
)

var (
	app = kingpin.New("graft", "A command-line tool to locate and transfer files")
	sourcePatternParameter = app.Arg("source-pattern", "source pattern - used to locate files (e.g. src/*)").Required().String()
	destinationPatternParameter = app.Arg("destination-pattern", "destination pattern for transfer (e.g. dst/$1)").Default("").String()

	exportTo = app.Flag("export-to", "export source listing to file, one line per found item").Default("").String()
	filesFrom = app.Flag("files-from", "import source listing from file, one line per item").Default("").String()

	minAge = app.Flag("min-age", " minimum age (e.g. -2 days, -8 weeks, 2015-10-10, etc.)").Default("").String()
	maxAge = app.Flag("max-age", "maximum age (e.g. 2 days, 8 weeks, 2015-10-10, etc.)").Default("").String()

	caseSensitive = app.Flag("case-sensitive", "be case sensitive when matching files and folders").Bool()
	dryRun = app.Flag("dry-run", "dry-run / simulation mode").Bool()
	hideMatches = app.Flag("hide-matches", "hide matches in search mode ($1: ...)").Bool()
	move = app.Flag("move", "move / rename files - do not make a copy").Bool()
	quiet = app.Flag("quiet", "quiet mode - do not show any output").Bool()
	regex = app.Flag("regex", "use a real regex instead of glob patterns (e.g. src/.*\\.jpg)").Bool()
	times = app.Flag("times", "transfer source modify times to destination").Bool()
)

var dirsToRemove = make([]string, 0)

func main() {
	kingpin.MustParse(app.Parse(os.Args[1:]))
	sourcePattern := *sourcePatternParameter
	destinationPattern := *destinationPatternParameter

	patternPath, pat := pattern.ParsePathPattern(sourcePattern)
	if destinationPattern == "" {
		searchIn := patternPath
		if patternPath == "" {
			searchIn = "./"
		}

		searchFor := ""
		if pat != "" {
			searchFor = pat
		}
		prntln("search in '" + searchIn + "': " + searchFor)

	} else if (*move) {
		prntln("move: " + sourcePattern + " => " + destinationPattern)
	} else {
		prntln("copy: " + sourcePattern + " => " + destinationPattern)
	}
	prntln("")

	if ! *regex {
		pat = pattern.GlobToRegex(pat)
	}

	caseInsensitiveQualifier := "(?i)"
	if *caseSensitive {
		caseInsensitiveQualifier = ""
	}

	compiledPattern, err := pattern.CompileNormalizedPathPattern(patternPath, caseInsensitiveQualifier + pat)
	if err == nil && compiledPattern.NumSubexp() == 0 && pat != "" {
		compiledPattern, err = pattern.CompileNormalizedPathPattern(patternPath, caseInsensitiveQualifier + "(" + pat + ")")
	}

	if err != nil {
		prntln("could not compile source pattern, please use slashes to qualify paths (recognized path: " + patternPath + ", pattern" + pat + ")")
		return
	}

	var matchingPaths []string

	if *filesFrom != "" {
		if ! file.Exists(*filesFrom) {
			prntln("Could not load files from " + *filesFrom)
			return
		}
		matchingPaths, err = file.ReadAllLinesFunc(*filesFrom, file.SkipEmptyLines)
	} else {
		 //matchingPaths, err = file.WalkPathByPattern(patternPath, compiledPattern, progressHandlerWalkPathByPattern)
		matchingFiles, _ := file.WalkPathFiltered(patternPath, func(f file.File, err error)(bool) {
			normalizedPath := pattern.NormalizeDirSep(f.Path)
			if ! compiledPattern.MatchString(normalizedPath) {
				return false
			}

			return minAgeFilter(f) && maxAgeFilter(f)
		}, progressHandlerWalkPathByPattern)

		for _, element := range matchingFiles {
			matchingPaths = append(matchingPaths, element.Path)
		}

		if *exportTo != "" {
			exportFile(*exportTo, matchingPaths)
		}
	}

	if err != nil {
		prntln("Could not load sources path " + patternPath + ":", err.Error())
		return
	}

	if destinationPattern == "" {
		for _, element := range matchingPaths {
			findElementHandler(element, compiledPattern)
		}
		return
	}

	dstPath, dstPatt := pattern.ParsePathPattern(destinationPattern)
	var dst string
	for _, element := range matchingPaths {
		if dstPatt == "" {
			dst = pattern.NormalizeDirSep(dstPath + element[len(patternPath)+1:])
		} else {
			dst = compiledPattern.ReplaceAllString(pattern.NormalizeDirSep(element), pattern.NormalizeDirSep(destinationPattern))
		}
		transferElementHandler(element, dst)
	}

	if *move {
		for _, dirToRemove := range dirsToRemove {
			os.Remove(dirToRemove)
		}
	}
	return
}

func minAgeFilter(f file.File)(bool) {
	if *minAge == "" {
		return true
	}

	minAgeTime, err := pattern.StrToAge(*minAge, time.Now())
	if err != nil {
		return false
	}
	return minAgeTime.UnixNano() > f.ModTime().UnixNano()
}

func maxAgeFilter(f file.File)(bool) {
	if *maxAge == "" {
		return true
	}

	maxAgeTime, err := pattern.StrToAge(*maxAge, time.Now())
	if err != nil {
		return false
	}
	return maxAgeTime.UnixNano() < f.ModTime().UnixNano()
}

func progressHandlerWalkPathByPattern(entriesWalked, entriesMatched int64, finished bool) (int64) {
	var progress string;
	if entriesMatched == 0 {
		progress = fmt.Sprintf("scanning - total: %d", entriesWalked)
	} else {
		progress = fmt.Sprintf("scanning - total: %d,  matches: %d", entriesWalked, entriesMatched)
	}
	// prnt("\x0c" + progressBar)
	prnt("\r" + progress)
	if finished {
		prntln("")
		prntln("")
	}
	if(entriesWalked > 1000) {
		return 500
	}
	return 100
}

func exportFile(file string, lines []string) {
	f, err := os.Create(*exportTo)
	if err != nil {
		prntln("could not create export file " + file + ": " + err.Error())
		return;
	}
	_, err = f.WriteString(strings.Join(lines, "\n"))
	defer f.Close()
	if err != nil {
		prntln("could not write export file " + file + ": " + err.Error())
	}

}

func appendRemoveDir(dir string) {
	if (*move) {
		dirsToRemove = append(dirsToRemove, dir)
	}
}

func handleProgress(bytesTransferred, size, chunkSize int64) (int64) {

	if size <= 0 {
		return chunkSize
	}

	percent := float64(bytesTransferred) / float64(size)
	charCountWhenFullyTransmitted := 20
	progressChars := int(math.Floor(percent * float64(charCountWhenFullyTransmitted)))
	normalizedInt :=percent * 100
	progressBar := fmt.Sprintf("[%-" + strconv.Itoa(charCountWhenFullyTransmitted + 1)+ "s] %3d%%", strings.Repeat("=", progressChars) + ">", normalizedInt)

	prnt("\r" + progressBar)
	if bytesTransferred == size {
		prntln("")
	}
	// fmt.Print("\r" + progressBar)
	return chunkSize
}

func prntln(a ...interface{}) (n int, err error) {
	if ! *quiet {
		return fmt.Println(a...)
	}
	return n, err
}

func prnt(a...interface{}) (n int, err error) {
	if ! *quiet {
		return fmt.Print(a...)
	}
	return n, err
}

func findElementHandler(element string, compiledPattern *regexp.Regexp) {
	prntln(element)
	if *hideMatches {
		return
	}
	elementMatches := pattern.BuildMatchList(compiledPattern, element)
	for i := 0; i < len(elementMatches); i++ {
		prntln("    $" + strconv.Itoa(i + 1) + ": " + elementMatches[i])
	}

}

func transferElementHandler(src, dst string) {

	prntln(src + " => " + dst)

	if *dryRun {
		return
	}

	srcStat, srcErr := os.Stat(src)

	if srcErr != nil {
		prntln("could not read source: ", srcErr)
		return
	}

	dstStat, _ := os.Stat(dst)
	dstExists := file.Exists(dst)
	if srcStat.IsDir() {
		if ! dstExists {
			if os.MkdirAll(dst, srcStat.Mode()) != nil {
				prntln("Could not create destination directory")
			}
			appendRemoveDir(dst)
			fixTimes(dst, srcStat)
			return
		}

		if dstStat.IsDir() {
			appendRemoveDir(dst)
			fixTimes(dst, srcStat)
			return
		}

		prntln("destination already exists as file, source is a directory")
		return
	}

	if dstExists && dstStat.IsDir() {
		prntln("destination already exists as directory, source is a file")
		return
	}

	srcDir := path.Dir(src)
	srcDirStat, _ := os.Stat(srcDir)

	dstDir := path.Dir(dst)
	if ! file.Exists(dstDir) {
		os.MkdirAll(dstDir, srcDirStat.Mode())
	}

	if *move {
		renameErr := os.Rename(src, dst)
		if renameErr == nil {
			appendRemoveDir(srcDir)
			fixTimes(dst, srcStat)
			return
		}
		prntln("Could not rename source")
		return
	}

	srcPointer, srcPointerErr := os.Open(src)
	if srcPointerErr != nil {
		prntln("Could not open source file")
		return
	}
	dstPointer, dstPointerErr := os.OpenFile(dst, os.O_WRONLY | os.O_CREATE, srcStat.Mode())

	if dstPointerErr != nil {
		prntln("Could not create destination file", dstPointerErr.Error())
		return
	}

	file.CopyResumed(srcPointer, dstPointer, handleProgress)
	fixTimes(dst, srcStat)
}

func fixTimes(dst string, inStats os.FileInfo) {
	if *times {
		os.Chtimes(dst, inStats.ModTime(), inStats.ModTime())
	}
}<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"go/build"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"code.google.com/p/go.tools/go/loader"
	"code.google.com/p/go.tools/godoc/vfs"

	"sourcegraph.com/sourcegraph/srclib-go/gog"
	"sourcegraph.com/sourcegraph/srclib-go/gog/definfo"
	defpkg "sourcegraph.com/sourcegraph/srclib-go/golang_def"
	"sourcegraph.com/sourcegraph/srclib/graph"
	"sourcegraph.com/sourcegraph/srclib/grapher"
	"sourcegraph.com/sourcegraph/srclib/repo"
	"sourcegraph.com/sourcegraph/srclib/unit"
)

func init() {
	_, err := parser.AddCommand("graph",
		"graph a Go package",
		"Graph a Go package, producing all defs, refs, and docs.",
		&graphCmd,
	)
	if err != nil {
		log.Fatal(err)
	}
}

type GraphCmd struct{}

var graphCmd GraphCmd

func (c *GraphCmd) Execute(args []string) error {
	var unit *unit.SourceUnit
	if err := json.NewDecoder(os.Stdin).Decode(&unit); err != nil {
		return err
	}
	if err := os.Stdin.Close(); err != nil {
		return err
	}

	if err := unmarshalTypedConfig(unit.Config); err != nil {
		return err
	}
	if err := config.apply(); err != nil {
		return err
	}

	if os.Getenv("IN_DOCKER_CONTAINER") != "" {
		buildPkg, err := UnitDataAsBuildPackage(unit)
		if err != nil {
			return err
		}

		// Make a new GOPATH.
		buildContext.GOPATH = "/tmp/gopath"

		// Set up GOPATH so it has this repo.
		log.Printf("Setting up a new GOPATH at %s", buildContext.GOPATH)
		dir := filepath.Join(buildContext.GOPATH, "src", string(unit.Repo))
		if err := os.MkdirAll(filepath.Dir(dir), 0700); err != nil {
			return err
		}
		log.Printf("Creating symlink to oldname %q at newname %q.", cwd, dir)
		if err := os.Symlink(cwd, dir); err != nil {
			return err
		}

		log.Printf("Changing directory to %q.", dir)
		if err := os.Chdir(dir); err != nil {
			return err
		}
		dockerCWD = cwd

		if config.GOROOT == "" {
			cwd = dir
		}

		// Get and install deps. (Only deps not in this repo; if we call `go
		// get` on this repo, we will either try to check out a different
		// version or fail with 'stale checkout?' because the .dockerignore
		// doesn't copy the .git dir.)
		var externalDeps []string
		for _, dep := range unit.Dependencies {
			importPath := dep.(string)
			if !strings.HasPrefix(importPath, string(unit.Repo)) && importPath != "C" {
				externalDeps = append(externalDeps, importPath)
			}
		}
		cmd := exec.Command("go", "get", "-x", "-d", "-t", "-v", "./"+buildPkg.Dir)
		cmd.Args = append(cmd.Args, externalDeps...)
		cmd.Env = config.env()
		cmd.Stdout, cmd.Stderr = os.Stderr, os.Stderr
		log.Printf("Downloading import dependencies: %v (env vars: %v).", cmd.Args, cmd.Env)
		if err := cmd.Run(); err != nil {
			return err
		}
		log.Printf("Finished downloading dependencies.")
	}

	out, err := Graph(unit)
	if err != nil {
		return err
	}

	// Make paths relative to repo.
	for _, gs := range out.Defs {
		if gs.File == "" {
			log.Printf("no file %+v", gs)
		}
		gs.File = relPath(cwd, gs.File)
	}
	for _, gr := range out.Refs {
		gr.File = relPath(cwd, gr.File)
	}
	for _, gd := range out.Docs {
		if gd.File != "" {
			gd.File = relPath(cwd, gd.File)
		}
	}

	if err := json.NewEncoder(os.Stdout).Encode(out); err != nil {
		return err
	}
	return nil
}

func relPath(base, path string) string {
	rp, err := filepath.Rel(base, path)
	if err != nil {
		log.Fatalf("Failed to make path %q relative to %q: %s", path, base, err)
	}

	// TODO(sqs): hack
	if strings.HasPrefix(rp, "../../../") && dockerCWD != "" {
		rp, err = filepath.Rel(dockerCWD, path)
		if err != nil {
			log.Fatalf("Failed to make path %q relative to %q: %s", path, cwd, err)
		}
	}

	return rp
}

func Graph(unit *unit.SourceUnit) (*grapher.Output, error) {
	pkg, err := UnitDataAsBuildPackage(unit)
	if err != nil {
		return nil, err
	}

	o, err := doGraph(pkg.ImportPath)
	if err != nil {
		return nil, err
	}

	o2 := grapher.Output{
		Defs: make([]*graph.Def, len(o.Defs)),
		Refs: make([]*graph.Ref, len(o.Refs)),
		Docs: make([]*graph.Doc, len(o.Docs)),
	}

	uri := string(unit.Repo)

	for i, gs := range o.Defs {
		o2.Defs[i], err = convertGoDef(gs, uri)
		if err != nil {
			return nil, err
		}
	}
	for i, gr := range o.Refs {
		o2.Refs[i], err = convertGoRef(gr, uri)
		if err != nil {
			return nil, err
		}
	}
	for i, gd := range o.Docs {
		o2.Docs[i], err = convertGoDoc(gd, uri)
		if err != nil {
			return nil, err
		}
	}

	return &o2, nil
}

func convertGoDef(gs *gog.Def, repoURI string) (*graph.Def, error) {
	resolvedTarget, err := ResolveDep(gs.DefKey.PackageImportPath, repoURI)
	if err != nil {
		return nil, err
	}
	path := graph.DefPath(pathOrDot(strings.Join(gs.Path, "/")))
	treePath := treePath(string(path))
	if !treePath.IsValid() {
		return nil, fmt.Errorf("'%s' is not a valid tree-path", treePath)
	}

	def := &graph.Def{
		DefKey: graph.DefKey{
			Unit:     resolvedTarget.ToUnit,
			UnitType: resolvedTarget.ToUnitType,
			Path:     path,
		},
		TreePath: treePath,

		Name: gs.Name,
		Kind: graph.DefKind(definfo.GeneralKindMap[gs.Kind]),

		File:     gs.File,
		DefStart: gs.DeclSpan[0],
		DefEnd:   gs.DeclSpan[1],

		Exported: gs.DefInfo.Exported,
		Test:     strings.HasSuffix(gs.File, "_test.go"),
	}

	d := defpkg.DefData{
		PackageImportPath: gs.DefKey.PackageImportPath,
		DefInfo:           gs.DefInfo,
	}
	def.Data, err = json.Marshal(d)
	if err != nil {
		return nil, err
	}

	if def.Kind == "func" {
		def.Callable = true
	}

	return def, nil
}

func convertGoRef(gr *gog.Ref, repoURI string) (*graph.Ref, error) {
	resolvedTarget, err := ResolveDep(gr.Def.PackageImportPath, repoURI)
	if err != nil {
		return nil, err
	}
	if resolvedTarget == nil {
		return nil, nil
	}

	return &graph.Ref{
		DefRepo:     uriOrEmpty(resolvedTarget.ToRepoCloneURL),
		DefPath:     graph.DefPath(pathOrDot(strings.Join(gr.Def.Path, "/"))),
		DefUnit:     resolvedTarget.ToUnit,
		DefUnitType: resolvedTarget.ToUnitType,
		Def:         gr.IsDef,
		File:        gr.File,
		Start:       gr.Span[0],
		End:         gr.Span[1],
	}, nil
}

func convertGoDoc(gd *gog.Doc, repoURI string) (*graph.Doc, error) {
	resolvedTarget, err := ResolveDep(gd.PackageImportPath, repoURI)
	if err != nil {
		return nil, err
	}
	return &graph.Doc{
		DefKey: graph.DefKey{
			Path:     graph.DefPath(pathOrDot(strings.Join(gd.Path, "/"))),
			Unit:     resolvedTarget.ToUnit,
			UnitType: resolvedTarget.ToUnitType,
		},
		Format: gd.Format,
		Data:   gd.Data,
		File:   gd.File,
		Start:  gd.Span[0],
		End:    gd.Span[1],
	}, nil
}

func uriOrEmpty(cloneURL string) repo.URI {
	if cloneURL == "" {
		return ""
	}
	return repo.MakeURI(cloneURL)
}

func pathOrDot(path string) string {
	if path == "" {
		return "."
	}
	return path
}

func treePath(path string) graph.TreePath {
	if path == "" || path == "." {
		return graph.TreePath(".")
	}
	return graph.TreePath(fmt.Sprintf("./%s", path))
}

func doGraph(importPath string) (*gog.Output, error) {
	// If we've overridden GOROOT and we're building a package not in
	// $GOROOT/src/pkg (such as "cmd/go"), then we need to virtualize GOROOT
	// because we can't set GOPATH=GOROOT (go/build ignores GOPATH in that
	// case).
	if config.GOROOT != "" && strings.HasPrefix(importPath, "cmd/") {
		// Unset our custom GOROOT (since we're routing FS ops to it using
		// vfs) and set it as our GOPATH.
		buildContext.GOROOT = build.Default.GOROOT
		buildContext.GOPATH = config.GOROOT

		virtualCWD = build.Default.GOROOT

		ns := vfs.NameSpace{}
		ns.Bind(filepath.Join(buildContext.GOROOT, "src/pkg"), vfs.OS(filepath.Join(config.GOROOT, "src/pkg")), "/", vfs.BindBefore)
		ns.Bind("/", vfs.OS("/"), "/", vfs.BindAfter)
		buildContext.IsDir = func(path string) bool {
			fi, err := ns.Stat(path)
			return err == nil && fi.Mode().IsDir()
		}
		buildContext.HasSubdir = func(root, dir string) (rel string, ok bool) { panic("unexpected") }
		buildContext.OpenFile = func(path string) (io.ReadCloser, error) {
			f, err := ns.Open(path)
			return f, err
		}
		buildContext.ReadDir = ns.ReadDir

		// We can't compile (easily?) in these false paths, so just analyze the
		// source.
		loaderConfig.SourceImports = true
	}

	// If we're using a custom GOROOT, we need to bootstrap the installation.
	if config.GOROOT != "" && !loaderConfig.SourceImports {
		if _, err := os.Stat("src/make.bash"); err == nil {
			// TODO(sqs): in docker, we can't write to this dir, so we'll have to
			// move it elsewhere
			cmd := exec.Command("bash", "make.bash")
			cmd.Dir = filepath.Join(cwd, "src")
			cmd.Env = config.env()
			cmd.Stdout, cmd.Stderr = os.Stderr, os.Stderr
			log.Printf("Bootstrapping: %v (env vars: %v)", cmd.Args, cmd.Env)
			if err := cmd.Run(); err != nil {
				return nil, err
			}
		}
	}

	if !loaderConfig.SourceImports {
		// Install pkg.
		cmd := exec.Command("go", "install", "-x", "-v", importPath)
		cmd.Env = config.env()
		cmd.Stdout, cmd.Stderr = os.Stderr, os.Stderr
		log.Printf("Install %q: %v (env vars: %v)", importPath, cmd.Args, cmd.Env)
		if err := cmd.Run(); err != nil {
			return nil, err
		}

		log.Println("\n\n############### AFTER BUILD ###############\n\n")
		out, err := exec.Command("find", "/tmp/gopath").Output()
		log.Println(string(out))
		log.Println(err)
	}

	importUnsafe := importPath == "unsafe"

	if err := loaderConfig.ImportWithTests(importPath); err != nil {
		return nil, err
	}

	if importUnsafe {
		// Special-case "unsafe" because go/loader does not let you load it
		// directly.
		if loaderConfig.ImportPkgs == nil {
			loaderConfig.ImportPkgs = make(map[string]bool)
		}
		loaderConfig.ImportPkgs["unsafe"] = true
	}

	build.Default = *loaderConfig.Build

	prog, err := loaderConfig.Load()
	if err != nil {
		return nil, err
	}

	g := gog.New(prog)

	var pkgs []*loader.PackageInfo
	for _, pkg := range prog.Imported {
		pkgs = append(pkgs, pkg)
	}

	for _, pkg := range pkgs {
		if err := g.Graph(pkg); err != nil {
			return nil, err
		}
	}

	return &g.Output, nil
}
<commit_msg>Don't require SourceImports for cmds (since we bootstrap the GOROOT)<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"go/build"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"code.google.com/p/go.tools/go/loader"
	"code.google.com/p/go.tools/godoc/vfs"

	"sourcegraph.com/sourcegraph/srclib-go/gog"
	"sourcegraph.com/sourcegraph/srclib-go/gog/definfo"
	defpkg "sourcegraph.com/sourcegraph/srclib-go/golang_def"
	"sourcegraph.com/sourcegraph/srclib/graph"
	"sourcegraph.com/sourcegraph/srclib/grapher"
	"sourcegraph.com/sourcegraph/srclib/repo"
	"sourcegraph.com/sourcegraph/srclib/unit"
)

func init() {
	_, err := parser.AddCommand("graph",
		"graph a Go package",
		"Graph a Go package, producing all defs, refs, and docs.",
		&graphCmd,
	)
	if err != nil {
		log.Fatal(err)
	}
}

type GraphCmd struct{}

var graphCmd GraphCmd

func (c *GraphCmd) Execute(args []string) error {
	var unit *unit.SourceUnit
	if err := json.NewDecoder(os.Stdin).Decode(&unit); err != nil {
		return err
	}
	if err := os.Stdin.Close(); err != nil {
		return err
	}

	if err := unmarshalTypedConfig(unit.Config); err != nil {
		return err
	}
	if err := config.apply(); err != nil {
		return err
	}

	if os.Getenv("IN_DOCKER_CONTAINER") != "" {
		buildPkg, err := UnitDataAsBuildPackage(unit)
		if err != nil {
			return err
		}

		// Make a new GOPATH.
		buildContext.GOPATH = "/tmp/gopath"

		// Set up GOPATH so it has this repo.
		log.Printf("Setting up a new GOPATH at %s", buildContext.GOPATH)
		dir := filepath.Join(buildContext.GOPATH, "src", string(unit.Repo))
		if err := os.MkdirAll(filepath.Dir(dir), 0700); err != nil {
			return err
		}
		log.Printf("Creating symlink to oldname %q at newname %q.", cwd, dir)
		if err := os.Symlink(cwd, dir); err != nil {
			return err
		}

		log.Printf("Changing directory to %q.", dir)
		if err := os.Chdir(dir); err != nil {
			return err
		}
		dockerCWD = cwd

		if config.GOROOT == "" {
			cwd = dir
		}

		// Get and install deps. (Only deps not in this repo; if we call `go
		// get` on this repo, we will either try to check out a different
		// version or fail with 'stale checkout?' because the .dockerignore
		// doesn't copy the .git dir.)
		var externalDeps []string
		for _, dep := range unit.Dependencies {
			importPath := dep.(string)
			if !strings.HasPrefix(importPath, string(unit.Repo)) && importPath != "C" {
				externalDeps = append(externalDeps, importPath)
			}
		}
		cmd := exec.Command("go", "get", "-x", "-d", "-t", "-v", "./"+buildPkg.Dir)
		cmd.Args = append(cmd.Args, externalDeps...)
		cmd.Env = config.env()
		cmd.Stdout, cmd.Stderr = os.Stderr, os.Stderr
		log.Printf("Downloading import dependencies: %v (env vars: %v).", cmd.Args, cmd.Env)
		if err := cmd.Run(); err != nil {
			return err
		}
		log.Printf("Finished downloading dependencies.")
	}

	out, err := Graph(unit)
	if err != nil {
		return err
	}

	// Make paths relative to repo.
	for _, gs := range out.Defs {
		if gs.File == "" {
			log.Printf("no file %+v", gs)
		}
		gs.File = relPath(cwd, gs.File)
	}
	for _, gr := range out.Refs {
		gr.File = relPath(cwd, gr.File)
	}
	for _, gd := range out.Docs {
		if gd.File != "" {
			gd.File = relPath(cwd, gd.File)
		}
	}

	if err := json.NewEncoder(os.Stdout).Encode(out); err != nil {
		return err
	}
	return nil
}

func relPath(base, path string) string {
	rp, err := filepath.Rel(base, path)
	if err != nil {
		log.Fatalf("Failed to make path %q relative to %q: %s", path, base, err)
	}

	// TODO(sqs): hack
	if strings.HasPrefix(rp, "../../../") && dockerCWD != "" {
		rp, err = filepath.Rel(dockerCWD, path)
		if err != nil {
			log.Fatalf("Failed to make path %q relative to %q: %s", path, cwd, err)
		}
	}

	return rp
}

func Graph(unit *unit.SourceUnit) (*grapher.Output, error) {
	pkg, err := UnitDataAsBuildPackage(unit)
	if err != nil {
		return nil, err
	}

	o, err := doGraph(pkg.ImportPath)
	if err != nil {
		return nil, err
	}

	o2 := grapher.Output{
		Defs: make([]*graph.Def, len(o.Defs)),
		Refs: make([]*graph.Ref, len(o.Refs)),
		Docs: make([]*graph.Doc, len(o.Docs)),
	}

	uri := string(unit.Repo)

	for i, gs := range o.Defs {
		o2.Defs[i], err = convertGoDef(gs, uri)
		if err != nil {
			return nil, err
		}
	}
	for i, gr := range o.Refs {
		o2.Refs[i], err = convertGoRef(gr, uri)
		if err != nil {
			return nil, err
		}
	}
	for i, gd := range o.Docs {
		o2.Docs[i], err = convertGoDoc(gd, uri)
		if err != nil {
			return nil, err
		}
	}

	return &o2, nil
}

func convertGoDef(gs *gog.Def, repoURI string) (*graph.Def, error) {
	resolvedTarget, err := ResolveDep(gs.DefKey.PackageImportPath, repoURI)
	if err != nil {
		return nil, err
	}
	path := graph.DefPath(pathOrDot(strings.Join(gs.Path, "/")))
	treePath := treePath(string(path))
	if !treePath.IsValid() {
		return nil, fmt.Errorf("'%s' is not a valid tree-path", treePath)
	}

	def := &graph.Def{
		DefKey: graph.DefKey{
			Unit:     resolvedTarget.ToUnit,
			UnitType: resolvedTarget.ToUnitType,
			Path:     path,
		},
		TreePath: treePath,

		Name: gs.Name,
		Kind: graph.DefKind(definfo.GeneralKindMap[gs.Kind]),

		File:     gs.File,
		DefStart: gs.DeclSpan[0],
		DefEnd:   gs.DeclSpan[1],

		Exported: gs.DefInfo.Exported,
		Test:     strings.HasSuffix(gs.File, "_test.go"),
	}

	d := defpkg.DefData{
		PackageImportPath: gs.DefKey.PackageImportPath,
		DefInfo:           gs.DefInfo,
	}
	def.Data, err = json.Marshal(d)
	if err != nil {
		return nil, err
	}

	if def.Kind == "func" {
		def.Callable = true
	}

	return def, nil
}

func convertGoRef(gr *gog.Ref, repoURI string) (*graph.Ref, error) {
	resolvedTarget, err := ResolveDep(gr.Def.PackageImportPath, repoURI)
	if err != nil {
		return nil, err
	}
	if resolvedTarget == nil {
		return nil, nil
	}

	return &graph.Ref{
		DefRepo:     uriOrEmpty(resolvedTarget.ToRepoCloneURL),
		DefPath:     graph.DefPath(pathOrDot(strings.Join(gr.Def.Path, "/"))),
		DefUnit:     resolvedTarget.ToUnit,
		DefUnitType: resolvedTarget.ToUnitType,
		Def:         gr.IsDef,
		File:        gr.File,
		Start:       gr.Span[0],
		End:         gr.Span[1],
	}, nil
}

func convertGoDoc(gd *gog.Doc, repoURI string) (*graph.Doc, error) {
	resolvedTarget, err := ResolveDep(gd.PackageImportPath, repoURI)
	if err != nil {
		return nil, err
	}
	return &graph.Doc{
		DefKey: graph.DefKey{
			Path:     graph.DefPath(pathOrDot(strings.Join(gd.Path, "/"))),
			Unit:     resolvedTarget.ToUnit,
			UnitType: resolvedTarget.ToUnitType,
		},
		Format: gd.Format,
		Data:   gd.Data,
		File:   gd.File,
		Start:  gd.Span[0],
		End:    gd.Span[1],
	}, nil
}

func uriOrEmpty(cloneURL string) repo.URI {
	if cloneURL == "" {
		return ""
	}
	return repo.MakeURI(cloneURL)
}

func pathOrDot(path string) string {
	if path == "" {
		return "."
	}
	return path
}

func treePath(path string) graph.TreePath {
	if path == "" || path == "." {
		return graph.TreePath(".")
	}
	return graph.TreePath(fmt.Sprintf("./%s", path))
}

func doGraph(importPath string) (*gog.Output, error) {
	// If we've overridden GOROOT and we're building a package not in
	// $GOROOT/src/pkg (such as "cmd/go"), then we need to virtualize GOROOT
	// because we can't set GOPATH=GOROOT (go/build ignores GOPATH in that
	// case).
	if config.GOROOT != "" && strings.HasPrefix(importPath, "cmd/") {
		// Unset our custom GOROOT (since we're routing FS ops to it using
		// vfs) and set it as our GOPATH.
		buildContext.GOROOT = build.Default.GOROOT
		buildContext.GOPATH = config.GOROOT

		virtualCWD = build.Default.GOROOT

		ns := vfs.NameSpace{}
		ns.Bind(filepath.Join(buildContext.GOROOT, "src/pkg"), vfs.OS(filepath.Join(config.GOROOT, "src/pkg")), "/", vfs.BindBefore)
		ns.Bind("/", vfs.OS("/"), "/", vfs.BindAfter)
		buildContext.IsDir = func(path string) bool {
			fi, err := ns.Stat(path)
			return err == nil && fi.Mode().IsDir()
		}
		buildContext.HasSubdir = func(root, dir string) (rel string, ok bool) { panic("unexpected") }
		buildContext.OpenFile = func(path string) (io.ReadCloser, error) {
			f, err := ns.Open(path)
			return f, err
		}
		buildContext.ReadDir = ns.ReadDir
	}

	// If we're using a custom GOROOT, we need to bootstrap the installation.
	if config.GOROOT != "" && !loaderConfig.SourceImports {
		if _, err := os.Stat("src/make.bash"); err == nil {
			// TODO(sqs): in docker, we can't write to this dir, so we'll have to
			// move it elsewhere
			cmd := exec.Command("bash", "make.bash")
			cmd.Dir = filepath.Join(cwd, "src")
			cmd.Env = config.env()
			cmd.Stdout, cmd.Stderr = os.Stderr, os.Stderr
			log.Printf("Bootstrapping: %v (env vars: %v)", cmd.Args, cmd.Env)
			if err := cmd.Run(); err != nil {
				return nil, err
			}
		}
	}

	if !loaderConfig.SourceImports {
		// Install pkg.
		cmd := exec.Command("go", "install", "-x", "-v", importPath)
		cmd.Env = config.env()
		cmd.Stdout, cmd.Stderr = os.Stderr, os.Stderr
		log.Printf("Install %q: %v (env vars: %v)", importPath, cmd.Args, cmd.Env)
		if err := cmd.Run(); err != nil {
			return nil, err
		}

		log.Println("\n\n############### AFTER BUILD ###############\n\n")
		out, err := exec.Command("find", "/tmp/gopath").Output()
		log.Println(string(out))
		log.Println(err)
	}

	importUnsafe := importPath == "unsafe"

	if err := loaderConfig.ImportWithTests(importPath); err != nil {
		return nil, err
	}

	if importUnsafe {
		// Special-case "unsafe" because go/loader does not let you load it
		// directly.
		if loaderConfig.ImportPkgs == nil {
			loaderConfig.ImportPkgs = make(map[string]bool)
		}
		loaderConfig.ImportPkgs["unsafe"] = true
	}

	build.Default = *loaderConfig.Build

	prog, err := loaderConfig.Load()
	if err != nil {
		return nil, err
	}

	g := gog.New(prog)

	var pkgs []*loader.PackageInfo
	for _, pkg := range prog.Imported {
		pkgs = append(pkgs, pkg)
	}

	for _, pkg := range pkgs {
		if err := g.Graph(pkg); err != nil {
			return nil, err
		}
	}

	return &g.Output, nil
}
<|endoftext|>


<commit_before>package consultant_test

import (
	"testing"

	"github.com/myENA/consultant/v2"
)

func TestWatch(t *testing.T) {
	t.Run("package-funcs", func(t *testing.T) {
		errs := make(map[string]error)
		_, errs["key"] = consultant.WatchKey("key", true, "", "")
		_, errs["keyprefix"] = consultant.WatchKeyPrefix("keyprefix", true, "", "")
		_, errs["nodes"] = consultant.WatchNodes(true, "", "")
		_, errs["services-stale"] = consultant.WatchServices(true, "", "")
		_, errs["service-tag-stale"] = consultant.WatchService("service", "tag", true, true, "", "")
		_, errs["checks-service"] = consultant.WatchChecks("service", "", true, "", "")
		_, errs["checks-state"] = consultant.WatchChecks("", "pass", true, "", "")
		_, errs["event"] = consultant.WatchEvent("event", "", "")
		_, errs["connect-roots"] = consultant.WatchConnectRoots("", "")
		_, errs["connect-leaf"] = consultant.WatchConnectLeaf("service", "", "")
		_, errs["proxy-config"] = consultant.WatchAgentService("sid", "", "")

		for n, err := range errs {
			if err != nil {
				t.Logf("error creating plan %q: %s", n, err)
				t.Fail()
			}
		}
	})
}
<commit_msg>fixing test for defunct watch plan<commit_after>package consultant_test

import (
	"testing"

	"github.com/myENA/consultant/v2"
)

func TestWatch(t *testing.T) {
	t.Run("package-funcs", func(t *testing.T) {
		errs := make(map[string]error)
		_, errs["key"] = consultant.WatchKey("key", true, "", "")
		_, errs["keyprefix"] = consultant.WatchKeyPrefix("keyprefix", true, "", "")
		_, errs["nodes"] = consultant.WatchNodes(true, "", "")
		_, errs["services-stale"] = consultant.WatchServices(true, "", "")
		_, errs["service-tag-stale"] = consultant.WatchService("service", "tag", true, true, "", "")
		_, errs["checks-service"] = consultant.WatchChecks("service", "", true, "", "")
		_, errs["checks-state"] = consultant.WatchChecks("", "pass", true, "", "")
		_, errs["event"] = consultant.WatchEvent("event", "", "")
		_, errs["connect-roots"] = consultant.WatchConnectRoots("", "")
		_, errs["connect-leaf"] = consultant.WatchConnectLeaf("service", "", "")
		_, errs["agent-service"] = consultant.WatchAgentService("sid")

		for n, err := range errs {
			if err != nil {
				t.Logf("error creating plan %q: %s", n, err)
				t.Fail()
			}
		}
	})
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Your path: %s!", r.URL.Path[1:])
}

func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":8080", nil)
}
<commit_msg>Text change<commit_after>package main

import (
	"fmt"
	"net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Your path is: %s!", r.URL.Path[1:])
}

func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":8080", nil)
}
<|endoftext|>