<commit_before>package main

import(
	"code.google.com/p/go.net/websocket"
	"net/http"
	"text/template"
	"encoding/json"
	"io/ioutil"
	"fmt"
	"strings"
	"regexp"
	//"strconv"
)

const addr = ":8080"

type User struct{
	Name string
}

type CommandType int

const(
	REGISTER = iota //0
	MESSAGE			//1
	BLOGIN
	BLOGOUT
)

type Command struct{
	Type int
	Value []byte
}

type Connection struct{
	//User who sends
	Usr *User
	//websocket-connection
	Conn *websocket.Conn
	// Buffered channel of outbound messages.
	send chan *Message
}

type Message struct{
	Usr *User
	Msg []byte
}

type Server struct{
	history []*Message
	broadcast chan *Message
	register chan *Connection
	unregister chan *Connection
	registeredConnections map[*Connection]bool
}

func (s *Server)run(){
	for {
		select {
		case c := <-server.register:
			server.registeredConnections[c] = true
			c.send<-&Message{&User{"From server"}, []byte("with love")}
			jsonU, _ := json.Marshal(s.history)
			//send history to new user
			c.send<-&Message{&User{"All user"}, jsonU}
		case c := <-server.unregister:
			delete(server.registeredConnections, c)
			close(c.send)
		case m := <-server.broadcast:
			//append to history
			s.history = append(s.history, m)
			for c := range s.registeredConnections {
				select {
				case c.send <- m:
				default:
					delete(s.registeredConnections, c)
					close(c.send)
					go c.Conn.Close()
				}
			}
		}
	}
}

func (c *Connection)Read(){
	for {
		var message string
		err := websocket.Message.Receive(c.Conn, &message)
		if err != nil {
			break
		}

		fmt.Println(message)

		var cmd *Command
		var user_name string
		var found bool
		errm := json.Unmarshal([]byte(message), &cmd)
		if(errm != nil){

		}else{
			if cmd.Type == REGISTER {
				//check if user name already is taken.
				for d := range server.registeredConnections {
					if d.Usr != nil && d.Usr.Name == string(cmd.Value) {
						found = true
					}
				}
				if found {
					break
				} else {
					c.Usr = &User{Name:string(cmd.Value)}
				}
			}

			if cmd.Type == MESSAGE {
				//check if the message is a private message.
				r,_ := regexp.MatchString("@", string(cmd.Value))
				if r {
					found = false
					user_name = strings.Split(string(cmd.Value), " ")[0]
					user_name = strings.Split(user_name, "@")[1]
					for d := range server.registeredConnections {
						if d.Usr.Name == user_name {
							d.send <-&Message{c.Usr, cmd.Value}
							found = true
						}
					}
					if(found) {
						c.send <-&Message{c.Usr, cmd.Value}
					} else {
						c.send <-&Message{&User{"From server"},[]byte("user not found")}
					}
				//else send the message to everyone
				} else {
					server.broadcast<-&Message{c.Usr, cmd.Value}
				}
			}

			if cmd.Type == BLOGIN {
				server.broadcast<-&Message{c.Usr, []byte("Logged In")}
			}

			if cmd.Type == BLOGOUT {
				server.broadcast<-&Message{c.Usr, []byte("Logged Out")}
				break
			}

		}

	}
	c.Conn.Close()
}

func (c *Connection)Write(){
	for message := range c.send {
		jsonM, _ := json.Marshal(message)
		fmt.Println(string(jsonM))
		err := websocket.Message.Send(c.Conn, string(jsonM))
		if err != nil {
			break
		}
	}
}

var server = Server{
	history: make([]*Message, 0),
	broadcast: make(chan *Message),
	register: make(chan *Connection),
	unregister: make(chan *Connection),
	registeredConnections: make(map[*Connection]bool),
}

func wsHandler(ws *websocket.Conn) {
	c := &Connection{Usr: nil,send: make(chan *Message), Conn: ws}
	server.register <- c
	defer func() {server.unregister <- c}()
	go c.Write()
	c.Read()
}

//var indexTemplate = template.Must(template.ParseFiles("template/index.html"))

const staticDir = "template/"

func mainHandler(w http.ResponseWriter, r *http.Request) {
	path := staticDir+r.URL.Path[1:]

	data, err := openFile(path)
	if(err == nil){
		fmt.Println(path[len(path)-3:])
		if(path[len(path)-3:] == "css"){

			w.Header().Set("Content-Type", STYLECSS)
		}

		if(path[len(path)-2:] == "js"){

			w.Header().Set("Content-Type", JAVASCRIPT)
		}

		w.Write(data)
	}else{
		//using standard notfound impl.
		http.NotFound(w, r)
	}
}

const(
	TEXTPLAIN string = "text/plain"
	STYLECSS string = "text/css"
	JAVASCRIPT string = "application/x-javascript"
)

func openFile(path string)([]byte, error){
	data ,err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}
	return data , nil
}

func chatHandler(w http.ResponseWriter, r *http.Request){
	indexTemplate, _ := template.ParseFiles("template/chat.html")
	indexTemplate.Execute(w, r.Host)
}

func doLogin(w http.ResponseWriter, r *http.Request){
	http.Redirect(w, r, "/chat.html", http.StatusFound)
}

func loginHandler(w http.ResponseWriter, r *http.Request){
	html, err := ioutil.ReadFile("template/index.html")
	if err != nil{
		w.Write([]byte(err.Error()))
		return
	}

	w.Write(html)
}
//writes the file
func uploadHandler(w http.ResponseWriter, r *http.Request){
	file, handler, err := r.FormFile("File")

	if err == nil {
		fmt.Println(file)
	}

    data, err := ioutil.ReadAll(file)
    if err != nil {
           fmt.Println(err)
    }

    err = ioutil.WriteFile(handler.Filename, data, 0777)
    if err != nil {
           fmt.Println(err)
    }
}

func main(){
	go server.run()
	http.HandleFunc("/upload", uploadHandler)
	http.HandleFunc("/", mainHandler)
	http.HandleFunc("/index.html", loginHandler)
	http.HandleFunc("/chat.html", chatHandler)
	http.HandleFunc("/doLogin", doLogin)
	http.Handle("/ws", websocket.Handler(wsHandler))
	err := http.ListenAndServe(addr, nil)
	    if err != nil {
	        panic("ListenAndServe: " + err.Error())
	    }
}
<commit_msg>better error handling<commit_after>package main

import(
	"code.google.com/p/go.net/websocket"
	"net/http"
	"text/template"
	"encoding/json"
	"io/ioutil"
	"fmt"
	"strings"
	"regexp"
	//"strconv"
)

const addr = ":8080"

type User struct{
	Name string
}

type CommandType int

const(
	REGISTER = iota //0
	MESSAGE			//1
	BLOGIN
	BLOGOUT
)

type Command struct{
	Type int
	Value []byte
}

type Connection struct{
	//User who sends
	Usr *User
	//websocket-connection
	Conn *websocket.Conn
	// Buffered channel of outbound messages.
	send chan *Message
}

type Message struct{
	Usr *User
	Msg []byte
}

type Server struct{
	history []*Message
	broadcast chan *Message
	register chan *Connection
	unregister chan *Connection
	registeredConnections map[*Connection]bool
}

func (s *Server)run(){
	for {
		select {
		case c := <-server.register:
			server.registeredConnections[c] = true
			c.send<-&Message{&User{"From server"}, []byte("with love")}
			jsonU, _ := json.Marshal(s.history)
			//send history to new user
			c.send<-&Message{&User{"All user"}, jsonU}
		case c := <-server.unregister:
			delete(server.registeredConnections, c)
			close(c.send)
		case m := <-server.broadcast:
			//append to history
			s.history = append(s.history, m)
			for c := range s.registeredConnections {
				select {
				case c.send <- m:
				default:
					delete(s.registeredConnections, c)
					close(c.send)
					go c.Conn.Close()
				}
			}
		}
	}
}

func (c *Connection)Read(){
	for {
		var message string
		err := websocket.Message.Receive(c.Conn, &message)
		if err != nil {
			break
		}

		fmt.Println(message)

		var cmd *Command
		var user_name string
		var found bool
		errm := json.Unmarshal([]byte(message), &cmd)
		if(errm != nil){

		}else{
			if cmd.Type == REGISTER {
				//check if user name already is taken.
				for d := range server.registeredConnections {
					if d.Usr != nil && d.Usr.Name == string(cmd.Value) {
						found = true
					}
				}
				if found {
					break
				} else {
					c.Usr = &User{Name:string(cmd.Value)}
				}
			}

			if cmd.Type == MESSAGE {
				//check if the message is a private message.
				r,_ := regexp.MatchString("@", string(cmd.Value))
				if r {
					found = false
					user_name = strings.Split(string(cmd.Value), " ")[0]
					user_name = strings.Split(user_name, "@")[1]
					for d := range server.registeredConnections {
						if d.Usr.Name == user_name {
							d.send <-&Message{c.Usr, cmd.Value}
							found = true
						}
					}
					if(found) {
						c.send <-&Message{c.Usr, cmd.Value}
					} else {
						c.send <-&Message{&User{"From server"},[]byte("user not found")}
					}
				//else send the message to everyone
				} else {
					server.broadcast<-&Message{c.Usr, cmd.Value}
				}
			}

			if cmd.Type == BLOGIN {
				server.broadcast<-&Message{c.Usr, []byte("Logged In")}
			}

			if cmd.Type == BLOGOUT {
				server.broadcast<-&Message{c.Usr, []byte("Logged Out")}
				break
			}

		}

	}
	c.Conn.Close()
}

func (c *Connection)Write(){
	for message := range c.send {
		jsonM, _ := json.Marshal(message)
		fmt.Println(string(jsonM))
		err := websocket.Message.Send(c.Conn, string(jsonM))
		if err != nil {
			break
		}
	}
}

var server = Server{
	history: make([]*Message, 0),
	broadcast: make(chan *Message),
	register: make(chan *Connection),
	unregister: make(chan *Connection),
	registeredConnections: make(map[*Connection]bool),
}

func wsHandler(ws *websocket.Conn) {
	c := &Connection{Usr: nil,send: make(chan *Message), Conn: ws}
	server.register <- c
	defer func() {server.unregister <- c}()
	go c.Write()
	c.Read()
}

//var indexTemplate = template.Must(template.ParseFiles("template/index.html"))

const staticDir = "template/"

func mainHandler(w http.ResponseWriter, r *http.Request) {
	path := staticDir+r.URL.Path[1:]

	data, err := openFile(path)
	if(err == nil){
		fmt.Println(path[len(path)-3:])
		if(path[len(path)-3:] == "css"){

			w.Header().Set("Content-Type", STYLECSS)
		}

		if(path[len(path)-2:] == "js"){

			w.Header().Set("Content-Type", JAVASCRIPT)
		}

		w.Write(data)
	}else{
		//using standard notfound impl.
		http.NotFound(w, r)
	}
}

const(
	TEXTPLAIN string = "text/plain"
	STYLECSS string = "text/css"
	JAVASCRIPT string = "application/x-javascript"
)

func openFile(path string)([]byte, error){
	data ,err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}
	return data , nil
}

func chatHandler(w http.ResponseWriter, r *http.Request){
	indexTemplate, _ := template.ParseFiles("template/chat.html")
	indexTemplate.Execute(w, r.Host)
}

func doLogin(w http.ResponseWriter, r *http.Request){
	http.Redirect(w, r, "/chat.html", http.StatusFound)
}

func loginHandler(w http.ResponseWriter, r *http.Request){
	html, err := ioutil.ReadFile("template/index.html")
	if err != nil{
		w.Write([]byte(err.Error()))
		return
	}

	w.Write(html)
}
//writes the file
func uploadHandler(w http.ResponseWriter, r *http.Request){
	file, handler, err := r.FormFile("File")

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

    data, err := ioutil.ReadAll(file)
    if err != nil {
           fmt.Println(err)
    }

    err = ioutil.WriteFile(handler.Filename, data, 0777)
    if err != nil {
           fmt.Println(err)
    }
}

func main(){
	go server.run()
	http.HandleFunc("/upload", uploadHandler)
	http.HandleFunc("/", mainHandler)
	http.HandleFunc("/index.html", loginHandler)
	http.HandleFunc("/chat.html", chatHandler)
	http.HandleFunc("/doLogin", doLogin)
	http.Handle("/ws", websocket.Handler(wsHandler))
	err := http.ListenAndServe(addr, nil)
	    if err != nil {
	        panic("ListenAndServe: " + err.Error())
	    }
}
<|endoftext|>


<commit_before>package nut

import (
	"testing"
	"time"
)

var stringTests = []struct {
	in  string
	out string
	ok  bool
}{
	// @todo: tests go here
}

var intTests = []struct {
	in  string
	out int64
	ok  bool
}{
	// decimal
	{"0", 0, true},
	{"10", 10, true},
	{"123456789", 123456789, true},

	// hexadecimal
	{"0x02", 2, true},
	{"0xff", 255, true},
	{"0xc", 12, true},

	// octal
	{"010", 8, true},
	{"01234567", 342391, true},
	{"012345678", 0, false},

	// signs
	{"+0", 0, true},
	{"-0", 0, true},
	{"+10", 10, true},
	{"-0x00", 0, true},
	{"-0x10", -16, true},
	{"+01", 1, true},
	{"-010", -8, true},

	// limits
	{"9223372036854775807", 1<<63 - 1, true},
	{"9223372036854775808", 0, false},
	{"9223372036854775809", 0, false},
	{"-9223372036854775807", -(1<<63 - 1), true},
	{"-9223372036854775808", -1 << 63, true},
	{"-9223372036854775809", 0, false},

	{"0x7FFFFFFFFFFFFFFF", 1<<63 - 1, true},
	{"0X8000000000000000", 0, false},
	{"0X8000000000000001", 0, false},
	{"-0x7FFFFFFFFFFFFFFF", -(1<<63 - 1), true},
	{"-0X8000000000000000", -1 << 63, true},
	{"-0X8000000000000001", 0, false},

	{"0777777777777777777777", 1<<63 - 1, true},
	{"01000000000000000000000", 0, false},
	{"01000000000000000000001", 0, false},
	{"-0777777777777777777777", -(1<<63 - 1), true},
	{"-01000000000000000000000", -1 << 63, true},
	{"-01000000000000000000001", 0, false},

	// invalid
	{"", 0, false},
	{"abc", 0, false},
	{"100 blue", 0, false},
	{"-0-", 0, false},
	{"++0", 0, false},
}

var boolTests = []struct {
	in  string
	out bool
	ok  bool
}{
	// truthy
	{"true", true, true},
	{"yes", true, true},
	{"on", true, true},

	// falsy
	{"false", false, true},
	{"no", false, true},
	{"off", false, true},

	// invalid
	{"", false, false},
	{"y", false, false},
	{"foo", false, false},
}

var durationTests = []struct {
	in  string
	out time.Duration
	ok  bool
}{
	// simple formats
	{"0", 0, true},
	{"0s", 0, true},
	{"5s", 5 * time.Second, true},
	{"37s", 37 * time.Second, true},
	{"010s", 10 * time.Second, true},
	{"3d", 3 * 24 * time.Hour, true},

	// all units
	{"10ns", 10 * time.Nanosecond, true},
	{"10µs", 10 * time.Microsecond, true},
	{"10μs", 10 * time.Microsecond, true},
	{"10us", 10 * time.Microsecond, true},
	{"10ms", 10 * time.Millisecond, true},
	{"10s", 10 * time.Second, true},
	{"10m", 10 * time.Minute, true},
	{"10h", 10 * time.Hour, true},
	{"10d", 10 * 24 * time.Hour, true},
	{"10w", 10 * 7 * 24 * time.Hour, true},

	// mixed units
	{"1h1m1s", time.Hour + time.Minute + time.Second, true},
	{"4h30m", 4*time.Hour + 30*time.Minute, true},
	{"1s500ms", time.Second + 500*time.Millisecond, true},
	{"1w1d24h1440m", 10 * 24 * time.Hour, true},

	// allow (ignore) spaces
	{"1h 1m1s", time.Hour + time.Minute + time.Second, true},
	{"4h 30m", 4*time.Hour + 30*time.Minute, true},
	{"1s    500ms", time.Second + 500*time.Millisecond, true},
	{"1w 1d 24h 1440m", 10 * 24 * time.Hour, true},

	// disallow signs and decimal values
	{"-3h", -1, false},
	{"+5m", -1, false},
	{"300.5h", -1, false},
	{"1h 1m 1.3s", -1, false},
	{"10w -3d", -1, false},
	{"1.2d20m", -1, false},

	// various invalid formats
	{"", -1, false},
	{"1sm", -1, false},
	{"100", -1, false},
	{"1d 200", -1, false},
	{"3 4 5ms", -1, false},
}

var timeTests = []struct {
	in  string
	out *time.Time
	ok  bool
}{
	// @todo: tests go here
}

func TestParseString(t *testing.T) {
	for _, test := range stringTests {
		fail := setup(t, "parseString", test.in)
		out, ok := parseString(test.in)

		if ok != test.ok {
			if test.ok {
				fail("parsing failed unexpectedly")
			} else {
				fail("parsing should not succeed")
			}
			continue
		}

		if out != test.out {
			fail("%#v != %#v", out, test.out)
		}
	}
}

func TestParseInt(t *testing.T) {
	for _, test := range intTests {
		fail := setup(t, "parseInt", test.in)
		out, ok := parseInt(test.in)

		if ok != test.ok {
			if test.ok {
				fail("parsing failed unexpectedly")
			} else {
				fail("parsing should not succeed")
			}
			continue
		}

		if out != test.out {
			fail("%#v != %#v", out, test.out)
		}
	}
}

func TestParseBool(t *testing.T) {
	for _, test := range boolTests {
		fail := setup(t, "parseBool", test.in)
		out, ok := parseBool(test.in)

		if ok != test.ok {
			if test.ok {
				fail("parsing failed unexpectedly")
			} else {
				fail("parsing should not succeed")
			}
			continue
		}

		if out != test.out {
			fail("%#v != %#v", out, test)
		}
	}
}

func TestParseDuration(t *testing.T) {
	for _, test := range durationTests {
		fail := setup(t, "parseDuration", test.in)
		out, ok := parseDuration(test.in)

		if ok != test.ok {
			if test.ok {
				fail("parsing failed unexpectedly")
			} else {
				fail("parsing should not succeed")
			}
			continue
		}

		if out != test.out {
			fail("%s != %s", out.String(), test.out.String())
		}
	}
}

func TestParseTime(t *testing.T) {
	for _, test := range timeTests {
		fail := setup(t, "parseTime", test.in)
		out, ok := parseTime(test.in)

		if ok != test.ok {
			if test.ok {
				fail("parsing failed unexpectedly")
			} else {
				fail("parsing should not succeed")
			}
			continue
		}

		if out == nil {
			if test.out != nil {
				fail("returned nil")
			}
			continue
		}

		if !out.Equal(*test.out) {
			fail("%s != %s", out.String(), test.out.String())
		}
	}
}

// Simplify failure reporting.
type failFunc func(format string, values ...interface{})

func setup(t *testing.T, signature string, input interface{}) failFunc {
	return func(format string, values... interface{}) {
		args := append([]interface{}{signature, input}, values...)
		t.Errorf("%s(%#v): " + format + "\n", args...)
	}
}

// Convenience function for creating a `time.Time` struct of a certain value,
// then returning a pointer to it.
func moment(value string) *time.Time {
	t, err := time.Parse("2006-01-02 15:04:05 -07:00", value)
	if err != nil {
		panic(err)
	}

	return &t
}
<commit_msg>Extend duration parsing tests<commit_after>package nut

import (
	"testing"
	"time"
)

var stringTests = []struct {
	in  string
	out string
	ok  bool
}{
	// @todo: tests go here
}

var intTests = []struct {
	in  string
	out int64
	ok  bool
}{
	// decimal
	{"0", 0, true},
	{"10", 10, true},
	{"123456789", 123456789, true},

	// hexadecimal
	{"0x02", 2, true},
	{"0xff", 255, true},
	{"0xc", 12, true},

	// octal
	{"010", 8, true},
	{"01234567", 342391, true},
	{"012345678", 0, false},

	// signs
	{"+0", 0, true},
	{"-0", 0, true},
	{"+10", 10, true},
	{"-0x00", 0, true},
	{"-0x10", -16, true},
	{"+01", 1, true},
	{"-010", -8, true},

	// limits
	{"9223372036854775807", 1<<63 - 1, true},
	{"9223372036854775808", 0, false},
	{"9223372036854775809", 0, false},
	{"-9223372036854775807", -(1<<63 - 1), true},
	{"-9223372036854775808", -1 << 63, true},
	{"-9223372036854775809", 0, false},

	{"0x7FFFFFFFFFFFFFFF", 1<<63 - 1, true},
	{"0X8000000000000000", 0, false},
	{"0X8000000000000001", 0, false},
	{"-0x7FFFFFFFFFFFFFFF", -(1<<63 - 1), true},
	{"-0X8000000000000000", -1 << 63, true},
	{"-0X8000000000000001", 0, false},

	{"0777777777777777777777", 1<<63 - 1, true},
	{"01000000000000000000000", 0, false},
	{"01000000000000000000001", 0, false},
	{"-0777777777777777777777", -(1<<63 - 1), true},
	{"-01000000000000000000000", -1 << 63, true},
	{"-01000000000000000000001", 0, false},

	// invalid
	{"", 0, false},
	{"abc", 0, false},
	{"100 blue", 0, false},
	{"-0-", 0, false},
	{"++0", 0, false},
}

var boolTests = []struct {
	in  string
	out bool
	ok  bool
}{
	// truthy
	{"true", true, true},
	{"yes", true, true},
	{"on", true, true},

	// falsy
	{"false", false, true},
	{"no", false, true},
	{"off", false, true},

	// invalid
	{"", false, false},
	{"y", false, false},
	{"foo", false, false},
}

var durationTests = []struct {
	in  string
	out time.Duration
	ok  bool
}{
	// simple formats
	{"0", 0, true},
	{"0s", 0, true},
	{"5s", 5 * time.Second, true},
	{"37s", 37 * time.Second, true},
	{"010s", 10 * time.Second, true},
	{"3d", 3 * 24 * time.Hour, true},

	// all units
	{"10ns", 10 * time.Nanosecond, true},
	{"10µs", 10 * time.Microsecond, true},
	{"10μs", 10 * time.Microsecond, true},
	{"10us", 10 * time.Microsecond, true},
	{"10ms", 10 * time.Millisecond, true},
	{"10s", 10 * time.Second, true},
	{"10m", 10 * time.Minute, true},
	{"10h", 10 * time.Hour, true},
	{"10d", 10 * 24 * time.Hour, true},
	{"10w", 10 * 7 * 24 * time.Hour, true},

	// mixed units
	{"1h1m1s", time.Hour + time.Minute + time.Second, true},
	{"4h30m", 4*time.Hour + 30*time.Minute, true},
	{"1s500ms", time.Second + 500*time.Millisecond, true},
	{"1w1d24h1440m", 10 * 24 * time.Hour, true},

	// allow (ignore) spaces
	{"1h 1m1s", time.Hour + time.Minute + time.Second, true},
	{"4h 30m", 4*time.Hour + 30*time.Minute, true},
	{"1s    500ms", time.Second + 500*time.Millisecond, true},
	{"1w 1d 24h 1440m", 10 * 24 * time.Hour, true},

	// disallow signs and decimal values
	{"-3h", 0, false},
	{"+5m", 0, false},
	{"300.5h", 0, false},
	{"1h 1m 1.3s", 0, false},
	{"10w -3d", 0, false},
	{"1.2d20m", 0, false},

	// units out of order
	{"1s2m", 0, false},
	{"1200ms 3s", 0, false},
	{"4h 5d 6w 7m", 0, false},

	// other invalid formats
	{"", 0, false},
	{"1sm", 0, false},
	{"2 m 3 s", 0, false},
	{"4 d5 h", 0, false},
	{"100", 0, false},
	{"1d 200", 0, false},
	{"3 4 5ms", 0, false},
}

var timeTests = []struct {
	in  string
	out *time.Time
	ok  bool
}{
	// @todo: tests go here
}

func TestParseString(t *testing.T) {
	for _, test := range stringTests {
		fail := setup(t, "parseString", test.in)
		out, ok := parseString(test.in)

		if ok != test.ok {
			if test.ok {
				fail("parsing failed unexpectedly")
			} else {
				fail("parsing should not succeed")
			}
			continue
		}

		if out != test.out {
			fail("%#v != %#v", out, test.out)
		}
	}
}

func TestParseInt(t *testing.T) {
	for _, test := range intTests {
		fail := setup(t, "parseInt", test.in)
		out, ok := parseInt(test.in)

		if ok != test.ok {
			if test.ok {
				fail("parsing failed unexpectedly")
			} else {
				fail("parsing should not succeed")
			}
			continue
		}

		if out != test.out {
			fail("%#v != %#v", out, test.out)
		}
	}
}

func TestParseBool(t *testing.T) {
	for _, test := range boolTests {
		fail := setup(t, "parseBool", test.in)
		out, ok := parseBool(test.in)

		if ok != test.ok {
			if test.ok {
				fail("parsing failed unexpectedly")
			} else {
				fail("parsing should not succeed")
			}
			continue
		}

		if out != test.out {
			fail("%#v != %#v", out, test)
		}
	}
}

func TestParseDuration(t *testing.T) {
	for _, test := range durationTests {
		fail := setup(t, "parseDuration", test.in)
		out, ok := parseDuration(test.in)

		if ok != test.ok {
			if test.ok {
				fail("parsing failed unexpectedly")
			} else {
				fail("parsing should not succeed")
			}
			continue
		}

		if out != test.out {
			fail("%s != %s", out.String(), test.out.String())
		}
	}
}

func TestParseTime(t *testing.T) {
	for _, test := range timeTests {
		fail := setup(t, "parseTime", test.in)
		out, ok := parseTime(test.in)

		if ok != test.ok {
			if test.ok {
				fail("parsing failed unexpectedly")
			} else {
				fail("parsing should not succeed")
			}
			continue
		}

		if out == nil {
			if test.out != nil {
				fail("returned nil")
			}
			continue
		}

		if !out.Equal(*test.out) {
			fail("%s != %s", out.String(), test.out.String())
		}
	}
}

// Simplify failure reporting.
type failFunc func(format string, values ...interface{})

func setup(t *testing.T, signature string, input interface{}) failFunc {
	return func(format string, values... interface{}) {
		args := append([]interface{}{signature, input}, values...)
		t.Errorf("%s(%#v): " + format + "\n", args...)
	}
}

// Convenience function for creating a `time.Time` struct of a certain value,
// then returning a pointer to it.
func moment(value string) *time.Time {
	t, err := time.Parse("2006-01-02 15:04:05 -07:00", value)
	if err != nil {
		panic(err)
	}

	return &t
}
<|endoftext|>


<commit_before>package frame

import (
	"9fans.net/go/draw"
	"image"
)

const (
	colBack = iota
	colHigh
	colBord
	colText
	colHText
	nCol

	frtickw = 3
)

type frbox struct {
	Wid    int // in pixels
	Nrune  int
	Ptr    []byte
	Bc     rune
	Minwid byte
}

type Frame struct {
	Font         *draw.Font
	Display      *draw.Display     // on which the frame is displayed
	Background   *draw.Image       // on which the frame appears
	Cols         [nCol]*draw.Image // background and text colours
	Rect         image.Rectangle   // in which the text appears
	Entire       image.Rectangle   // size of full frame
	Scroll       func(*Frame, int) // function provided by application
	box          []*frbox
	p0, p1       uint64 // bounds of a selection
	nbox, nalloc int
	maxtab       int // max size of a tab (in pixels)
	nchars       int // number of runes in frame
	nlines       int // number of lines with text
	maxlines     int // total number of lines in frame
	lastlinefull int
	modified     bool
	tick         *draw.Image // typing tick
	tickback     *draw.Image // image under tick
	ticked       bool
	noredraw     bool
	tickscale    int // tick scaling factor
}

// NewFrame creates a new Frame with Font ft, background image b, colours cols, and
// of the size r
func NewFrame(r image.Rectangle, ft *draw.Font, b *draw.Image, cols [nCol]*draw.Image) *Frame {
	f := new(Frame)
	f.Font = ft
	f.Display = b.Display
	f.maxtab = 8 * ft.StringWidth("0")
	f.nbox = 0
	f.nalloc = 0
	f.nchars = 0
	f.nlines = 0
	f.p0 = 0
	f.p1 = 0
	f.box = nil
	f.lastlinefull = 0
	f.Cols = cols
	f.SetRects(r, b)

	if f.tick == nil && f.Cols[colBack] != nil {
		f.InitTick()
	}
	return f
}

// InitTick
func (f *Frame) InitTick() {
	var err error
	if f.Cols[colBack] == nil || f.Display == nil {
		return
	}

	f.tickscale = f.Display.ScaleSize(1)
	b := f.Display.ScreenImage
	ft := f.Font

	if f.tick != nil {
		f.tick.Free()
	}

	f.tick, err = f.Display.AllocImage(image.Rect(0, 0, f.tickscale*frtickw, ft.Height), b.Pix, false, draw.White)
	if err != nil {
		return
	}

	f.tickback, err = f.Display.AllocImage(f.tick.R, b.Pix, false, draw.White)
	if err != nil {
		f.tick.Free()
		f.tick = nil
		return
	}

	// background colour
	f.tick.Draw(f.tick.R, f.Cols[colBack], nil, image.Pt(0, 0))
	// vertical line
	f.tick.Draw(image.Rect(f.tickscale*(frtickw/2), 0, f.tickscale*(frtickw/2+1), ft.Height), f.Display.Black, nil, image.Pt(0, 0))
	// box on each end
	f.tick.Draw(image.Rect(0, 0, f.tickscale*frtickw, f.tickscale*frtickw), f.Cols[colText], nil, image.Pt(0, 0))
	f.tick.Draw(image.Rect(0, ft.Height-f.tickscale*frtickw, f.tickscale*frtickw, ft.Height), f.Cols[colText], nil, image.Pt(0, 0))
}

// SetRects
func (f *Frame) SetRects(r image.Rectangle, b *draw.Image) {
	f.Background = b
	f.Entire = r
	f.Rect = r
	f.Rect.Max.Y -= (r.Max.Y - r.Min.Y) % f.Font.Height
	f.maxlines = (r.Max.Y - r.Min.Y) / f.Font.Height
}

// Clear
func (f *Frame) Clear(freeall bool) {
	if f.nbox != 0 {
		f.delbox(0, f.nbox-1)
	}
	if f.box != nil {
		f.box = nil
	}
	if freeall {
		f.tick.Free()
		f.tickback.Free()
		f.tick = nil
		f.tickback = nil
	}
	f.box = nil
	f.ticked = false
}
<commit_msg>re-exported NumColours<commit_after>package frame

import (
	"9fans.net/go/draw"
	"image"
)

const (
	colBack = iota
	colHigh
	colBord
	colText
	colHText
	NumColours

	frtickw = 3
)

type frbox struct {
	Wid    int // in pixels
	Nrune  int
	Ptr    []byte
	Bc     rune
	Minwid byte
}

type Frame struct {
	Font         *draw.Font
	Display      *draw.Display           // on which the frame is displayed
	Background   *draw.Image             // on which the frame appears
	Cols         [NumColours]*draw.Image // background and text colours
	Rect         image.Rectangle         // in which the text appears
	Entire       image.Rectangle         // size of full frame
	Scroll       func(*Frame, int)       // function provided by application
	box          []*frbox
	p0, p1       uint64 // bounds of a selection
	nbox, nalloc int
	maxtab       int // max size of a tab (in pixels)
	nchars       int // number of runes in frame
	nlines       int // number of lines with text
	maxlines     int // total number of lines in frame
	lastlinefull int
	modified     bool
	tick         *draw.Image // typing tick
	tickback     *draw.Image // image under tick
	ticked       bool
	noredraw     bool
	tickscale    int // tick scaling factor
}

// NewFrame creates a new Frame with Font ft, background image b, colours cols, and
// of the size r
func NewFrame(r image.Rectangle, ft *draw.Font, b *draw.Image, cols [NumColours]*draw.Image) *Frame {
	f := new(Frame)
	f.Font = ft
	f.Display = b.Display
	f.maxtab = 8 * ft.StringWidth("0")
	f.nbox = 0
	f.nalloc = 0
	f.nchars = 0
	f.nlines = 0
	f.p0 = 0
	f.p1 = 0
	f.box = nil
	f.lastlinefull = 0
	f.Cols = cols
	f.SetRects(r, b)

	if f.tick == nil && f.Cols[colBack] != nil {
		f.InitTick()
	}
	return f
}

// InitTick
func (f *Frame) InitTick() {
	var err error
	if f.Cols[colBack] == nil || f.Display == nil {
		return
	}

	f.tickscale = f.Display.ScaleSize(1)
	b := f.Display.ScreenImage
	ft := f.Font

	if f.tick != nil {
		f.tick.Free()
	}

	f.tick, err = f.Display.AllocImage(image.Rect(0, 0, f.tickscale*frtickw, ft.Height), b.Pix, false, draw.White)
	if err != nil {
		return
	}

	f.tickback, err = f.Display.AllocImage(f.tick.R, b.Pix, false, draw.White)
	if err != nil {
		f.tick.Free()
		f.tick = nil
		return
	}

	// background colour
	f.tick.Draw(f.tick.R, f.Cols[colBack], nil, image.Pt(0, 0))
	// vertical line
	f.tick.Draw(image.Rect(f.tickscale*(frtickw/2), 0, f.tickscale*(frtickw/2+1), ft.Height), f.Display.Black, nil, image.Pt(0, 0))
	// box on each end
	f.tick.Draw(image.Rect(0, 0, f.tickscale*frtickw, f.tickscale*frtickw), f.Cols[colText], nil, image.Pt(0, 0))
	f.tick.Draw(image.Rect(0, ft.Height-f.tickscale*frtickw, f.tickscale*frtickw, ft.Height), f.Cols[colText], nil, image.Pt(0, 0))
}

// SetRects
func (f *Frame) SetRects(r image.Rectangle, b *draw.Image) {
	f.Background = b
	f.Entire = r
	f.Rect = r
	f.Rect.Max.Y -= (r.Max.Y - r.Min.Y) % f.Font.Height
	f.maxlines = (r.Max.Y - r.Min.Y) / f.Font.Height
}

// Clear
func (f *Frame) Clear(freeall bool) {
	if f.nbox != 0 {
		f.delbox(0, f.nbox-1)
	}
	if f.box != nil {
		f.box = nil
	}
	if freeall {
		f.tick.Free()
		f.tickback.Free()
		f.tick = nil
		f.tickback = nil
	}
	f.box = nil
	f.ticked = false
}
<|endoftext|>


<commit_before>package action

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

	"github.com/Masterminds/glide/cfg"
	"github.com/Masterminds/glide/godep"
	"github.com/Masterminds/glide/msg"
	gpath "github.com/Masterminds/glide/path"
	"github.com/Masterminds/glide/repo"
	"github.com/Masterminds/glide/util"
)

// Get fetches one or more dependencies and installs.
//
// This includes resolving dependency resolution and re-generating the lock file.
func Get(names []string, installer *repo.Installer, insecure, skipRecursive, strip, stripVendor bool) {
	base := gpath.Basepath()
	EnsureGopath()
	EnsureVendorDir()
	conf := EnsureConfig()
	glidefile, err := gpath.Glide()
	if err != nil {
		msg.Die("Could not find Glide file: %s", err)
	}

	// Add the packages to the config.
	if count, err := addPkgsToConfig(conf, names, insecure); err != nil {
		msg.Die("Failed to get new packages: %s", err)
	} else if count == 0 {
		msg.Warn("Nothing to do")
		return
	}

	// Fetch the new packages. Can't resolve versions via installer.Update if
	// get is called while the vendor/ directory is empty so we checkout
	// everything.
	installer.Checkout(conf, false)

	// Prior to resolving dependencies we need to start working with a clone
	// of the conf because we'll be making real changes to it.
	confcopy := conf.Clone()

	if !skipRecursive {
		// Get all repos and update them.
		// TODO: Can we streamline this in any way? The reason that we update all
		// of the dependencies is that we need to re-negotiate versions. For example,
		// if an existing dependency has the constraint >1.0 and this new package
		// adds the constraint <2.0, then this may re-resolve the existing dependency
		// to be between 1.0 and 2.0. But changing that dependency may then result
		// in that dependency's dependencies changing... so we sorta do the whole
		// thing to be safe.
		err = installer.Update(confcopy)
		if err != nil {
			msg.Die("Could not update packages: %s", err)
		}
	}

	// Set Reference
	if err := repo.SetReference(confcopy); err != nil {
		msg.Err("Failed to set references: %s", err)
	}

	// VendoredCleanup
	// When stripping VCS happens this will happen as well. No need for double
	// effort.
	if installer.UpdateVendored && !strip {
		repo.VendoredCleanup(confcopy)
	}

	// Write YAML
	if err := conf.WriteFile(glidefile); err != nil {
		msg.Die("Failed to write glide YAML file: %s", err)
	}
	if !skipRecursive {
		// Write lock
		if stripVendor {
			confcopy = godep.RemoveGodepSubpackages(confcopy)
		}
		writeLock(conf, confcopy, base)
	} else {
		msg.Warn("Skipping lockfile generation because full dependency tree is not being calculated")
	}

	if strip {
		msg.Info("Removing version control data from vendor directory...")
		gpath.StripVcs()
	}

	if stripVendor {
		msg.Info("Removing nested vendor and Godeps/_workspace directories...")
		err := gpath.StripVendor()
		if err != nil {
			msg.Err("Unable to strip vendor directories: %s", err)
		}
	}
}

func writeLock(conf, confcopy *cfg.Config, base string) {
	hash, err := conf.Hash()
	if err != nil {
		msg.Die("Failed to generate config hash. Unable to generate lock file.")
	}
	lock := cfg.NewLockfile(confcopy.Imports, hash)
	if err := lock.WriteFile(filepath.Join(base, gpath.LockFile)); err != nil {
		msg.Die("Failed to write glide lock file: %s", err)
	}
}

// addPkgsToConfig adds the given packages to the config file.
//
// Along the way it:
// - ensures that this package is not in the ignore list
// - checks to see if this is already in the dependency list.
// - splits version of of package name and adds the version attribute
// - separates repo from packages
// - sets up insecure repo URLs where necessary
// - generates a list of subpackages
func addPkgsToConfig(conf *cfg.Config, names []string, insecure bool) (int, error) {

	msg.Info("Preparing to install %d package.", len(names))

	numAdded := 0
	for _, name := range names {
		var version string
		parts := strings.Split(name, "#")
		if len(parts) > 1 {
			name = parts[0]
			version = parts[1]
		}

		root, subpkg := util.NormalizeName(name)
		if len(root) == 0 {
			return 0, fmt.Errorf("Package name is required for %q.", name)
		}

		if conf.HasDependency(root) {

			// Check if the subpackage is present.
			if subpkg != "" {
				dep := conf.Imports.Get(root)
				if dep.HasSubpackage(subpkg) {
					msg.Warn("Package %q is already in glide.yaml. Skipping", name)
				} else {
					dep.Subpackages = append(dep.Subpackages, subpkg)
					msg.Info("Adding sub-package %s to existing import %s", subpkg, root)
					numAdded++
				}
			} else {
				msg.Warn("Package %q is already in glide.yaml. Skipping", root)
			}
			continue
		}

		if conf.HasIgnore(root) {
			msg.Warn("Package %q is set to be ignored in glide.yaml. Skipping", root)
			continue
		}

		dep := &cfg.Dependency{
			Name: root,
		}

		if version != "" {
			dep.Reference = version
		}

		// When retriving from an insecure location set the repo to the
		// insecure location.
		if insecure {
			dep.Repository = "http://" + root
		}

		if len(subpkg) > 0 {
			dep.Subpackages = []string{subpkg}
		}

		if dep.Reference != "" {
			msg.Info("Importing %s with the version %s", dep.Name, dep.Reference)
		} else {
			msg.Info("Importing %s", dep.Name)
		}

		conf.Imports = append(conf.Imports, dep)
		numAdded++
	}
	return numAdded, nil
}
<commit_msg>Fixes #379: Failed get was writing glide.yaml and glide.lock files<commit_after>package action

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

	"github.com/Masterminds/glide/cfg"
	"github.com/Masterminds/glide/godep"
	"github.com/Masterminds/glide/msg"
	gpath "github.com/Masterminds/glide/path"
	"github.com/Masterminds/glide/repo"
	"github.com/Masterminds/glide/util"
)

// Get fetches one or more dependencies and installs.
//
// This includes resolving dependency resolution and re-generating the lock file.
func Get(names []string, installer *repo.Installer, insecure, skipRecursive, strip, stripVendor bool) {
	base := gpath.Basepath()
	EnsureGopath()
	EnsureVendorDir()
	conf := EnsureConfig()
	glidefile, err := gpath.Glide()
	if err != nil {
		msg.Die("Could not find Glide file: %s", err)
	}

	// Add the packages to the config.
	if count, err := addPkgsToConfig(conf, names, insecure); err != nil {
		msg.Die("Failed to get new packages: %s", err)
	} else if count == 0 {
		msg.Warn("Nothing to do")
		return
	}

	// Fetch the new packages. Can't resolve versions via installer.Update if
	// get is called while the vendor/ directory is empty so we checkout
	// everything.
	err = installer.Checkout(conf, false)
	if err != nil {
		msg.Die("Failed to checkout packages: %s", err)
	}

	// Prior to resolving dependencies we need to start working with a clone
	// of the conf because we'll be making real changes to it.
	confcopy := conf.Clone()

	if !skipRecursive {
		// Get all repos and update them.
		// TODO: Can we streamline this in any way? The reason that we update all
		// of the dependencies is that we need to re-negotiate versions. For example,
		// if an existing dependency has the constraint >1.0 and this new package
		// adds the constraint <2.0, then this may re-resolve the existing dependency
		// to be between 1.0 and 2.0. But changing that dependency may then result
		// in that dependency's dependencies changing... so we sorta do the whole
		// thing to be safe.
		err = installer.Update(confcopy)
		if err != nil {
			msg.Die("Could not update packages: %s", err)
		}
	}

	// Set Reference
	if err := repo.SetReference(confcopy); err != nil {
		msg.Err("Failed to set references: %s", err)
	}

	// VendoredCleanup
	// When stripping VCS happens this will happen as well. No need for double
	// effort.
	if installer.UpdateVendored && !strip {
		repo.VendoredCleanup(confcopy)
	}

	// Write YAML
	if err := conf.WriteFile(glidefile); err != nil {
		msg.Die("Failed to write glide YAML file: %s", err)
	}
	if !skipRecursive {
		// Write lock
		if stripVendor {
			confcopy = godep.RemoveGodepSubpackages(confcopy)
		}
		writeLock(conf, confcopy, base)
	} else {
		msg.Warn("Skipping lockfile generation because full dependency tree is not being calculated")
	}

	if strip {
		msg.Info("Removing version control data from vendor directory...")
		gpath.StripVcs()
	}

	if stripVendor {
		msg.Info("Removing nested vendor and Godeps/_workspace directories...")
		err := gpath.StripVendor()
		if err != nil {
			msg.Err("Unable to strip vendor directories: %s", err)
		}
	}
}

func writeLock(conf, confcopy *cfg.Config, base string) {
	hash, err := conf.Hash()
	if err != nil {
		msg.Die("Failed to generate config hash. Unable to generate lock file.")
	}
	lock := cfg.NewLockfile(confcopy.Imports, hash)
	if err := lock.WriteFile(filepath.Join(base, gpath.LockFile)); err != nil {
		msg.Die("Failed to write glide lock file: %s", err)
	}
}

// addPkgsToConfig adds the given packages to the config file.
//
// Along the way it:
// - ensures that this package is not in the ignore list
// - checks to see if this is already in the dependency list.
// - splits version of of package name and adds the version attribute
// - separates repo from packages
// - sets up insecure repo URLs where necessary
// - generates a list of subpackages
func addPkgsToConfig(conf *cfg.Config, names []string, insecure bool) (int, error) {

	msg.Info("Preparing to install %d package.", len(names))

	numAdded := 0
	for _, name := range names {
		var version string
		parts := strings.Split(name, "#")
		if len(parts) > 1 {
			name = parts[0]
			version = parts[1]
		}

		root, subpkg := util.NormalizeName(name)
		if len(root) == 0 {
			return 0, fmt.Errorf("Package name is required for %q.", name)
		}

		if conf.HasDependency(root) {

			// Check if the subpackage is present.
			if subpkg != "" {
				dep := conf.Imports.Get(root)
				if dep.HasSubpackage(subpkg) {
					msg.Warn("Package %q is already in glide.yaml. Skipping", name)
				} else {
					dep.Subpackages = append(dep.Subpackages, subpkg)
					msg.Info("Adding sub-package %s to existing import %s", subpkg, root)
					numAdded++
				}
			} else {
				msg.Warn("Package %q is already in glide.yaml. Skipping", root)
			}
			continue
		}

		if conf.HasIgnore(root) {
			msg.Warn("Package %q is set to be ignored in glide.yaml. Skipping", root)
			continue
		}

		dep := &cfg.Dependency{
			Name: root,
		}

		if version != "" {
			dep.Reference = version
		}

		// When retriving from an insecure location set the repo to the
		// insecure location.
		if insecure {
			dep.Repository = "http://" + root
		}

		if len(subpkg) > 0 {
			dep.Subpackages = []string{subpkg}
		}

		if dep.Reference != "" {
			msg.Info("Importing %s with the version %s", dep.Name, dep.Reference)
		} else {
			msg.Info("Importing %s", dep.Name)
		}

		conf.Imports = append(conf.Imports, dep)
		numAdded++
	}
	return numAdded, nil
}
<|endoftext|>


<commit_before>package freeze

import (
	"bytes"
	"flag"
	"os"
	"os/exec"
	"testing"
)

// The panics caused by accessing protected memory are unrecoverable.
// Therefore, the only way to test freeze's behavior is to spawn a subprocess
// and check its return value. We accomplish this by rerunning the test binary
// with a special flag enabled.

var crash = flag.Bool("crash", false, "")

func execCrasher(t *testing.T, test string) {
	cmd := exec.Command(os.Args[0], "-test.run="+test, "-crash")
	output, _ := cmd.CombinedOutput()
	if !bytes.Contains(output, []byte("unexpected fault address")) {
		t.Fatalf("Test did not trigger 'unexpected fault address' panic")
	}
}

// TestWritePointerInt tests that modifying a frozen int pointer triggers a
// panic.
func TestWritePointerInt(t *testing.T) {
	if !*crash {
		execCrasher(t, "TestWritePointerInt")
		return
	}

	var x int = 3
	xp := Pointer(&x).(*int)
	*xp++
}

// TestWritePointerString tests that modifying a frozen string pointer
// triggers a panic.
func TestWritePointerString(t *testing.T) {
	if !*crash {
		execCrasher(t, "TestWritePointerString")
		return
	}

	s := "foo"
	sp := Pointer(&s).(*string)
	*sp = "bar"
}

// TestWritePointerStruct tests that modifying a frozen struct pointer
// triggers a panic.
func TestWritePointerStruct(t *testing.T) {
	if !*crash {
		execCrasher(t, "TestWritePointerStruct")
		return
	}

	type foo struct {
		X int
		y bool
	}
	f := foo{3, true}
	fp := Pointer(&f).(*foo)
	fp.X++
}

// TestWriteSlice tests that modifying a frozen slice triggers a panic.
func TestWriteSlice(t *testing.T) {
	if !*crash {
		execCrasher(t, "TestWriteSlice")
		return
	}

	xs := []int{1, 2, 3}
	xs = Slice(xs).([]int)
	xs[0]++
}

// TestWriteSliceAppend tests that appending to a frozen slice triggers a
// panic when cap > len.
func TestWriteSliceAppend(t *testing.T) {
	if !*crash {
		execCrasher(t, "TestWriteSliceAppend")
		return
	}

	xs := make([]int, 3, 4)
	xs = Slice(xs).([]int)
	xs = append(xs, 5)
}

// TestWriteObject1 tests that modifying a frozen object triggers a panic.
func TestWriteObject1(t *testing.T) {
	if !*crash {
		execCrasher(t, "TestWriteObject1")
		return
	}

	type foo struct {
		S  string
		Ip *int
		Bs []*bool
	}
	f := &foo{"foo", new(int), []*bool{new(bool)}}
	f = Object(f).(*foo)
	*f.Bs[0] = true
}

// TestWriteObject2 tests that modifying a frozen object triggers a panic.
func TestWriteObject2(t *testing.T) {
	if !*crash {
		execCrasher(t, "TestWriteObject2")
		return
	}

	type foo struct {
		S  string
		Ip *int
		Bs []*bool
	}
	f := &foo{"foo", new(int), []*bool{new(bool)}}
	f = Object(f).(*foo)
	f.Bs[0] = new(bool)
}

// TestWriteObject3 tests that modifying a frozen object triggers a panic.
func TestWriteObject3(t *testing.T) {
	if !*crash {
		execCrasher(t, "TestWriteObject3")
		return
	}

	type foo struct {
		S  string
		Ip *int
		Bs []*bool
	}
	f := &foo{"foo", new(int), []*bool{new(bool)}}
	f = Object(f).(*foo)
	*f.Ip = 8
}

// TestWriteObject4 tests that modifying a frozen object triggers a panic.
func TestWriteObject4(t *testing.T) {
	if !*crash {
		execCrasher(t, "TestWriteObject4")
		return
	}

	type foo struct {
		S  string
		Ip *int
		Bs []*bool
	}
	f := &foo{"foo", new(int), []*bool{new(bool)}}
	f = Object(f).(*foo)
	f.S = "bar"
}

// TestReadPointer tests that frozen pointers can be read without triggering a
// panic.
func TestReadPointer(t *testing.T) {
	var x int = 3
	xp := Pointer(&x).(*int)
	y := *xp * 2
	if y != 6 {
		t.Fatal(y)
	}

	type foo struct {
		I int
		b bool
	}
	f := foo{3, true}
	fp := Pointer(&f).(*foo)
	y = fp.I * 2
	if y != 6 {
		t.Fatal(y)
	}
}

// TestReadSlice tests that frozen slices can be read without triggering a
// panic.
func TestReadSlice(t *testing.T) {
	xs := []int{1, 2, 3}
	xs = Slice(xs).([]int)
	y := xs[2] * 2
	if y != 6 {
		t.Fatal(y)
	}

	type foo struct {
		I int
		b bool
	}
	fs := []foo{{3, true}}
	fs = Slice(fs).([]foo)
	y = fs[0].I * 2
	if y != 6 {
		t.Fatal(y)
	}

	// should be able to append as long as len == cap
	fs = append(fs, foo{0, false})
	fs[0].I++ // fs can now be modified

	// if we don't reassign the pointer, we should still be pointing to
	// writable memory
	xs = []int{1, 2, 3}
	Slice(xs)
	xs[0]++
}

// TestReadObject tests that frozen objects can be read without triggering a
// panic.
func TestReadObject(t *testing.T) {
	type foo struct {
		S  string
		Ip *int
		Bs []bool
	}
	var i int = 3
	f := &foo{"foo", &i, []bool{true, false, true}}
	f = Object(f).(*foo)
	if f.S != "foo" {
		t.Fatal(f.S)
	}
	if (*f.Ip)*2 != 6 {
		t.Fatal(*f.Ip)
	}
	if f.Bs[0] && f.Bs[2] == f.Bs[1] {
		t.Fatal(f.Bs)
	}
}

// TestFreezeUnexportedObject tests that Object will not descend into
// unexported fields.
func TestFreezeUnexportedObject(t *testing.T) {
	type foo struct {
		b []byte
	}
	f := &foo{[]byte{1, 2, 3}}
	f = Object(f).(*foo)
	// f.b should not be frozen
	f.b[0] = 9
}

// TestWriteSlicePointers tests that the elements of a frozen slice of
// pointers can be modified without triggering a panic.
func TestWriteSlicePointers(t *testing.T) {
	xs := []*int{new(int), new(int), new(int)}
	xs = Slice(xs).([]*int)
	*xs[0]++
	if *xs[0] != 1 {
		t.Fatal(*xs[0])
	}
}
<commit_msg>appease golint<commit_after>package freeze

import (
	"bytes"
	"flag"
	"os"
	"os/exec"
	"testing"
)

// The panics caused by accessing protected memory are unrecoverable.
// Therefore, the only way to test freeze's behavior is to spawn a subprocess
// and check its return value. We accomplish this by rerunning the test binary
// with a special flag enabled.

var crash = flag.Bool("crash", false, "")

func execCrasher(t *testing.T, test string) {
	cmd := exec.Command(os.Args[0], "-test.run="+test, "-crash")
	output, _ := cmd.CombinedOutput()
	if !bytes.Contains(output, []byte("unexpected fault address")) {
		t.Fatalf("Test did not trigger 'unexpected fault address' panic")
	}
}

// TestWritePointerInt tests that modifying a frozen int pointer triggers a
// panic.
func TestWritePointerInt(t *testing.T) {
	if !*crash {
		execCrasher(t, "TestWritePointerInt")
		return
	}

	x := 3
	xp := Pointer(&x).(*int)
	*xp++
}

// TestWritePointerString tests that modifying a frozen string pointer
// triggers a panic.
func TestWritePointerString(t *testing.T) {
	if !*crash {
		execCrasher(t, "TestWritePointerString")
		return
	}

	s := "foo"
	sp := Pointer(&s).(*string)
	*sp = "bar"
}

// TestWritePointerStruct tests that modifying a frozen struct pointer
// triggers a panic.
func TestWritePointerStruct(t *testing.T) {
	if !*crash {
		execCrasher(t, "TestWritePointerStruct")
		return
	}

	type foo struct {
		X int
		y bool
	}
	f := foo{3, true}
	fp := Pointer(&f).(*foo)
	fp.X++
}

// TestWriteSlice tests that modifying a frozen slice triggers a panic.
func TestWriteSlice(t *testing.T) {
	if !*crash {
		execCrasher(t, "TestWriteSlice")
		return
	}

	xs := []int{1, 2, 3}
	xs = Slice(xs).([]int)
	xs[0]++
}

// TestWriteSliceAppend tests that appending to a frozen slice triggers a
// panic when cap > len.
func TestWriteSliceAppend(t *testing.T) {
	if !*crash {
		execCrasher(t, "TestWriteSliceAppend")
		return
	}

	xs := make([]int, 3, 4)
	xs = Slice(xs).([]int)
	_ = append(xs, 5)
}

// TestWriteObject1 tests that modifying a frozen object triggers a panic.
func TestWriteObject1(t *testing.T) {
	if !*crash {
		execCrasher(t, "TestWriteObject1")
		return
	}

	type foo struct {
		S  string
		IP *int
		BS []*bool
	}
	f := &foo{"foo", new(int), []*bool{new(bool)}}
	f = Object(f).(*foo)
	*f.BS[0] = true
}

// TestWriteObject2 tests that modifying a frozen object triggers a panic.
func TestWriteObject2(t *testing.T) {
	if !*crash {
		execCrasher(t, "TestWriteObject2")
		return
	}

	type foo struct {
		S  string
		IP *int
		BS []*bool
	}
	f := &foo{"foo", new(int), []*bool{new(bool)}}
	f = Object(f).(*foo)
	f.BS[0] = new(bool)
}

// TestWriteObject3 tests that modifying a frozen object triggers a panic.
func TestWriteObject3(t *testing.T) {
	if !*crash {
		execCrasher(t, "TestWriteObject3")
		return
	}

	type foo struct {
		S  string
		IP *int
		BS []*bool
	}
	f := &foo{"foo", new(int), []*bool{new(bool)}}
	f = Object(f).(*foo)
	*f.IP = 8
}

// TestWriteObject4 tests that modifying a frozen object triggers a panic.
func TestWriteObject4(t *testing.T) {
	if !*crash {
		execCrasher(t, "TestWriteObject4")
		return
	}

	type foo struct {
		S  string
		IP *int
		BS []*bool
	}
	f := &foo{"foo", new(int), []*bool{new(bool)}}
	f = Object(f).(*foo)
	f.S = "bar"
}

// TestReadPointer tests that frozen pointers can be read without triggering a
// panic.
func TestReadPointer(t *testing.T) {
	x := 3
	xp := Pointer(&x).(*int)
	y := *xp * 2
	if y != 6 {
		t.Fatal(y)
	}

	type foo struct {
		I int
		b bool
	}
	f := foo{3, true}
	fp := Pointer(&f).(*foo)
	y = fp.I * 2
	if y != 6 {
		t.Fatal(y)
	}
}

// TestReadSlice tests that frozen slices can be read without triggering a
// panic.
func TestReadSlice(t *testing.T) {
	xs := []int{1, 2, 3}
	xs = Slice(xs).([]int)
	y := xs[2] * 2
	if y != 6 {
		t.Fatal(y)
	}

	type foo struct {
		I int
		b bool
	}
	fs := []foo{{3, true}}
	fs = Slice(fs).([]foo)
	y = fs[0].I * 2
	if y != 6 {
		t.Fatal(y)
	}

	// should be able to append as long as len == cap
	fs = append(fs, foo{0, false})
	fs[0].I++ // fs can now be modified

	// if we don't reassign the pointer, we should still be pointing to
	// writable memory
	xs = []int{1, 2, 3}
	Slice(xs)
	xs[0]++
}

// TestReadObject tests that frozen objects can be read without triggering a
// panic.
func TestReadObject(t *testing.T) {
	type foo struct {
		S  string
		IP *int
		BS []bool
	}
	x := 3
	f := &foo{"foo", &x, []bool{true, false, true}}
	f = Object(f).(*foo)
	if f.S != "foo" {
		t.Fatal(f.S)
	}
	if (*f.IP)*2 != 6 {
		t.Fatal(*f.IP)
	}
	if f.BS[0] && f.BS[2] == f.BS[1] {
		t.Fatal(f.BS)
	}
}

// TestFreezeUnexportedObject tests that Object will not descend into
// unexported fields.
func TestFreezeUnexportedObject(t *testing.T) {
	type foo struct {
		b []byte
	}
	f := &foo{[]byte{1, 2, 3}}
	f = Object(f).(*foo)
	// f.b should not be frozen
	f.b[0] = 9
}

// TestWriteSlicePointers tests that the elements of a frozen slice of
// pointers can be modified without triggering a panic.
func TestWriteSlicePointers(t *testing.T) {
	xs := []*int{new(int), new(int), new(int)}
	xs = Slice(xs).([]*int)
	*xs[0]++
	if *xs[0] != 1 {
		t.Fatal(*xs[0])
	}
}
<|endoftext|>


<commit_before>package yalzo

type TodoList struct {
    list []Todo
    labels []string
}

type Todo struct {
    label string
    title string
    isArchived bool
    no int
}

func NewTodoList(l []Todo, ls []string) TodoList{
    tl := &TodoList{
        list: l,
        labels: ls,
    }
    return (*tl)
}

func (tl *TodoList) ChangeLabelName(i int, l string) {
    (*tl).list[i].label = l
}

func (tl *TodoList) Delete(n int) {
    for i := n ; i < len((*tl).list) ; i++ {
        (*tl).list[i].setNumber(i)
    }
    tl.list = append(tl.list[:n], tl.list[n+1:]...)
}

func (tl *TodoList) AddTodo(l string, t string) {
    tl.list = append(tl.list, Todo{
        no:    len(tl.list),
        label: l,
        title: t,
    })
}

func (tl *TodoList) Exchange(i1 int, i2 int) {
    (*tl).list[i2].setNumber(i1+1)
    (*tl).list[i1].setNumber(i2+1)

    tmp := (*tl).list[i2]
    (*tl).list[i2] = (*tl).list[i1]
    (*tl).list[i1] = tmp
}

func (t *Todo) setNumber(n int) {
    (*t).no = n
}
<commit_msg>fmtのかけ忘れとレビューのかけ忘れ<commit_after>package yalzo

import (
	"os"
)

type TodoList struct {
	list   []Todo
	labels []string
}

type Todo struct {
	label      string
	title      string
	isArchived bool
	no         int
}

func NewTodoList(fp *os.File, ls []string) *TodoList {
	l, err := ReadCSV(fp)
	if err != nil {
		panic(err)
	}
	return &TodoList{
		list:   l,
		labels: ls,
	}
}

func (tl *TodoList) ChangeLabelName(i int, l string) {
	(*tl).list[i].label = l
}

func (tl *TodoList) Delete(n int) {
	for i := n; i < len((*tl).list); i++ {
		(*tl).list[i].setNumber(i)
	}
	tl.list = append(tl.list[:n], tl.list[n+1:]...)
}

func (tl *TodoList) AddTodo(l string, t string) {
	tl.list = append(tl.list, Todo{
		no:    len(tl.list),
		label: l,
		title: t,
	})
}

func (tl *TodoList) Exchange(i1 int, i2 int) {
	(*tl).list[i2].setNumber(i1 + 1)
	(*tl).list[i1].setNumber(i2 + 1)

    (*tl).list[i2], (*tl).list[i1] = (*tl).list[i1], (*tl).list[i2]
}

func (t *Todo) setNumber(n int) {
	(*t).no = n
}
<|endoftext|>


<commit_before>package yalzo

import (
	"bytes"
	"fmt"
	"github.com/mattn/go-runewidth"
	"os"
)

const (
	LABEL_TEXT_WIDTH = 16
)

type TodoList struct {
	todos  []Todo
	archs  []Todo
	labels []string
	reader *os.File
}

type Todo struct {
	label      string
	title      string
	isArchived bool
	no         int
}

type Tab int

const (
	TODO Tab = iota
	ARCHIVE
)

func (t Tab) String() string {
	switch t {
	case TODO:
		return "Todo"
	case ARCHIVE:
		return "Archive"
	}
	return "Unknown"
}

func NewTodoList(fp *os.File, ls []string) *TodoList {
	l, as, err := ReadCSV(fp)
	if err != nil {
		panic(err)
	}

	return &TodoList{
		todos:  l,
		archs:  as,
		labels: ls,
		reader: fp,
	}
}

func (tl *TodoList) GetList(width int, tab Tab) []string {
	lines := make([]string, 0, 100)
	lists := tl.getListInTab(tab)
	for i := 0; i < len(lists); i++ {
		lines = append(lines, lists[i].tolimitStr(width))
	}
	return lines
}

func (tl *TodoList) GetLabels() []string {
	for i := 0; i < len(tl.todos); i++ {
		label := tl.todos[i].label
		if !tl.existLabel(label) && label != "" {
			tl.labels = append(tl.labels, label)
		}
	}

	for i := 0; i < len(tl.archs); i++ {
		label := tl.archs[i].label
		if !tl.existLabel(label) && label != "" {
			tl.labels = append(tl.labels, label)
		}
	}

	return tl.labels
}

func (tl *TodoList) Save() {
	SaveCSV(tl.todos, tl.archs, tl.reader)
}

func (tl *TodoList) ChangeTitle(i int, t string, tab Tab) {
	switch tab {
	case TODO:
		(*tl).todos[i].title = t
	case ARCHIVE:
		(*tl).archs[i].title = t
	}
}

func (tl *TodoList) ChangeLabelName(i int, l string, tab Tab) {
	switch tab {
	case TODO:
		(*tl).todos[i].label = l
	case ARCHIVE:
		(*tl).archs[i].label = l
	}
}

func (tl *TodoList) Delete(n int) {
	for i := n; i < len((*tl).todos); i++ {
		(*tl).todos[i].setNumber(i)
	}
	tl.todos = append(tl.todos[:n], tl.todos[n+1:]...)
}

func (tl *TodoList) AddTodo(t string) int {
	no := len(tl.todos) + 1
	tl.todos = append(tl.todos, Todo{
		no:    no,
		label: "",
		title: t,
	})
	return no
}

func (tl *TodoList) MoveArchive(n int) {
	length := len(tl.todos)
	tl.todos[n].isArchived = true
	tl.todos[n].setNumber(length)
	tl.archs = append(tl.archs, tl.todos[n])
	for i := n + 1; i < len(tl.todos); i++ {
		tl.todos[i].setNumber(i - 1)
	}
	tl.todos = append(tl.todos[:n], tl.todos[n+1:]...)
}

func (tl *TodoList) MoveTodo(n int) {
	length := len(tl.todos)
	tl.archs[n].isArchived = false
	tl.archs[n].setNumber(length)
	tl.todos = append(tl.todos, tl.archs[n])
	for i := n + 1; i < length; i++ {
		tl.todos[i].setNumber(i - 1)
	}
	tl.archs = append(tl.archs[:n], tl.archs[n+1:]...)
}

func (tl *TodoList) Exchange(i1 int, i2 int, tab Tab) {
	switch tab {
	case TODO:
		tl.todos[i2].setNumber(i1 + 1)
		tl.todos[i1].setNumber(i2 + 1)
		tl.todos[i2], tl.todos[i1] = tl.todos[i1], tl.todos[i2]
	case ARCHIVE:
		tl.archs[i2].setNumber(i1 + 1)
		tl.archs[i1].setNumber(i2 + 1)
		tl.archs[i2], tl.archs[i1] = tl.archs[i1], tl.archs[i2]
	}
}

func (t *Todo) setNumber(n int) {
	(*t).no = n
}

func (tl *TodoList) existLabel(l string) bool {
	for i := 0; i < len(tl.labels); i++ {
		if tl.labels[i] == l {
			return true
		}
	}
	return false
}

func (tl *TodoList) getListInTab(tab Tab) []Todo {
	switch tab {
	case ARCHIVE:
		return tl.archs
	case TODO:
		return tl.todos
	}
	return []Todo{}
}

func (t *Todo) tolimitStr(limit int) string {
	num_s := fmt.Sprintf("%3d", t.no)
	label_s := t.label
	label_len := runewidth.StringWidth(label_s)
	if label_len > LABEL_TEXT_WIDTH {
		label_s = runewidth.Truncate(label_s, LABEL_TEXT_WIDTH, "")
	} else {
		padding := repeatSpace((LABEL_TEXT_WIDTH - label_len) / 2)
		buf := bytes.NewBuffer(padding)
		buf.Write([]byte(label_s))
		buf.Write(padding)
		label_s = buf.String()

		// if label string lenght is odd and more than LABEL_TEXT_WIDTH
		if runewidth.StringWidth(label_s) == LABEL_TEXT_WIDTH+1 {
			label_s = runewidth.Truncate(label_s, LABEL_TEXT_WIDTH, "")
		}
	}

	str := num_s + " [ " + label_s + " ] " + t.title
	length := runewidth.StringWidth(str)
	if length > limit {
		return runewidth.Truncate(str, limit, "")
	} else {
		str_len := runewidth.StringWidth(str)
		buf := bytes.NewBufferString(str)
		for str_len < limit {
			str_len++
			buf.Write([]byte(" "))
		}
		return buf.String()
	}
}

func repeatSpace(cnt int) []byte {
	buf := bytes.NewBuffer(make([]byte, 0, cnt))
	for cnt-1 >= 0 {
		buf.Write([]byte(" "))
		cnt--
	}
	return buf.Bytes()
}
<commit_msg>変数名と関数名の変更<commit_after>package yalzo

import (
	"bytes"
	"fmt"
	"github.com/mattn/go-runewidth"
	"os"
)

const (
	LABEL_TEXT_WIDTH = 16
)

type TodoList struct {
	todos  []Todo
	archs  []Todo
	labels []string
	file   *os.File
}

type Todo struct {
	label      string
	title      string
	isArchived bool
	no         int
}

type Tab int

const (
	TODO Tab = iota
	ARCHIVE
)

func (t Tab) String() string {
	switch t {
	case TODO:
		return "Todo"
	case ARCHIVE:
		return "Archive"
	}
	return "Unknown"
}

func NewTodoList(fp *os.File, ls []string) *TodoList {
	l, as, err := ReadCSV(fp)
	if err != nil {
		panic(err)
	}

	return &TodoList{
		todos:  l,
		archs:  as,
		labels: ls,
		file:   fp,
	}
}

func (tl *TodoList) GetList(width int, tab Tab) []string {
	lines := make([]string, 0, 100)
	lists := tl.getListInTab(tab)
	for i := 0; i < len(lists); i++ {
		lines = append(lines, lists[i].createTodoText(width))
	}
	return lines
}

func (tl *TodoList) GetLabels() []string {
	for i := 0; i < len(tl.todos); i++ {
		label := tl.todos[i].label
		if !tl.existLabel(label) && label != "" {
			tl.labels = append(tl.labels, label)
		}
	}

	for i := 0; i < len(tl.archs); i++ {
		label := tl.archs[i].label
		if !tl.existLabel(label) && label != "" {
			tl.labels = append(tl.labels, label)
		}
	}

	return tl.labels
}

func (tl *TodoList) Save() {
	SaveCSV(tl.todos, tl.archs, tl.file)
}

func (tl *TodoList) ChangeTitle(i int, t string, tab Tab) {
	switch tab {
	case TODO:
		(*tl).todos[i].title = t
	case ARCHIVE:
		(*tl).archs[i].title = t
	}
}

func (tl *TodoList) ChangeLabelName(i int, l string, tab Tab) {
	switch tab {
	case TODO:
		(*tl).todos[i].label = l
	case ARCHIVE:
		(*tl).archs[i].label = l
	}
}

func (tl *TodoList) Delete(n int) {
	for i := n; i < len((*tl).todos); i++ {
		(*tl).todos[i].setNumber(i)
	}
	tl.todos = append(tl.todos[:n], tl.todos[n+1:]...)
}

func (tl *TodoList) AddTodo(t string) int {
	no := len(tl.todos) + 1
	tl.todos = append(tl.todos, Todo{
		no:    no,
		label: "",
		title: t,
	})
	return no
}

func (tl *TodoList) MoveArchive(n int) {
	length := len(tl.todos)
	tl.todos[n].isArchived = true
	tl.todos[n].setNumber(length)
	tl.archs = append(tl.archs, tl.todos[n])
	for i := n + 1; i < len(tl.todos); i++ {
		tl.todos[i].setNumber(i - 1)
	}
	tl.todos = append(tl.todos[:n], tl.todos[n+1:]...)
}

func (tl *TodoList) MoveTodo(n int) {
	length := len(tl.todos)
	tl.archs[n].isArchived = false
	tl.archs[n].setNumber(length)
	tl.todos = append(tl.todos, tl.archs[n])
	for i := n + 1; i < length; i++ {
		tl.todos[i].setNumber(i - 1)
	}
	tl.archs = append(tl.archs[:n], tl.archs[n+1:]...)
}

func (tl *TodoList) Exchange(i1 int, i2 int, tab Tab) {
	switch tab {
	case TODO:
		tl.todos[i2].setNumber(i1 + 1)
		tl.todos[i1].setNumber(i2 + 1)
		tl.todos[i2], tl.todos[i1] = tl.todos[i1], tl.todos[i2]
	case ARCHIVE:
		tl.archs[i2].setNumber(i1 + 1)
		tl.archs[i1].setNumber(i2 + 1)
		tl.archs[i2], tl.archs[i1] = tl.archs[i1], tl.archs[i2]
	}
}

func (t *Todo) setNumber(n int) {
	(*t).no = n
}

func (tl *TodoList) existLabel(l string) bool {
	for i := 0; i < len(tl.labels); i++ {
		if tl.labels[i] == l {
			return true
		}
	}
	return false
}

func (tl *TodoList) getListInTab(tab Tab) []Todo {
	switch tab {
	case ARCHIVE:
		return tl.archs
	case TODO:
		return tl.todos
	}
	return []Todo{}
}

func (t *Todo) createTodoText(limit int) string {
	num_s := fmt.Sprintf("%3d", t.no)
	label_s := t.label
	label_len := runewidth.StringWidth(label_s)
	if label_len > LABEL_TEXT_WIDTH {
		label_s = runewidth.Truncate(label_s, LABEL_TEXT_WIDTH, "")
	} else {
		padding := repeatSpace((LABEL_TEXT_WIDTH - label_len) / 2)
		buf := bytes.NewBuffer(padding)
		buf.Write([]byte(label_s))
		buf.Write(padding)
		label_s = buf.String()

		// if label string lenght is odd and more than LABEL_TEXT_WIDTH
		if runewidth.StringWidth(label_s) == LABEL_TEXT_WIDTH+1 {
			label_s = runewidth.Truncate(label_s, LABEL_TEXT_WIDTH, "")
		}
	}

	str := num_s + " [ " + label_s + " ] " + t.title
	length := runewidth.StringWidth(str)
	if length > limit {
		return runewidth.Truncate(str, limit, "")
	} else {
		str_len := runewidth.StringWidth(str)
		buf := bytes.NewBufferString(str)
		for str_len < limit {
			str_len++
			buf.Write([]byte(" "))
		}
		return buf.String()
	}
}

func repeatSpace(cnt int) []byte {
	buf := bytes.NewBuffer(make([]byte, 0, cnt))
	for cnt-1 >= 0 {
		buf.Write([]byte(" "))
		cnt--
	}
	return buf.Bytes()
}
<|endoftext|>


<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package instance

import (
	"errors"
	"fmt"
	"launchpad.net/juju-core/utils"
	"math"
	"sort"
	"strconv"
	"strings"
)

var ErrNoDNSName = errors.New("DNS name not allocated")

// An instance Id is a provider-specific identifier associated with an
// instance (physical or virtual machine allocated in the provider).
type Id string

// Port identifies a network port number for a particular protocol.
type Port struct {
	Protocol string
	Number   int
}

func (p Port) String() string {
	return fmt.Sprintf("%d/%s", p.Number, p.Protocol)
}

// Instance represents the the realization of a machine in state.
type Instance interface {
	// Id returns a provider-generated identifier for the Instance.
	Id() Id

	// Status returns the provider-specific status for the instance.
	Status() string

	// Refresh refreshes local knowledge of the instance from the provider.
	Refresh() error

	// Addresses returns a list of hostnames or ip addresses
	// associated with the instance. This will supercede DNSName
	// which can be implemented by selecting a preferred address.
	Addresses() ([]Address, error)

	// DNSName returns the DNS name for the instance.
	// If the name is not yet allocated, it will return
	// an ErrNoDNSName error.
	DNSName() (string, error)

	// WaitDNSName returns the DNS name for the instance,
	// waiting until it is allocated if necessary.
	// TODO: We may not need this in the interface any more.  All
	// implementations now delegate to environs.WaitDNSName.
	WaitDNSName() (string, error)

	// OpenPorts opens the given ports on the instance, which
	// should have been started with the given machine id.
	OpenPorts(machineId string, ports []Port) error

	// ClosePorts closes the given ports on the instance, which
	// should have been started with the given machine id.
	ClosePorts(machineId string, ports []Port) error

	// Ports returns the set of ports open on the instance, which
	// should have been started with the given machine id.
	// The ports are returned as sorted by SortPorts.
	Ports(machineId string) ([]Port, error)
}

// HardwareCharacteristics represents the characteristics of the instance (if known).
// Attributes that are nil are unknown or not supported.
type HardwareCharacteristics struct {
	Arch     *string   `yaml:"arch,omitempty"`
	Mem      *uint64   `yaml:"mem,omitempty"`
	RootDisk *uint64   `yaml:"rootdisk,omitempty"`
	CpuCores *uint64   `yaml:"cpucores,omitempty"`
	CpuPower *uint64   `yaml:"cpupower,omitempty"`
	Tags     *[]string `yaml:"tags,omitempty"`
}

func uintStr(i uint64) string {
	if i == 0 {
		return ""
	}
	return fmt.Sprintf("%d", i)
}

func (hc HardwareCharacteristics) String() string {
	var strs []string
	if hc.Arch != nil {
		strs = append(strs, fmt.Sprintf("arch=%s", *hc.Arch))
	}
	if hc.CpuCores != nil {
		strs = append(strs, fmt.Sprintf("cpu-cores=%d", *hc.CpuCores))
	}
	if hc.CpuPower != nil {
		strs = append(strs, fmt.Sprintf("cpu-power=%d", *hc.CpuPower))
	}
	if hc.Mem != nil {
		strs = append(strs, fmt.Sprintf("mem=%dM", *hc.Mem))
	}
	if hc.RootDisk != nil {
		strs = append(strs, fmt.Sprintf("root-disk=%dM", *hc.RootDisk))
	}
	if hc.Tags != nil && len(*hc.Tags) > 0 {
		strs = append(strs, fmt.Sprintf("tags=%s", strings.Join(*hc.Tags, ",")))
	}
	return strings.Join(strs, " ")
}

// MustParseHardware constructs a HardwareCharacteristics from the supplied arguments,
// as Parse, but panics on failure.
func MustParseHardware(args ...string) HardwareCharacteristics {
	hc, err := ParseHardware(args...)
	if err != nil {
		panic(err)
	}
	return hc
}

// ParseHardware constructs a HardwareCharacteristics from the supplied arguments,
// each of which must contain only spaces and name=value pairs. If any
// name is specified more than once, an error is returned.
func ParseHardware(args ...string) (HardwareCharacteristics, error) {
	hc := HardwareCharacteristics{}
	for _, arg := range args {
		raws := strings.Split(strings.TrimSpace(arg), " ")
		for _, raw := range raws {
			if raw == "" {
				continue
			}
			if err := hc.setRaw(raw); err != nil {
				return HardwareCharacteristics{}, err
			}
		}
	}
	return hc, nil
}

// setRaw interprets a name=value string and sets the supplied value.
func (hc *HardwareCharacteristics) setRaw(raw string) error {
	eq := strings.Index(raw, "=")
	if eq <= 0 {
		return fmt.Errorf("malformed characteristic %q", raw)
	}
	name, str := raw[:eq], raw[eq+1:]
	var err error
	switch name {
	case "arch":
		err = hc.setArch(str)
	case "cpu-cores":
		err = hc.setCpuCores(str)
	case "cpu-power":
		err = hc.setCpuPower(str)
	case "mem":
		err = hc.setMem(str)
	case "root-disk":
		err = hc.setRootDisk(str)
	case "tags":
		err = hc.setTags(str)
	default:
		return fmt.Errorf("unknown characteristic %q", name)
	}
	if err != nil {
		return fmt.Errorf("bad %q characteristic: %v", name, err)
	}
	return nil
}

func (hc *HardwareCharacteristics) setArch(str string) error {
	if hc.Arch != nil {
		return fmt.Errorf("already set")
	}
	if str != "" && !utils.IsSupportedArch(str) {
		return fmt.Errorf("%q not recognized", str)
	}
	hc.Arch = &str
	return nil
}

func (hc *HardwareCharacteristics) setCpuCores(str string) (err error) {
	if hc.CpuCores != nil {
		return fmt.Errorf("already set")
	}
	hc.CpuCores, err = parseUint64(str)
	return
}

func (hc *HardwareCharacteristics) setCpuPower(str string) (err error) {
	if hc.CpuPower != nil {
		return fmt.Errorf("already set")
	}
	hc.CpuPower, err = parseUint64(str)
	return
}

func (hc *HardwareCharacteristics) setMem(str string) (err error) {
	if hc.Mem != nil {
		return fmt.Errorf("already set")
	}
	hc.Mem, err = parseSize(str)
	return
}

func (hc *HardwareCharacteristics) setRootDisk(str string) (err error) {
	if hc.RootDisk != nil {
		return fmt.Errorf("already set")
	}
	hc.RootDisk, err = parseSize(str)
	return
}

func (hc *HardwareCharacteristics) setTags(str string) (err error) {
	if hc.Tags != nil {
		return fmt.Errorf("already set")
	}
	hc.Tags = parseTags(str)
	return
}

// parseTags returns the tags in the value s
func parseTags(s string) *[]string {
	if s == "" {
		return &[]string{}
	}
	tags := strings.Split(s, ",")
	return &tags
}

func parseUint64(str string) (*uint64, error) {
	var value uint64
	if str != "" {
		if val, err := strconv.ParseUint(str, 10, 64); err != nil {
			return nil, fmt.Errorf("must be a non-negative integer")
		} else {
			value = uint64(val)
		}
	}
	return &value, nil
}

func parseSize(str string) (*uint64, error) {
	var value uint64
	if str != "" {
		mult := 1.0
		if m, ok := mbSuffixes[str[len(str)-1:]]; ok {
			str = str[:len(str)-1]
			mult = m
		}
		val, err := strconv.ParseFloat(str, 64)
		if err != nil || val < 0 {
			return nil, fmt.Errorf("must be a non-negative float with optional M/G/T/P suffix")
		}
		val *= mult
		value = uint64(math.Ceil(val))
	}
	return &value, nil
}

var mbSuffixes = map[string]float64{
	"M": 1,
	"G": 1024,
	"T": 1024 * 1024,
	"P": 1024 * 1024 * 1024,
}

type portSlice []Port

func (p portSlice) Len() int      { return len(p) }
func (p portSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p portSlice) Less(i, j int) bool {
	p1 := p[i]
	p2 := p[j]
	if p1.Protocol != p2.Protocol {
		return p1.Protocol < p2.Protocol
	}
	return p1.Number < p2.Number
}

// SortPorts sorts the given ports, first by protocol,
// then by number.
func SortPorts(ports []Port) {
	sort.Sort(portSlice(ports))
}
<commit_msg>Fix compile<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package instance

import (
	"errors"
	"fmt"
	"math"
	"sort"
	"strconv"
	"strings"

	"launchpad.net/juju-core/juju/arch"
)

var ErrNoDNSName = errors.New("DNS name not allocated")

// An instance Id is a provider-specific identifier associated with an
// instance (physical or virtual machine allocated in the provider).
type Id string

// Port identifies a network port number for a particular protocol.
type Port struct {
	Protocol string
	Number   int
}

func (p Port) String() string {
	return fmt.Sprintf("%d/%s", p.Number, p.Protocol)
}

// Instance represents the the realization of a machine in state.
type Instance interface {
	// Id returns a provider-generated identifier for the Instance.
	Id() Id

	// Status returns the provider-specific status for the instance.
	Status() string

	// Refresh refreshes local knowledge of the instance from the provider.
	Refresh() error

	// Addresses returns a list of hostnames or ip addresses
	// associated with the instance. This will supercede DNSName
	// which can be implemented by selecting a preferred address.
	Addresses() ([]Address, error)

	// DNSName returns the DNS name for the instance.
	// If the name is not yet allocated, it will return
	// an ErrNoDNSName error.
	DNSName() (string, error)

	// WaitDNSName returns the DNS name for the instance,
	// waiting until it is allocated if necessary.
	// TODO: We may not need this in the interface any more.  All
	// implementations now delegate to environs.WaitDNSName.
	WaitDNSName() (string, error)

	// OpenPorts opens the given ports on the instance, which
	// should have been started with the given machine id.
	OpenPorts(machineId string, ports []Port) error

	// ClosePorts closes the given ports on the instance, which
	// should have been started with the given machine id.
	ClosePorts(machineId string, ports []Port) error

	// Ports returns the set of ports open on the instance, which
	// should have been started with the given machine id.
	// The ports are returned as sorted by SortPorts.
	Ports(machineId string) ([]Port, error)
}

// HardwareCharacteristics represents the characteristics of the instance (if known).
// Attributes that are nil are unknown or not supported.
type HardwareCharacteristics struct {
	Arch     *string   `yaml:"arch,omitempty"`
	Mem      *uint64   `yaml:"mem,omitempty"`
	RootDisk *uint64   `yaml:"rootdisk,omitempty"`
	CpuCores *uint64   `yaml:"cpucores,omitempty"`
	CpuPower *uint64   `yaml:"cpupower,omitempty"`
	Tags     *[]string `yaml:"tags,omitempty"`
}

func uintStr(i uint64) string {
	if i == 0 {
		return ""
	}
	return fmt.Sprintf("%d", i)
}

func (hc HardwareCharacteristics) String() string {
	var strs []string
	if hc.Arch != nil {
		strs = append(strs, fmt.Sprintf("arch=%s", *hc.Arch))
	}
	if hc.CpuCores != nil {
		strs = append(strs, fmt.Sprintf("cpu-cores=%d", *hc.CpuCores))
	}
	if hc.CpuPower != nil {
		strs = append(strs, fmt.Sprintf("cpu-power=%d", *hc.CpuPower))
	}
	if hc.Mem != nil {
		strs = append(strs, fmt.Sprintf("mem=%dM", *hc.Mem))
	}
	if hc.RootDisk != nil {
		strs = append(strs, fmt.Sprintf("root-disk=%dM", *hc.RootDisk))
	}
	if hc.Tags != nil && len(*hc.Tags) > 0 {
		strs = append(strs, fmt.Sprintf("tags=%s", strings.Join(*hc.Tags, ",")))
	}
	return strings.Join(strs, " ")
}

// MustParseHardware constructs a HardwareCharacteristics from the supplied arguments,
// as Parse, but panics on failure.
func MustParseHardware(args ...string) HardwareCharacteristics {
	hc, err := ParseHardware(args...)
	if err != nil {
		panic(err)
	}
	return hc
}

// ParseHardware constructs a HardwareCharacteristics from the supplied arguments,
// each of which must contain only spaces and name=value pairs. If any
// name is specified more than once, an error is returned.
func ParseHardware(args ...string) (HardwareCharacteristics, error) {
	hc := HardwareCharacteristics{}
	for _, arg := range args {
		raws := strings.Split(strings.TrimSpace(arg), " ")
		for _, raw := range raws {
			if raw == "" {
				continue
			}
			if err := hc.setRaw(raw); err != nil {
				return HardwareCharacteristics{}, err
			}
		}
	}
	return hc, nil
}

// setRaw interprets a name=value string and sets the supplied value.
func (hc *HardwareCharacteristics) setRaw(raw string) error {
	eq := strings.Index(raw, "=")
	if eq <= 0 {
		return fmt.Errorf("malformed characteristic %q", raw)
	}
	name, str := raw[:eq], raw[eq+1:]
	var err error
	switch name {
	case "arch":
		err = hc.setArch(str)
	case "cpu-cores":
		err = hc.setCpuCores(str)
	case "cpu-power":
		err = hc.setCpuPower(str)
	case "mem":
		err = hc.setMem(str)
	case "root-disk":
		err = hc.setRootDisk(str)
	case "tags":
		err = hc.setTags(str)
	default:
		return fmt.Errorf("unknown characteristic %q", name)
	}
	if err != nil {
		return fmt.Errorf("bad %q characteristic: %v", name, err)
	}
	return nil
}

func (hc *HardwareCharacteristics) setArch(str string) error {
	if hc.Arch != nil {
		return fmt.Errorf("already set")
	}
	if str != "" && !arch.IsSupportedArch(str) {
		return fmt.Errorf("%q not recognized", str)
	}
	hc.Arch = &str
	return nil
}

func (hc *HardwareCharacteristics) setCpuCores(str string) (err error) {
	if hc.CpuCores != nil {
		return fmt.Errorf("already set")
	}
	hc.CpuCores, err = parseUint64(str)
	return
}

func (hc *HardwareCharacteristics) setCpuPower(str string) (err error) {
	if hc.CpuPower != nil {
		return fmt.Errorf("already set")
	}
	hc.CpuPower, err = parseUint64(str)
	return
}

func (hc *HardwareCharacteristics) setMem(str string) (err error) {
	if hc.Mem != nil {
		return fmt.Errorf("already set")
	}
	hc.Mem, err = parseSize(str)
	return
}

func (hc *HardwareCharacteristics) setRootDisk(str string) (err error) {
	if hc.RootDisk != nil {
		return fmt.Errorf("already set")
	}
	hc.RootDisk, err = parseSize(str)
	return
}

func (hc *HardwareCharacteristics) setTags(str string) (err error) {
	if hc.Tags != nil {
		return fmt.Errorf("already set")
	}
	hc.Tags = parseTags(str)
	return
}

// parseTags returns the tags in the value s
func parseTags(s string) *[]string {
	if s == "" {
		return &[]string{}
	}
	tags := strings.Split(s, ",")
	return &tags
}

func parseUint64(str string) (*uint64, error) {
	var value uint64
	if str != "" {
		if val, err := strconv.ParseUint(str, 10, 64); err != nil {
			return nil, fmt.Errorf("must be a non-negative integer")
		} else {
			value = uint64(val)
		}
	}
	return &value, nil
}

func parseSize(str string) (*uint64, error) {
	var value uint64
	if str != "" {
		mult := 1.0
		if m, ok := mbSuffixes[str[len(str)-1:]]; ok {
			str = str[:len(str)-1]
			mult = m
		}
		val, err := strconv.ParseFloat(str, 64)
		if err != nil || val < 0 {
			return nil, fmt.Errorf("must be a non-negative float with optional M/G/T/P suffix")
		}
		val *= mult
		value = uint64(math.Ceil(val))
	}
	return &value, nil
}

var mbSuffixes = map[string]float64{
	"M": 1,
	"G": 1024,
	"T": 1024 * 1024,
	"P": 1024 * 1024 * 1024,
}

type portSlice []Port

func (p portSlice) Len() int      { return len(p) }
func (p portSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p portSlice) Less(i, j int) bool {
	p1 := p[i]
	p2 := p[j]
	if p1.Protocol != p2.Protocol {
		return p1.Protocol < p2.Protocol
	}
	return p1.Number < p2.Number
}

// SortPorts sorts the given ports, first by protocol,
// then by number.
func SortPorts(ports []Port) {
	sort.Sort(portSlice(ports))
}
<|endoftext|>


<commit_before>package internal

import (
	"time"

	"golang.org/x/exp/rand"
)

// Retry backoff with jitter sleep to prevent overloaded conditions during intervals
// https://www.awsarchitectureblog.com/2015/03/backoff.html
func RetryBackoff(retry int, minBackoff, maxBackoff time.Duration) time.Duration {
	if retry < 0 {
		retry = 0
	}

	backoff := minBackoff << uint(retry)
	if backoff > maxBackoff || backoff < minBackoff {
		backoff = maxBackoff
	}

	if backoff == 0 {
		return 0
	}
	return time.Duration(rand.Int63n(int64(backoff)))
}
<commit_msg>Tweak backoff<commit_after>package internal

import (
	"time"

	"golang.org/x/exp/rand"
)

func RetryBackoff(retry int, minBackoff, maxBackoff time.Duration) time.Duration {
	if retry < 0 {
		panic("not reached")
	}

	d := minBackoff << uint(retry)
	d = minBackoff + time.Duration(rand.Int63n(int64(d)))

	if d > maxBackoff || d < minBackoff {
		d = maxBackoff
	}

	return d
}
<|endoftext|>


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

package span

import (
	"fmt"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"strings"
	"unicode"
)

const fileScheme = "file"

// URI represents the full URI for a file.
type URI string

func (uri URI) IsFile() bool {
	return strings.HasPrefix(string(uri), "file://")
}

// Filename returns the file path for the given URI.
// It is an error to call this on a URI that is not a valid filename.
func (uri URI) Filename() string {
	filename, err := filename(uri)
	if err != nil {
		panic(err)
	}
	return filepath.FromSlash(filename)
}

func filename(uri URI) (string, error) {
	if uri == "" {
		return "", nil
	}
	u, err := url.ParseRequestURI(string(uri))
	if err != nil {
		return "", err
	}
	if u.Scheme != fileScheme {
		return "", fmt.Errorf("only file URIs are supported, got %q from %q", u.Scheme, uri)
	}
	// If the URI is a Windows URI, we trim the leading "/" and lowercase
	// the drive letter, which will never be case sensitive.
	if isWindowsDriveURIPath(u.Path) {
		u.Path = strings.ToUpper(string(u.Path[1])) + u.Path[2:]
	}
	return u.Path, nil
}

func URIFromURI(s string) URI {
	if !strings.HasPrefix(s, "file://") {
		return URI(s)
	}

	if !strings.HasPrefix(s, "file:///") {
		// VS Code sends URLs with only two slashes, which are invalid. golang/go#39789.
		s = "file:///" + s[len("file://"):]
	}
	// Even though the input is a URI, it may not be in canonical form. VS Code
	// in particular over-escapes :, @, etc. Unescape and re-encode to canonicalize.
	path, err := url.PathUnescape(s[len("file://"):])
	if err != nil {
		panic(err)
	}

	// File URIs from Windows may have lowercase drive letters.
	// Since drive letters are guaranteed to be case insensitive,
	// we change them to uppercase to remain consistent.
	// For example, file:///c:/x/y/z becomes file:///C:/x/y/z.
	if isWindowsDriveURIPath(path) {
		path = path[:1] + strings.ToUpper(string(path[1])) + path[2:]
	}
	u := url.URL{Scheme: fileScheme, Path: path}
	return URI(u.String())
}

func CompareURI(a, b URI) int {
	if equalURI(a, b) {
		return 0
	}
	if a < b {
		return -1
	}
	return 1
}

func equalURI(a, b URI) bool {
	if a == b {
		return true
	}
	// If we have the same URI basename, we may still have the same file URIs.
	if !strings.EqualFold(path.Base(string(a)), path.Base(string(b))) {
		return false
	}
	fa, err := filename(a)
	if err != nil {
		return false
	}
	fb, err := filename(b)
	if err != nil {
		return false
	}
	// Stat the files to check if they are equal.
	infoa, err := os.Stat(filepath.FromSlash(fa))
	if err != nil {
		return false
	}
	infob, err := os.Stat(filepath.FromSlash(fb))
	if err != nil {
		return false
	}
	return os.SameFile(infoa, infob)
}

// URIFromPath returns a span URI for the supplied file path.
// It will always have the file scheme.
func URIFromPath(path string) URI {
	if path == "" {
		return ""
	}
	// Handle standard library paths that contain the literal "$GOROOT".
	// TODO(rstambler): The go/packages API should allow one to determine a user's $GOROOT.
	const prefix = "$GOROOT"
	if len(path) >= len(prefix) && strings.EqualFold(prefix, path[:len(prefix)]) {
		suffix := path[len(prefix):]
		path = runtime.GOROOT() + suffix
	}
	if !isWindowsDrivePath(path) {
		if abs, err := filepath.Abs(path); err == nil {
			path = abs
		}
	}
	// Check the file path again, in case it became absolute.
	if isWindowsDrivePath(path) {
		path = "/" + strings.ToUpper(string(path[0])) + path[1:]
	}
	path = filepath.ToSlash(path)
	u := url.URL{
		Scheme: fileScheme,
		Path:   path,
	}
	return URI(u.String())
}

// isWindowsDrivePath returns true if the file path is of the form used by
// Windows. We check if the path begins with a drive letter, followed by a ":".
// For example: C:/x/y/z.
func isWindowsDrivePath(path string) bool {
	if len(path) < 3 {
		return false
	}
	return unicode.IsLetter(rune(path[0])) && path[1] == ':'
}

// isWindowsDriveURI returns true if the file URI is of the format used by
// Windows URIs. The url.Parse package does not specially handle Windows paths
// (see golang/go#6027), so we check if the URI path has a drive prefix (e.g. "/C:").
func isWindowsDriveURIPath(uri string) bool {
	if len(uri) < 4 {
		return false
	}
	return uri[0] == '/' && unicode.IsLetter(rune(uri[1])) && uri[2] == ':'
}
<commit_msg>internal/span: fix a comment about windows drive letters<commit_after>// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package span

import (
	"fmt"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"strings"
	"unicode"
)

const fileScheme = "file"

// URI represents the full URI for a file.
type URI string

func (uri URI) IsFile() bool {
	return strings.HasPrefix(string(uri), "file://")
}

// Filename returns the file path for the given URI.
// It is an error to call this on a URI that is not a valid filename.
func (uri URI) Filename() string {
	filename, err := filename(uri)
	if err != nil {
		panic(err)
	}
	return filepath.FromSlash(filename)
}

func filename(uri URI) (string, error) {
	if uri == "" {
		return "", nil
	}
	u, err := url.ParseRequestURI(string(uri))
	if err != nil {
		return "", err
	}
	if u.Scheme != fileScheme {
		return "", fmt.Errorf("only file URIs are supported, got %q from %q", u.Scheme, uri)
	}
	// If the URI is a Windows URI, we trim the leading "/" and uppercase
	// the drive letter, which will never be case sensitive.
	if isWindowsDriveURIPath(u.Path) {
		u.Path = strings.ToUpper(string(u.Path[1])) + u.Path[2:]
	}
	return u.Path, nil
}

func URIFromURI(s string) URI {
	if !strings.HasPrefix(s, "file://") {
		return URI(s)
	}

	if !strings.HasPrefix(s, "file:///") {
		// VS Code sends URLs with only two slashes, which are invalid. golang/go#39789.
		s = "file:///" + s[len("file://"):]
	}
	// Even though the input is a URI, it may not be in canonical form. VS Code
	// in particular over-escapes :, @, etc. Unescape and re-encode to canonicalize.
	path, err := url.PathUnescape(s[len("file://"):])
	if err != nil {
		panic(err)
	}

	// File URIs from Windows may have lowercase drive letters.
	// Since drive letters are guaranteed to be case insensitive,
	// we change them to uppercase to remain consistent.
	// For example, file:///c:/x/y/z becomes file:///C:/x/y/z.
	if isWindowsDriveURIPath(path) {
		path = path[:1] + strings.ToUpper(string(path[1])) + path[2:]
	}
	u := url.URL{Scheme: fileScheme, Path: path}
	return URI(u.String())
}

func CompareURI(a, b URI) int {
	if equalURI(a, b) {
		return 0
	}
	if a < b {
		return -1
	}
	return 1
}

func equalURI(a, b URI) bool {
	if a == b {
		return true
	}
	// If we have the same URI basename, we may still have the same file URIs.
	if !strings.EqualFold(path.Base(string(a)), path.Base(string(b))) {
		return false
	}
	fa, err := filename(a)
	if err != nil {
		return false
	}
	fb, err := filename(b)
	if err != nil {
		return false
	}
	// Stat the files to check if they are equal.
	infoa, err := os.Stat(filepath.FromSlash(fa))
	if err != nil {
		return false
	}
	infob, err := os.Stat(filepath.FromSlash(fb))
	if err != nil {
		return false
	}
	return os.SameFile(infoa, infob)
}

// URIFromPath returns a span URI for the supplied file path.
// It will always have the file scheme.
func URIFromPath(path string) URI {
	if path == "" {
		return ""
	}
	// Handle standard library paths that contain the literal "$GOROOT".
	// TODO(rstambler): The go/packages API should allow one to determine a user's $GOROOT.
	const prefix = "$GOROOT"
	if len(path) >= len(prefix) && strings.EqualFold(prefix, path[:len(prefix)]) {
		suffix := path[len(prefix):]
		path = runtime.GOROOT() + suffix
	}
	if !isWindowsDrivePath(path) {
		if abs, err := filepath.Abs(path); err == nil {
			path = abs
		}
	}
	// Check the file path again, in case it became absolute.
	if isWindowsDrivePath(path) {
		path = "/" + strings.ToUpper(string(path[0])) + path[1:]
	}
	path = filepath.ToSlash(path)
	u := url.URL{
		Scheme: fileScheme,
		Path:   path,
	}
	return URI(u.String())
}

// isWindowsDrivePath returns true if the file path is of the form used by
// Windows. We check if the path begins with a drive letter, followed by a ":".
// For example: C:/x/y/z.
func isWindowsDrivePath(path string) bool {
	if len(path) < 3 {
		return false
	}
	return unicode.IsLetter(rune(path[0])) && path[1] == ':'
}

// isWindowsDriveURI returns true if the file URI is of the format used by
// Windows URIs. The url.Parse package does not specially handle Windows paths
// (see golang/go#6027), so we check if the URI path has a drive prefix (e.g. "/C:").
func isWindowsDriveURIPath(uri string) bool {
	if len(uri) < 4 {
		return false
	}
	return uri[0] == '/' && unicode.IsLetter(rune(uri[1])) && uri[2] == ':'
}
<|endoftext|>