<commit_before>// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package apidApigeeSync

import (
	"github.com/30x/apid-core"
	"github.com/apigee-labs/transicator/common"
)

const (
	LISTENER_TABLE_APID_CLUSTER = "edgex.apid_cluster"
	LISTENER_TABLE_DATA_SCOPE   = "edgex.data_scope"
)

func processSnapshot(snapshot *common.Snapshot) {

	var prevDb string
	if apidInfo.LastSnapshot != "" && apidInfo.LastSnapshot != snapshot.SnapshotInfo {
		log.Debugf("Release snapshot for {%s}. Switching to version {%s}",
			apidInfo.LastSnapshot , snapshot.SnapshotInfo)
		prevDb = apidInfo.LastSnapshot
	} else {
		log.Debugf("Process snapshot for version {%s}",
			snapshot.SnapshotInfo)
	}
	db, err := dataService.DBVersion(snapshot.SnapshotInfo)
	if err != nil {
		log.Panicf("Unable to access database: %v", err)
	}

	processSqliteSnapshot(db)

	//update apid instance info
	apidInfo.LastSnapshot = snapshot.SnapshotInfo
	err = updateApidInstanceInfo()
	if err != nil {
		log.Panicf("Unable to update instance info: %v", err)
	}

	setDB(db)
	log.Debugf("Snapshot processed: %s", snapshot.SnapshotInfo)

	// Releases the DB, when the Connection reference count reaches 0.
	if prevDb != "" {
		dataService.ReleaseDB(prevDb)
	}
}

func processSqliteSnapshot(db apid.DB) {

	var numApidClusters int
	tx, err := db.Begin()
	if err != nil {
		log.Panicf("Unable to open DB txn: %v", err)
	}

	err = tx.QueryRow("SELECT COUNT(*) FROM edgex_apid_cluster").Scan(&numApidClusters)
	if err != nil {
		log.Panicf("Unable to read database: %s", err.Error())
	}

	if numApidClusters != 1 {
		log.Panic("Illegal state for apid_cluster. Must be a single row.")
	}

	prep, err := tx.Prepare("ALTER TABLE edgex_apid_cluster ADD COLUMN last_sequence text DEFAULT ''")
	if err != nil {
		if err.Error() == "duplicate column name: last_sequence" {
			tx.Rollback()
			return
		} else {
			log.Panicf("Unable to create last_sequence column on DB.  Unrecoverable error ", err)
		}
	}

	_, err = prep.Exec()
	if err != nil {
		log.Debugf("Snapshot processing DB exec failed. Err: %v", err)
		prep.Close()
		tx.Rollback()
		return
	}
	prep.Close()
	tx.Commit()

}

func processChangeList(changes *common.ChangeList) bool {

	ok := false

	tx, err := getDB().Begin()
	if err != nil {
		log.Panicf("Error processing ChangeList: %v", err)
		return ok
	}
	defer tx.Rollback()

	log.Debugf("apigeeSyncEvent: %d changes", len(changes.Changes))

	for _, change := range changes.Changes {
		if change.Table == LISTENER_TABLE_APID_CLUSTER {
			log.Panicf("illegal operation: %s for %s", change.Operation, change.Table)
		}
		switch change.Operation {
		case common.Insert:
			ok = insert(change.Table, []common.Row{change.NewRow}, tx)
		case common.Update:
			if change.Table == LISTENER_TABLE_DATA_SCOPE {
				log.Panicf("illegal operation: %s for %s", change.Operation, change.Table)
			}
			ok = update(change.Table, []common.Row{change.OldRow}, []common.Row{change.NewRow}, tx)
		case common.Delete:
			ok = _delete(change.Table, []common.Row{change.OldRow}, tx)
		}
		if !ok {
			log.Error("Sql Operation error. Operation rollbacked")
			return ok
		}
	}

	err = tx.Commit()
	if err != nil {
		log.Panicf("Error processing ChangeList: %v", err)
		return false
	}

	return ok
}
<commit_msg>Ensure Query and Insert occur in a single txn.<commit_after>// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package apidApigeeSync

import (
	"github.com/30x/apid-core"
	"github.com/apigee-labs/transicator/common"
)

const (
	LISTENER_TABLE_APID_CLUSTER = "edgex.apid_cluster"
	LISTENER_TABLE_DATA_SCOPE   = "edgex.data_scope"
)

func processSnapshot(snapshot *common.Snapshot) {

	var prevDb string
	if apidInfo.LastSnapshot != "" && apidInfo.LastSnapshot != snapshot.SnapshotInfo {
		log.Debugf("Release snapshot for {%s}. Switching to version {%s}",
			apidInfo.LastSnapshot , snapshot.SnapshotInfo)
		prevDb = apidInfo.LastSnapshot
	} else {
		log.Debugf("Process snapshot for version {%s}",
			snapshot.SnapshotInfo)
	}
	db, err := dataService.DBVersion(snapshot.SnapshotInfo)
	if err != nil {
		log.Panicf("Unable to access database: %v", err)
	}

	processSqliteSnapshot(db)

	//update apid instance info
	apidInfo.LastSnapshot = snapshot.SnapshotInfo
	err = updateApidInstanceInfo()
	if err != nil {
		log.Panicf("Unable to update instance info: %v", err)
	}

	setDB(db)
	log.Debugf("Snapshot processed: %s", snapshot.SnapshotInfo)

	// Releases the DB, when the Connection reference count reaches 0.
	if prevDb != "" {
		dataService.ReleaseDB(prevDb)
	}
}

func processSqliteSnapshot(db apid.DB) {

	var numApidClusters int
	tx, err := db.Begin()
	if err != nil {
		log.Panicf("Unable to open DB txn: {%v}", err.Error())
	}

	err = tx.QueryRow("SELECT COUNT(*) FROM edgex_apid_cluster").Scan(&numApidClusters)
	if err != nil {
		log.Panicf("Unable to read database: {%s}", err.Error())
	}

	if numApidClusters != 1 {
		log.Panic("Illegal state for apid_cluster. Must be a single row.")
	}

	prep, err := tx.Prepare("ALTER TABLE edgex_apid_cluster ADD COLUMN last_sequence text DEFAULT ''")
	if err != nil {
		if err.Error() == "duplicate column name: last_sequence" {
			tx.Rollback()
			return
		} else {
			log.Panicf("Unable to create last_sequence column on DB.  Error {%v}", err.Error())
		}
	}

	_, err = prep.Exec()
	if err != nil {
		log.Errorf("Snapshot processing DB exec failed. Err: {%v}", err)
		prep.Close()
		tx.Rollback()
		return
	}
	prep.Close()
	tx.Commit()

}

func processChangeList(changes *common.ChangeList) bool {

	ok := false

	tx, err := getDB().Begin()
	if err != nil {
		log.Panicf("Error processing ChangeList: %v", err)
		return ok
	}
	defer tx.Rollback()

	log.Debugf("apigeeSyncEvent: %d changes", len(changes.Changes))

	for _, change := range changes.Changes {
		if change.Table == LISTENER_TABLE_APID_CLUSTER {
			log.Panicf("illegal operation: %s for %s", change.Operation, change.Table)
		}
		switch change.Operation {
		case common.Insert:
			ok = insert(change.Table, []common.Row{change.NewRow}, tx)
		case common.Update:
			if change.Table == LISTENER_TABLE_DATA_SCOPE {
				log.Panicf("illegal operation: %s for %s", change.Operation, change.Table)
			}
			ok = update(change.Table, []common.Row{change.OldRow}, []common.Row{change.NewRow}, tx)
		case common.Delete:
			ok = _delete(change.Table, []common.Row{change.OldRow}, tx)
		}
		if !ok {
			log.Error("Sql Operation error. Operation rollbacked")
			return ok
		}
	}

	err = tx.Commit()
	if err != nil {
		log.Panicf("Error processing ChangeList: %v", err)
		return false
	}

	return ok
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/base64"
	"github.com/zvin/gocairo"
	"io/ioutil"
	"math"
	"strings"
	"sync"
)

const (
	WIDTH  = 2000
	HEIGHT = 3000
)

var (
	Locations      map[string]*Location
	LocationsMutex sync.RWMutex
)

//func Base64Encode(data []byte) *bytes.Buffer {
func Base64Encode(data string) string {
	bb := &bytes.Buffer{}
	encoder := base64.NewEncoder(base64.StdEncoding, bb)
	encoder.Write([]byte(data))
	encoder.Close()
	return bb.String()
}

func SaveAllLocations() {
	Log.Printf("SaveAllLocations wants locations rlock.")
	LocationsMutex.RLock()
	Log.Printf("SaveAllLocations got locations rlock.")
	defer func() {
		LocationsMutex.RUnlock()
		Log.Printf("SaveAllLocations released locations rlock.")
	}()
	for _, location := range Locations {
		Log.Printf("SaveAllLocations wants %v lock.", location.Url)
		location.Mutex.Lock()
		Log.Printf("SaveAllLocations got %v lock.", location.Url)
		location.Save()
		location.Mutex.Unlock()
		Log.Printf("SaveAllLocations released %v lock.", location.Url)
	}
}

type Location struct {
	Url      string
	Users    []*User
	FileName string
	Surface  *cairo.Surface
	delta    []interface{}
	Mutex    sync.RWMutex
}

func init() {
	Locations = make(map[string]*Location)
}

func GetLocation(url string) *Location {
	Log.Printf("GetLocation wants locations lock.")
	LocationsMutex.Lock()
	Log.Printf("GetLocation got locations lock.")
	defer func() {
		LocationsMutex.Unlock()
		Log.Printf("GetLocation released locations lock.")
	}()
	location, present := Locations[url]
	if present {
		return location
	} else {
		location = NewLocation(url)
	}
	return location
}

func MinInt(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func NewLocation(url string) *Location {
	loc := new(Location)
	loc.Url = url
	Locations[url] = loc
	b64fname := Base64Encode(url)
	b64fname = b64fname[:MinInt(len(b64fname), 251)]
	loc.FileName = "img/" + strings.Replace(b64fname, "/", "_", -1) + ".png" // filename
	Log.Printf("filename: %v", loc.FileName)
	loc.Surface = cairo.NewSurfaceFromPNG(loc.FileName)
	if loc.Surface.SurfaceStatus() != 0 {
		loc.Surface.Finish()
		loc.Surface.Destroy()
		loc.Surface = cairo.NewSurface(cairo.FormatArgB32, WIDTH, HEIGHT)
	}
	loc.Surface.SetSourceRGB(0, 0, 0)
	return loc
}

func (location *Location) AddUser(user *User) {
	location.Users = append(location.Users, user)
}

func (location *Location) RemoveUser(user *User) {
	location.Users = Remove(location.Users, user)
	if len(location.Users) == 0 {
		location.Save()
		Log.Printf("RemoveUser user %v location %v wants locations lock.", user.UserId, location.Url)
		LocationsMutex.Lock()
		Log.Printf("RemoveUser user %v location %v got locations lock.", user.UserId, location.Url)
		delete(Locations, location.Url)
		LocationsMutex.Unlock()
		Log.Printf("RemoveUser user %v location %v released locations lock.", user.UserId, location.Url)
		location.Surface.Finish()
		location.Surface.Destroy()
	}
}

func MaxFloat(a, b float64) float64 {
	if a > b {
		return a
	}
	return b
}

func Distance(x1, y1, x2, y2 int) float64 {
	return math.Sqrt(float64((x1 - x2) ^ 2 + (y1 - y2) ^ 2))
}

func (location *Location) DrawLine(x1, y1, x2, y2, duration, red, green, blue int, use_pen bool) {
	//    fmt.Printf("draw line duration %d\n", duration)
	if duration <= 0 {
		return
	}
	location.delta = append(location.delta, []interface{}{x1, y1, x2, y2, duration, red, green, blue, use_pen})
	d := Distance(x1, y1, x2, y2)
	speed := MaxFloat(d/float64(duration), 1)
	if !use_pen { // not use_pen: use eraser
		location.Surface.SetOperator(cairo.OperatorDestOut)
	} else {
		location.Surface.SetOperator(cairo.OperatorOver)
		location.Surface.SetSourceRGB(float64(red)/255., float64(green)/255., float64(blue)/255.)
	}
	location.Surface.SetLineWidth(1. / (speed * 3))
	location.Surface.MoveTo(float64(x1), float64(y1))
	location.Surface.LineTo(float64(x2), float64(y2))
	location.Surface.Stroke()
}

func (location *Location) GetImageBytes() []byte {
	data, err := ioutil.ReadFile(location.FileName)
	if err != nil {
		Log.Println("Error reading file ", err)
	}
	return data
}

func (location *Location) GetDelta() []interface{} {
	return location.delta
}

func (location *Location) Save() {
	if len(location.delta) > 0 {
		Log.Printf("save %s (delta %d)\n", location.Url, len(location.delta))
		location.Surface.WriteToPNG(location.FileName) // Output to PNG
		location.delta = nil
	}
}

func Remove(list []*User, value *User) []*User {
	var i int
	var elem *User
	for i, elem = range list {
		if elem == value {
			break
		}
	}
	return append(list[:i], list[i+1:]...)
}
<commit_msg>try to avoid interlocking<commit_after>package main

import (
	"bytes"
	"encoding/base64"
	"github.com/zvin/gocairo"
	"io/ioutil"
	"math"
	"strings"
	"sync"
)

const (
	WIDTH  = 2000
	HEIGHT = 3000
)

var (
	Locations      map[string]*Location
	LocationsMutex sync.RWMutex
)

//func Base64Encode(data []byte) *bytes.Buffer {
func Base64Encode(data string) string {
	bb := &bytes.Buffer{}
	encoder := base64.NewEncoder(base64.StdEncoding, bb)
	encoder.Write([]byte(data))
	encoder.Close()
	return bb.String()
}

func SaveAllLocations() {
//	Log.Printf("SaveAllLocations wants locations rlock.")
//	LocationsMutex.RLock()
//	Log.Printf("SaveAllLocations got locations rlock.")
//	defer func() {
//		LocationsMutex.RUnlock()
//		Log.Printf("SaveAllLocations released locations rlock.")
//	}()
	for _, location := range Locations {
		Log.Printf("SaveAllLocations wants %v lock.", location.Url)
		location.Mutex.Lock()
		Log.Printf("SaveAllLocations got %v lock.", location.Url)
		location.Save()
		location.Mutex.Unlock()
		Log.Printf("SaveAllLocations released %v lock.", location.Url)
	}
}

type Location struct {
	Url      string
	Users    []*User
	FileName string
	Surface  *cairo.Surface
	delta    []interface{}
	Mutex    sync.RWMutex
}

func init() {
	Locations = make(map[string]*Location)
}

func GetLocation(url string) *Location {
	Log.Printf("GetLocation wants locations lock.")
	LocationsMutex.Lock()
	Log.Printf("GetLocation got locations lock.")
	defer func() {
		LocationsMutex.Unlock()
		Log.Printf("GetLocation released locations lock.")
	}()
	location, present := Locations[url]
	if present {
		return location
	} else {
		location = NewLocation(url)
	}
	return location
}

func MinInt(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func NewLocation(url string) *Location {
	loc := new(Location)
	loc.Url = url
	Locations[url] = loc
	b64fname := Base64Encode(url)
	b64fname = b64fname[:MinInt(len(b64fname), 251)]
	loc.FileName = "img/" + strings.Replace(b64fname, "/", "_", -1) + ".png" // filename
	Log.Printf("filename: %v", loc.FileName)
	loc.Surface = cairo.NewSurfaceFromPNG(loc.FileName)
	if loc.Surface.SurfaceStatus() != 0 {
		loc.Surface.Finish()
		loc.Surface.Destroy()
		loc.Surface = cairo.NewSurface(cairo.FormatArgB32, WIDTH, HEIGHT)
	}
	loc.Surface.SetSourceRGB(0, 0, 0)
	return loc
}

func (location *Location) AddUser(user *User) {
	location.Users = append(location.Users, user)
}

func (location *Location) RemoveUser(user *User) {
	location.Users = Remove(location.Users, user)
	if len(location.Users) == 0 {
		location.Save()
		Log.Printf("RemoveUser user %v location %v wants locations lock.", user.UserId, location.Url)
		LocationsMutex.Lock()
		Log.Printf("RemoveUser user %v location %v got locations lock.", user.UserId, location.Url)
		delete(Locations, location.Url)
		LocationsMutex.Unlock()
		Log.Printf("RemoveUser user %v location %v released locations lock.", user.UserId, location.Url)
		location.Surface.Finish()
		location.Surface.Destroy()
	}
}

func MaxFloat(a, b float64) float64 {
	if a > b {
		return a
	}
	return b
}

func Distance(x1, y1, x2, y2 int) float64 {
	return math.Sqrt(float64((x1 - x2) ^ 2 + (y1 - y2) ^ 2))
}

func (location *Location) DrawLine(x1, y1, x2, y2, duration, red, green, blue int, use_pen bool) {
	//    fmt.Printf("draw line duration %d\n", duration)
	if duration <= 0 {
		return
	}
	location.delta = append(location.delta, []interface{}{x1, y1, x2, y2, duration, red, green, blue, use_pen})
	d := Distance(x1, y1, x2, y2)
	speed := MaxFloat(d/float64(duration), 1)
	if !use_pen { // not use_pen: use eraser
		location.Surface.SetOperator(cairo.OperatorDestOut)
	} else {
		location.Surface.SetOperator(cairo.OperatorOver)
		location.Surface.SetSourceRGB(float64(red)/255., float64(green)/255., float64(blue)/255.)
	}
	location.Surface.SetLineWidth(1. / (speed * 3))
	location.Surface.MoveTo(float64(x1), float64(y1))
	location.Surface.LineTo(float64(x2), float64(y2))
	location.Surface.Stroke()
}

func (location *Location) GetImageBytes() []byte {
	data, err := ioutil.ReadFile(location.FileName)
	if err != nil {
		Log.Println("Error reading file ", err)
	}
	return data
}

func (location *Location) GetDelta() []interface{} {
	return location.delta
}

func (location *Location) Save() {
	if len(location.delta) > 0 {
		Log.Printf("save %s (delta %d)\n", location.Url, len(location.delta))
		location.Surface.WriteToPNG(location.FileName) // Output to PNG
		location.delta = nil
	}
}

func Remove(list []*User, value *User) []*User {
	var i int
	var elem *User
	for i, elem = range list {
		if elem == value {
			break
		}
	}
	return append(list[:i], list[i+1:]...)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"strings"

	"github.com/gosexy/gettext"
	"github.com/lxc/lxd"
	"github.com/olekukonko/tablewriter"
)

type listCmd struct{}

func (c *listCmd) showByDefault() bool {
	return true
}

func (c *listCmd) usage() string {
	return gettext.Gettext(
		"Lists the available resources.\n" +
			"\n" +
			"lxc list [resource]\n" +
			"\n" +
			"Currently resource must be a defined remote, and list only lists\n" +
			"the defined containers.\n")

}

func (c *listCmd) flags() {}

func listContainers(d *lxd.Client, cts []string, showsnaps bool) error {
	data := [][]string{}

	for _, ct := range cts {
		// get more information
		c, err := d.ContainerStatus(ct)
		d := []string{}
		if err == nil {
			d = []string{ct, c.Status.State}
		} else {
			return fmt.Errorf(gettext.Gettext("Container not found"))
		}

		if c.Status.State == "RUNNING" {
			ipv4s := []string{}
			ipv6s := []string{}
			for _, ip := range c.Status.Ips {
				if ip.Interface == "lo" {
					continue
				}

				if ip.Protocol == "IPV6" {
					ipv6s = append(ipv6s, ip.Address)
				} else {
					ipv4s = append(ipv4s, ip.Address)
				}
			}
			ipv4 := strings.Join(ipv4s, ", ")
			ipv6 := strings.Join(ipv6s, ", ")
			d = append(d, ipv4)
			d = append(d, ipv6)
		} else {
			d = append(d, "")
			d = append(d, "")
		}
		data = append(data, d)
	}

	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"NAME", "STATE", "IPV4", "IPV6"})

	for _, v := range data {
		table.Append(v)
	}

	table.Render() // Send output

	if showsnaps {
		cName := cts[0]
		first_snapshot := true
		snaps, err := d.ListSnapshots(cName)
		if err != nil {
			return nil
		}
		for _, snap := range snaps {
			if first_snapshot {
				fmt.Printf("Snapshots:\n")
			}
			fmt.Printf("  %s\n", snap)
			first_snapshot = false
		}
	}
	return nil
}

func (c *listCmd) run(config *lxd.Config, args []string) error {
	if len(args) > 1 {
		return errArgs
	}

	var remote string
	var name string
	if len(args) == 1 {
		remote, name = config.ParseRemoteAndContainer(args[0])
	} else {
		remote = config.DefaultRemote
		name = ""
	}

	d, err := lxd.NewClient(config, remote)
	if err != nil {
		return err
	}

	var cts []string
	showsnapshots := false
	if name == "" {
		cts, err = d.ListContainers()
		if err != nil {
			return err
		}
	} else {
		showsnapshots = true
		cts = []string{name}
	}

	return listContainers(d, cts, showsnapshots)
}
<commit_msg>only claim a container is not found if it actually isn't<commit_after>package main

import (
	"fmt"
	"net/http"
	"os"
	"strings"

	"github.com/gosexy/gettext"
	"github.com/lxc/lxd"
	"github.com/olekukonko/tablewriter"
)

type listCmd struct{}

func (c *listCmd) showByDefault() bool {
	return true
}

func (c *listCmd) usage() string {
	return gettext.Gettext(
		"Lists the available resources.\n" +
			"\n" +
			"lxc list [resource]\n" +
			"\n" +
			"Currently resource must be a defined remote, and list only lists\n" +
			"the defined containers.\n")

}

func (c *listCmd) flags() {}

func listContainers(d *lxd.Client, cts []string, showsnaps bool) error {
	data := [][]string{}

	for _, ct := range cts {
		// get more information
		c, err := d.ContainerStatus(ct)
		d := []string{}
		if err == nil {
			d = []string{ct, c.Status.State}
		} else if err == lxd.LXDErrors[http.StatusNotFound] {
			return fmt.Errorf(gettext.Gettext("Container not found"))
		} else {
			return err
		}

		if c.Status.State == "RUNNING" {
			ipv4s := []string{}
			ipv6s := []string{}
			for _, ip := range c.Status.Ips {
				if ip.Interface == "lo" {
					continue
				}

				if ip.Protocol == "IPV6" {
					ipv6s = append(ipv6s, ip.Address)
				} else {
					ipv4s = append(ipv4s, ip.Address)
				}
			}
			ipv4 := strings.Join(ipv4s, ", ")
			ipv6 := strings.Join(ipv6s, ", ")
			d = append(d, ipv4)
			d = append(d, ipv6)
		} else {
			d = append(d, "")
			d = append(d, "")
		}
		data = append(data, d)
	}

	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"NAME", "STATE", "IPV4", "IPV6"})

	for _, v := range data {
		table.Append(v)
	}

	table.Render() // Send output

	if showsnaps {
		cName := cts[0]
		first_snapshot := true
		snaps, err := d.ListSnapshots(cName)
		if err != nil {
			return nil
		}
		for _, snap := range snaps {
			if first_snapshot {
				fmt.Printf("Snapshots:\n")
			}
			fmt.Printf("  %s\n", snap)
			first_snapshot = false
		}
	}
	return nil
}

func (c *listCmd) run(config *lxd.Config, args []string) error {
	if len(args) > 1 {
		return errArgs
	}

	var remote string
	var name string
	if len(args) == 1 {
		remote, name = config.ParseRemoteAndContainer(args[0])
	} else {
		remote = config.DefaultRemote
		name = ""
	}

	d, err := lxd.NewClient(config, remote)
	if err != nil {
		return err
	}

	var cts []string
	showsnapshots := false
	if name == "" {
		cts, err = d.ListContainers()
		if err != nil {
			return err
		}
	} else {
		showsnapshots = true
		cts = []string{name}
	}

	return listContainers(d, cts, showsnapshots)
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os/exec"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"../godump978"
	rtl "github.com/jpoirier/gortlsdr"
)

type UAT struct {
	dev     *rtl.Context
	indexID int
}

type ES struct {
	dev     *rtl.Context
	indexID int
}

var UATDev *UAT
var ESDev *ES

var uat_shutdown chan int
var uat_wg *sync.WaitGroup = &sync.WaitGroup{}

var es_shutdown chan int
var es_wg *sync.WaitGroup = &sync.WaitGroup{}

var maxSignalStrength int

func (e *ES) read() {
	defer es_wg.Done()
	log.Println("Entered ES read() ...")
	cmd := exec.Command("/usr/bin/dump1090", "--net", "--device-index", strconv.Itoa(e.indexID))
	err := cmd.Start()
	if err != nil {
		log.Printf("Error executing /usr/bin/dump1090: %s\n", err.Error())
		return
	}
	log.Println("Executed /usr/bin/dump1090 successfully...")
	for {
		select {
		default:
			time.Sleep(1 * time.Second)
		case <-es_shutdown:
			log.Println("ES read(): shutdown msg received, calling cmd.Process.Kill() ...")
			cmd.Process.Kill()
			log.Println("\t kill successful...")
			return
		}
	}
}

func (u *UAT) read() {
	defer uat_wg.Done()
	log.Println("Entered UAT read() ...")
	var buffer = make([]uint8, rtl.DefaultBufLength)
	for {
		select {
		default:
			nRead, err := u.dev.ReadSync(buffer, rtl.DefaultBufLength)
			if err != nil {
				//log.Printf("\tReadSync Failed - error: %s\n", err)
				break
			}
			// log.Printf("\tReadSync %d\n", nRead)
			if nRead > 0 {
				buf := buffer[:nRead]
				godump978.InChan <- buf
			}
		case <-uat_shutdown:
			log.Println("UAT read(): shutdown msg received...")
			return
		}
	}
}

func (e *ES) sdrConfig() (err error) {
	return
}

// Read 978MHz from SDR.
func (u *UAT) sdrConfig() (err error) {
	log.Printf("===== UAT Device name: %s =====\n", rtl.GetDeviceName(u.indexID))
	if u.dev, err = rtl.Open(u.indexID); err != nil {
		log.Printf("\tUAT Open Failed...\n")
		return
	}
	log.Printf("\tGetTunerType: %s\n", u.dev.GetTunerType())

	//---------- Set Tuner Gain ----------
	err = u.dev.SetTunerGainMode(true)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetTunerGainMode Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tSetTunerGainMode Successful\n")
	}

	tgain := 480
	err = u.dev.SetTunerGain(tgain)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetTunerGain Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tSetTunerGain Successful\n")
	}

	//---------- Get/Set Sample Rate ----------
	samplerate := 2083334
	err = u.dev.SetSampleRate(samplerate)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetSampleRate Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tSetSampleRate - rate: %d\n", samplerate)
	}
	log.Printf("\tGetSampleRate: %d\n", u.dev.GetSampleRate())

	//---------- Get/Set Xtal Freq ----------
	rtlFreq, tunerFreq, err := u.dev.GetXtalFreq()
	if err != nil {
		u.dev.Close()
		log.Printf("\tGetXtalFreq Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tGetXtalFreq - Rtl: %d, Tuner: %d\n", rtlFreq, tunerFreq)
	}

	newRTLFreq := 28800000
	newTunerFreq := 28800000
	err = u.dev.SetXtalFreq(newRTLFreq, newTunerFreq)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetXtalFreq Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tSetXtalFreq - Center freq: %d, Tuner freq: %d\n",
			newRTLFreq, newTunerFreq)
	}

	//---------- Get/Set Center Freq ----------
	err = u.dev.SetCenterFreq(978000000)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetCenterFreq 978MHz Failed, error: %s\n", err)
		return
	} else {
		log.Printf("\tSetCenterFreq 978MHz Successful\n")
	}

	log.Printf("\tGetCenterFreq: %d\n", u.dev.GetCenterFreq())

	//---------- Set Bandwidth ----------
	bw := 1000000
	log.Printf("\tSetting Bandwidth: %d\n", bw)
	if err = u.dev.SetTunerBw(bw); err != nil {
		u.dev.Close()
		log.Printf("\tSetTunerBw %d Failed, error: %s\n", bw, err)
		return
	} else {
		log.Printf("\tSetTunerBw %d Successful\n", bw)
	}

	if err = u.dev.ResetBuffer(); err != nil {
		u.dev.Close()
		log.Printf("\tResetBuffer Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tResetBuffer Successful\n")
	}
	//---------- Get/Set Freq Correction ----------
	freqCorr := u.dev.GetFreqCorrection()
	log.Printf("\tGetFreqCorrection: %d\n", freqCorr)
	err = u.dev.SetFreqCorrection(globalSettings.PPM)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetFreqCorrection %d Failed, error: %s\n", globalSettings.PPM, err)
		return
	} else {
		log.Printf("\tSetFreqCorrection %d Successful\n", globalSettings.PPM)
	}
	return
}

// Read from the godump978 channel - on or off.
func uatReader() {
	log.Println("Entered uatReader() ...")
	for {
		uat := <-godump978.OutChan
		o, msgtype := parseInput(uat)
		if o != nil && msgtype != 0 {
			relayMessage(msgtype, o)
		}
	}
}

func (u *UAT) shutdown() {
	log.Println("Entered UAT shutdown() ...")
	close(uat_shutdown) // signal to shutdown
	log.Println("UAT shutdown(): closing device ...")
	u.dev.Close() // preempt the blocking ReadSync call
	log.Println("UAT shutdown(): calling uat_wg.Wait() ...")
	uat_wg.Wait() // Wait for the goroutine to shutdown
	log.Println("UAT shutdown(): uat_wg.Wait() returned...")
}

func (e *ES) shutdown() {
	log.Println("Entered ES shutdown() ...")
	close(es_shutdown) // signal to shutdown
	log.Println("ES shutdown(): calling es_wg.Wait() ...")
	es_wg.Wait() // Wait for the goroutine to shutdown
	log.Println("ES shutdown(): es_wg.Wait() returned...")
}

var devMap = map[int]string{0: "", 1: ""}

// Watch for config/device changes.
func sdrWatcher() {
	for {
		time.Sleep(1 * time.Second)
		count := rtl.GetDeviceCount()
		atomic.StoreUint32(&globalStatus.Devices, uint32(count))
		log.Println("DeviceCount...", count)

		// support two and only two dongles
		if count > 2 {
			count = 2
		}

		// cleanup if necessary
		if count < 1 || (!globalSettings.UAT_Enabled && !globalSettings.ES_Enabled) {
			log.Println("count == 0, doing cleanup if necessary...")
			if UATDev != nil {
				UATDev.shutdown()
				UATDev = nil
			}
			if ESDev != nil {
				ESDev.shutdown()
				ESDev = nil
			}
			continue
		}

		if count == 1 {
			if UATDev != nil && ESDev == nil {
				UATDev.indexID = 0
			} else if UATDev == nil && ESDev != nil {
				ESDev.indexID = 0
			}
		}

		ids := []string{"", ""}
		for i := 0; i < count; i++ {
			// manufact, product, serial, err
			_, _, s, _ := rtl.GetDeviceUsbStrings(i)
			ids[i] = s
		}

		// UAT specific handling
		// When count is one, favor UAT in the case where the user
		// has enabled both UAT and ES via the web interface.
		id := 0
		if globalSettings.UAT_Enabled {
			// log.Println("globalSettings.UAT_Enabled == true")
			if count == 1 {
				if ESDev != nil {
					ESDev.shutdown()
					ESDev = nil
				}
			} else { // count == 2
				if UATDev == nil && ESDev != nil {
					if ESDev.indexID == 0 {
						id = 1
					}
				}
			}

			if UATDev == nil {
				// log.Println("\tUATDev == nil")
				// preference check based on stratux
				// hardware serial when it exists
				serial := ids[id]
				if strings.HasPrefix(serial, "stratux:1090") {
					log.Println("Settings conflict: 978UAT set via WebUI but hardware serial says stratux:1090")
				} else {
					UATDev = &UAT{indexID: id}
					if err := UATDev.sdrConfig(); err != nil {
						log.Printf("UATDev = &UAT{indexID: id} failed: %s\n", err)
						UATDev = nil
					} else {
						uat_shutdown = make(chan int)
						uat_wg.Add(1)
						go UATDev.read()
					}
				}
			}
		} else if UATDev != nil {
			UATDev.shutdown()
			UATDev = nil
			if count == 1 && ESDev != nil {
				ESDev.indexID = 0
			}
		}

		// ES specific handling
		id = 0
		if globalSettings.ES_Enabled {
			// log.Println("globalSettings.ES_Enabled == true")
			if count == 1 {
				if globalSettings.UAT_Enabled {
					// defer to the UAT handler
					goto End
				}
			} else { // count == 2
				if ESDev == nil && UATDev != nil {
					if UATDev.indexID == 0 {
						id = 1
					}
				}
			}

			if ESDev == nil {
				// log.Println("\tESDev == nil")
				// preference check based on stratux
				// hardware serial when it exists
				serial := ids[id]
				if strings.HasPrefix(serial, "stratux:978") {
					log.Println("Settings conflict: 1090ES set via WebUI but hardware serial says stratux:978")
				} else {
					ESDev = &ES{indexID: id}
					if err := ESDev.sdrConfig(); err != nil {
						log.Printf("ESDev = &ES{indexID: id} failed: %s\n", err)
						ESDev = nil
					} else {
						es_shutdown = make(chan int)
						es_wg.Add(1)
						go ESDev.read()
					}
				}
			}
		} else if ESDev != nil {
			ESDev.shutdown()
			ESDev = nil
			if count == 1 && UATDev != nil {
				UATDev.indexID = 0
			}
		}
	End:
	}
}

func sdrInit() {
	go sdrWatcher()
	go uatReader()
	godump978.Dump978Init()
	go godump978.ProcessDataFromChannel()
}
<commit_msg>Fixed zombie process issue.<commit_after>package main

import (
	"log"
	"os/exec"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"../godump978"
	rtl "github.com/jpoirier/gortlsdr"
)

type UAT struct {
	dev     *rtl.Context
	indexID int
}

type ES struct {
	dev     *rtl.Context
	indexID int
}

var UATDev *UAT
var ESDev *ES

var uat_shutdown chan int
var uat_wg *sync.WaitGroup = &sync.WaitGroup{}

var es_shutdown chan int
var es_wg *sync.WaitGroup = &sync.WaitGroup{}

var maxSignalStrength int

func (e *ES) read() {
	defer es_wg.Done()
	log.Println("Entered ES read() ...")
	cmd := exec.Command("/usr/bin/dump1090", "--net", "--device-index", strconv.Itoa(e.indexID))
	err := cmd.Start()
	if err != nil {
		log.Printf("Error executing /usr/bin/dump1090: %s\n", err.Error())
		return
	}
	log.Println("Executed /usr/bin/dump1090 successfully...")
	for {
		select {
		default:
			time.Sleep(1 * time.Second)
		case <-es_shutdown:
			log.Println("ES read(): shutdown msg received, calling cmd.Process.Kill() ...")
			err := cmd.Process.Kill()
			if err != nil {
				log.Println("\t couldn't kill dump1090: %s", err.Error)
			} else {
				cmd.Wait()
				log.Println("\t kill successful...")
			}
			return
		}
	}
}

func (u *UAT) read() {
	defer uat_wg.Done()
	log.Println("Entered UAT read() ...")
	var buffer = make([]uint8, rtl.DefaultBufLength)
	for {
		select {
		default:
			nRead, err := u.dev.ReadSync(buffer, rtl.DefaultBufLength)
			if err != nil {
				//log.Printf("\tReadSync Failed - error: %s\n", err)
				break
			}
			// log.Printf("\tReadSync %d\n", nRead)
			if nRead > 0 {
				buf := buffer[:nRead]
				godump978.InChan <- buf
			}
		case <-uat_shutdown:
			log.Println("UAT read(): shutdown msg received...")
			return
		}
	}
}

func (e *ES) sdrConfig() (err error) {
	return
}

// Read 978MHz from SDR.
func (u *UAT) sdrConfig() (err error) {
	log.Printf("===== UAT Device name: %s =====\n", rtl.GetDeviceName(u.indexID))
	if u.dev, err = rtl.Open(u.indexID); err != nil {
		log.Printf("\tUAT Open Failed...\n")
		return
	}
	log.Printf("\tGetTunerType: %s\n", u.dev.GetTunerType())

	//---------- Set Tuner Gain ----------
	err = u.dev.SetTunerGainMode(true)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetTunerGainMode Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tSetTunerGainMode Successful\n")
	}

	tgain := 480
	err = u.dev.SetTunerGain(tgain)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetTunerGain Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tSetTunerGain Successful\n")
	}

	//---------- Get/Set Sample Rate ----------
	samplerate := 2083334
	err = u.dev.SetSampleRate(samplerate)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetSampleRate Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tSetSampleRate - rate: %d\n", samplerate)
	}
	log.Printf("\tGetSampleRate: %d\n", u.dev.GetSampleRate())

	//---------- Get/Set Xtal Freq ----------
	rtlFreq, tunerFreq, err := u.dev.GetXtalFreq()
	if err != nil {
		u.dev.Close()
		log.Printf("\tGetXtalFreq Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tGetXtalFreq - Rtl: %d, Tuner: %d\n", rtlFreq, tunerFreq)
	}

	newRTLFreq := 28800000
	newTunerFreq := 28800000
	err = u.dev.SetXtalFreq(newRTLFreq, newTunerFreq)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetXtalFreq Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tSetXtalFreq - Center freq: %d, Tuner freq: %d\n",
			newRTLFreq, newTunerFreq)
	}

	//---------- Get/Set Center Freq ----------
	err = u.dev.SetCenterFreq(978000000)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetCenterFreq 978MHz Failed, error: %s\n", err)
		return
	} else {
		log.Printf("\tSetCenterFreq 978MHz Successful\n")
	}

	log.Printf("\tGetCenterFreq: %d\n", u.dev.GetCenterFreq())

	//---------- Set Bandwidth ----------
	bw := 1000000
	log.Printf("\tSetting Bandwidth: %d\n", bw)
	if err = u.dev.SetTunerBw(bw); err != nil {
		u.dev.Close()
		log.Printf("\tSetTunerBw %d Failed, error: %s\n", bw, err)
		return
	} else {
		log.Printf("\tSetTunerBw %d Successful\n", bw)
	}

	if err = u.dev.ResetBuffer(); err != nil {
		u.dev.Close()
		log.Printf("\tResetBuffer Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tResetBuffer Successful\n")
	}
	//---------- Get/Set Freq Correction ----------
	freqCorr := u.dev.GetFreqCorrection()
	log.Printf("\tGetFreqCorrection: %d\n", freqCorr)
	err = u.dev.SetFreqCorrection(globalSettings.PPM)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetFreqCorrection %d Failed, error: %s\n", globalSettings.PPM, err)
		return
	} else {
		log.Printf("\tSetFreqCorrection %d Successful\n", globalSettings.PPM)
	}
	return
}

// Read from the godump978 channel - on or off.
func uatReader() {
	log.Println("Entered uatReader() ...")
	for {
		uat := <-godump978.OutChan
		o, msgtype := parseInput(uat)
		if o != nil && msgtype != 0 {
			relayMessage(msgtype, o)
		}
	}
}

func (u *UAT) shutdown() {
	log.Println("Entered UAT shutdown() ...")
	close(uat_shutdown) // signal to shutdown
	log.Println("UAT shutdown(): closing device ...")
	u.dev.Close() // preempt the blocking ReadSync call
	log.Println("UAT shutdown(): calling uat_wg.Wait() ...")
	uat_wg.Wait() // Wait for the goroutine to shutdown
	log.Println("UAT shutdown(): uat_wg.Wait() returned...")
}

func (e *ES) shutdown() {
	log.Println("Entered ES shutdown() ...")
	close(es_shutdown) // signal to shutdown
	log.Println("ES shutdown(): calling es_wg.Wait() ...")
	es_wg.Wait() // Wait for the goroutine to shutdown
	log.Println("ES shutdown(): es_wg.Wait() returned...")
}

var devMap = map[int]string{0: "", 1: ""}

// Watch for config/device changes.
func sdrWatcher() {
	for {
		time.Sleep(1 * time.Second)
		count := rtl.GetDeviceCount()
		atomic.StoreUint32(&globalStatus.Devices, uint32(count))
		log.Println("DeviceCount...", count)

		// support two and only two dongles
		if count > 2 {
			count = 2
		}

		// cleanup if necessary
		if count < 1 || (!globalSettings.UAT_Enabled && !globalSettings.ES_Enabled) {
			log.Println("count == 0, doing cleanup if necessary...")
			if UATDev != nil {
				UATDev.shutdown()
				UATDev = nil
			}
			if ESDev != nil {
				ESDev.shutdown()
				ESDev = nil
			}
			continue
		}

		if count == 1 {
			if UATDev != nil && ESDev == nil {
				UATDev.indexID = 0
			} else if UATDev == nil && ESDev != nil {
				ESDev.indexID = 0
			}
		}

		ids := []string{"", ""}
		for i := 0; i < count; i++ {
			// manufact, product, serial, err
			_, _, s, _ := rtl.GetDeviceUsbStrings(i)
			ids[i] = s
		}

		// UAT specific handling
		// When count is one, favor UAT in the case where the user
		// has enabled both UAT and ES via the web interface.
		id := 0
		if globalSettings.UAT_Enabled {
			// log.Println("globalSettings.UAT_Enabled == true")
			if count == 1 {
				if ESDev != nil {
					ESDev.shutdown()
					ESDev = nil
				}
			} else { // count == 2
				if UATDev == nil && ESDev != nil {
					if ESDev.indexID == 0 {
						id = 1
					}
				}
			}

			if UATDev == nil {
				// log.Println("\tUATDev == nil")
				// preference check based on stratux
				// hardware serial when it exists
				serial := ids[id]
				if strings.HasPrefix(serial, "stratux:1090") {
					log.Println("Settings conflict: 978UAT set via WebUI but hardware serial says stratux:1090")
				} else {
					UATDev = &UAT{indexID: id}
					if err := UATDev.sdrConfig(); err != nil {
						log.Printf("UATDev = &UAT{indexID: id} failed: %s\n", err)
						UATDev = nil
					} else {
						uat_shutdown = make(chan int)
						uat_wg.Add(1)
						go UATDev.read()
					}
				}
			}
		} else if UATDev != nil {
			UATDev.shutdown()
			UATDev = nil
			if count == 1 && ESDev != nil {
				ESDev.indexID = 0
			}
		}

		// ES specific handling
		id = 0
		if globalSettings.ES_Enabled {
			// log.Println("globalSettings.ES_Enabled == true")
			if count == 1 {
				if globalSettings.UAT_Enabled {
					// defer to the UAT handler
					goto End
				}
			} else { // count == 2
				if ESDev == nil && UATDev != nil {
					if UATDev.indexID == 0 {
						id = 1
					}
				}
			}

			if ESDev == nil {
				// log.Println("\tESDev == nil")
				// preference check based on stratux
				// hardware serial when it exists
				serial := ids[id]
				if strings.HasPrefix(serial, "stratux:978") {
					log.Println("Settings conflict: 1090ES set via WebUI but hardware serial says stratux:978")
				} else {
					ESDev = &ES{indexID: id}
					if err := ESDev.sdrConfig(); err != nil {
						log.Printf("ESDev = &ES{indexID: id} failed: %s\n", err)
						ESDev = nil
					} else {
						es_shutdown = make(chan int)
						es_wg.Add(1)
						go ESDev.read()
					}
				}
			}
		} else if ESDev != nil {
			ESDev.shutdown()
			ESDev = nil
			if count == 1 && UATDev != nil {
				UATDev.indexID = 0
			}
		}
	End:
	}
}

func sdrInit() {
	go sdrWatcher()
	go uatReader()
	godump978.Dump978Init()
	go godump978.ProcessDataFromChannel()
}
<|endoftext|>


<commit_before>package ps

import "testing"

func TestMapImmutable(t *testing.T) {
    // build a couple small maps
    world := NewMap().Set("hello", "world")
    kids := world.Set("hello", "kids")

    // both maps should still retain their data
    if v, _ := world.Lookup("hello"); v != "world" {
        t.Errorf("Set() modified the receiving map")
    }
    if size := world.Size(); size != 1 {
        t.Errorf("world size is not 1 : %d", size)
    }
    if v, _ := kids.Lookup("hello"); v != "kids" {
        t.Errorf("Set() did not modify the resulting map")
    }
    if size := kids.Size(); size != 1 {
        t.Errorf("kids size is not 1 : %d", size)
    }

    // both maps have the right keys
    if keys := world.Keys(); len(keys) != 1 || keys[0] != "hello" {
        t.Errorf("world has the wrong keys: %#v", keys)
    }
    if keys := kids.Keys(); len(keys) != 1 || keys[0] != "hello" {
        t.Errorf("kids has the wrong keys: %#v", keys)
    }

    // test deletion
    empty := kids.Delete("hello")
    if size := empty.Size(); size != 0 {
        t.Errorf("empty size is not 1 : %d", size)
    }
    if keys := empty.Keys(); len(keys) != 0 {
        t.Errorf("empty has the wrong keys: %#v", keys)
    }
}

func BenchmarkMapSet(b *testing.B) {
    m := NewMap()
    for i := 0; i < b.N; i++ {
        m = m.Set("foo", i)
    }
}

func BenchmarkMapDelete(b *testing.B) {
    m := NewMap().Set("key", "value")
    for i := 0; i < b.N; i++ {
        m.Delete("key")
    }
}
<commit_msg>Test for maps with multiple keys<commit_after>package ps

import "testing"
import "sort"

func TestMapImmutable(t *testing.T) {
    // build a couple small maps
    world := NewMap().Set("hello", "world")
    kids := world.Set("hello", "kids")

    // both maps should still retain their data
    if v, _ := world.Lookup("hello"); v != "world" {
        t.Errorf("Set() modified the receiving map")
    }
    if size := world.Size(); size != 1 {
        t.Errorf("world size is not 1 : %d", size)
    }
    if v, _ := kids.Lookup("hello"); v != "kids" {
        t.Errorf("Set() did not modify the resulting map")
    }
    if size := kids.Size(); size != 1 {
        t.Errorf("kids size is not 1 : %d", size)
    }

    // both maps have the right keys
    if keys := world.Keys(); len(keys) != 1 || keys[0] != "hello" {
        t.Errorf("world has the wrong keys: %#v", keys)
    }
    if keys := kids.Keys(); len(keys) != 1 || keys[0] != "hello" {
        t.Errorf("kids has the wrong keys: %#v", keys)
    }

    // test deletion
    empty := kids.Delete("hello")
    if size := empty.Size(); size != 0 {
        t.Errorf("empty size is not 1 : %d", size)
    }
    if keys := empty.Keys(); len(keys) != 0 {
        t.Errorf("empty has the wrong keys: %#v", keys)
    }
}

func TestMapMultipleKeys(t *testing.T) {
    m := NewMap().Set("one", 1).Set("two", 2).Set("three", 3)

    // do we have the right number of keys?
    keys := m.Keys()
    if len(keys) != 3 {
        t.Logf("wrong size keys: %d", len(keys))
        t.FailNow()
    }

    // do we have the right keys?
    sort.Strings(keys)
    if keys[0] != "one" {
        t.Errorf("unexpected key: %s", keys[0])
    }
    if keys[1] != "three" {
        t.Errorf("unexpected key: %s", keys[1])
    }
    if keys[2] != "two" {
        t.Errorf("unexpected key: %s", keys[2])
    }
}

func BenchmarkMapSet(b *testing.B) {
    m := NewMap()
    for i := 0; i < b.N; i++ {
        m = m.Set("foo", i)
    }
}

func BenchmarkMapDelete(b *testing.B) {
    m := NewMap().Set("key", "value")
    for i := 0; i < b.N; i++ {
        m.Delete("key")
    }
}
<|endoftext|>


<commit_before>// Copyright ©2013 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Based on the QRDecomposition class from Jama 1.0.3.

package mat64

import (
	//"fmt"
	"math"
)

type QRFactor struct {
	QR    *Dense
	rDiag []float64
}

// QR computes a QR Decomposition for an m-by-n matrix a with m >= n by Householder
// reflections, the QR decomposition is an m-by-n orthogonal matrix q and an n-by-n
// upper triangular matrix r so that a = q.r. QR will panic with ErrShape if m < n.
//
// The QR decomposition always exists, even if the matrix does not have full rank,
// so QR will never fail unless m < n. The primary use of the QR decomposition is
// in the least squares solution of non-square systems of simultaneous linear equations.
// This will fail if QRIsFullRank() returns false. The matrix a is overwritten by the
// decomposition.
func QR(a *Dense) QRFactor {
	// Initialize.
	m, n := a.Dims()
	if m < n {
		panic(ErrShape)
	}

	qr := a
	rDiag := make([]float64, n)

	// Main loop.
	for k := 0; k < n; k++ {
		// Compute 2-norm of k-th column without under/overflow.
		var norm float64
		for i := k; i < m; i++ {
			norm = math.Hypot(norm, qr.At(i, k))
		}

		if norm != 0 {
			// Form k-th Householder vector.
			if qr.At(k, k) < 0 {
				norm = -norm
			}
			for i := k; i < m; i++ {
				qr.Set(i, k, qr.At(i, k)/norm)
			}
			qr.Set(k, k, qr.At(k, k)+1)

			// Apply transformation to remaining columns.
			for j := k + 1; j < n; j++ {
				var s float64
				for i := k; i < m; i++ {
					s += qr.At(i, k) * qr.At(i, j)
				}
				s /= -qr.At(k, k)
				for i := k; i < m; i++ {
					qr.Set(i, j, qr.At(i, j)+s*qr.At(i, k))
				}
			}
		}
		rDiag[k] = -norm
	}

	return QRFactor{qr, rDiag}
}

// IsFullRank returns whether the R matrix and hence a has full rank.
func (f QRFactor) IsFullRank() bool {
	for _, v := range f.rDiag {
		if v == 0 {
			return false
		}
	}
	return true
}

// H returns the Householder vectors in a lower trapezoidal matrix
// whose columns define the reflections.
func (f QRFactor) H() *Dense {
	qr := f.QR
	m, n := qr.Dims()
	h := NewDense(m, n, nil)
	for i := 0; i < m; i++ {
		for j := 0; j < n; j++ {
			if i >= j {
				h.Set(i, j, qr.At(i, j))
			}
		}
	}
	return h
}

// R returns the upper triangular factor for the QR decomposition.
func (f QRFactor) R() *Dense {
	qr, rDiag := f.QR, f.rDiag
	_, n := qr.Dims()
	r := NewDense(n, n, nil)
	for i, v := range rDiag[:n] {
		for j := 0; j < n; j++ {
			if i < j {
				r.Set(i, j, qr.At(i, j))
			} else if i == j {
				r.Set(i, j, v)
			}
		}
	}
	return r
}

// Q generates and returns the (economy-sized) orthogonal factor.
func (f QRFactor) Q() *Dense {
	qr := f.QR
	m, n := qr.Dims()
	q := NewDense(m, n, nil)

	for k := n - 1; k >= 0; k-- {
		// for i := 0; i < m; i++ {
		// 	q.Set(i, k, 0)
		// }
		q.Set(k, k, 1)
		for j := k; j < n; j++ {
			if qr.At(k, k) != 0 {
				var s float64
				for i := k; i < m; i++ {
					s += qr.At(i, k) * q.At(i, j)
				}
				s /= -qr.At(k, k)
				for i := k; i < m; i++ {
					q.Set(i, j, q.At(i, j)+s*qr.At(i, k))
				}
			}
		}
	}

	return q
}

// Solve computes a least squares solution of a.x = b where b has as many rows as a.
// A matrix x is returned that minimizes the two norm of Q*R*X-B. QRSolve will panic
// if a is not full rank. The matrix b is overwritten during the call.
func (f QRFactor) Solve(b *Dense) (x *Dense) {
	qr := f.QR
	rDiag := f.rDiag
	m, n := qr.Dims()
	bm, bn := b.Dims()
	if bm != m {
		panic(ErrShape)
	}
	if !f.IsFullRank() {
		panic("mat64: matrix is rank deficient")
	}
	nx := bn

	// Compute Y = transpose(Q)*B
	for k := 0; k < n; k++ {
		for j := 0; j < nx; j++ {
			var s float64
			for i := k; i < m; i++ {
				s += qr.At(i, k) * b.At(i, j)
			}
			s /= -qr.At(k, k)

			for i := k; i < m; i++ {
				b.Set(i, j, b.At(i, j)+s*qr.At(i, k))
			}
		}
	}

	// Solve R*X = Y;
	for k := n - 1; k >= 0; k-- {
		for j := 0; j < nx; j++ {
			b.Set(k, j, b.At(k, j)/rDiag[k])
		}
		for i := 0; i < k; i++ {
			for j := 0; j < nx; j++ {
				b.Set(i, j, b.At(i, j)-b.At(k, j)*qr.At(i, k))
			}
		}
	}

	x = NewDense(n, bn, use(b.mat.Data, n*bn))
	return x
}
<commit_msg>Removed commented fmt<commit_after>// Copyright ©2013 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Based on the QRDecomposition class from Jama 1.0.3.

package mat64

import (
	"math"
)

type QRFactor struct {
	QR    *Dense
	rDiag []float64
}

// QR computes a QR Decomposition for an m-by-n matrix a with m >= n by Householder
// reflections, the QR decomposition is an m-by-n orthogonal matrix q and an n-by-n
// upper triangular matrix r so that a = q.r. QR will panic with ErrShape if m < n.
//
// The QR decomposition always exists, even if the matrix does not have full rank,
// so QR will never fail unless m < n. The primary use of the QR decomposition is
// in the least squares solution of non-square systems of simultaneous linear equations.
// This will fail if QRIsFullRank() returns false. The matrix a is overwritten by the
// decomposition.
func QR(a *Dense) QRFactor {
	// Initialize.
	m, n := a.Dims()
	if m < n {
		panic(ErrShape)
	}

	qr := a
	rDiag := make([]float64, n)

	// Main loop.
	for k := 0; k < n; k++ {
		// Compute 2-norm of k-th column without under/overflow.
		var norm float64
		for i := k; i < m; i++ {
			norm = math.Hypot(norm, qr.At(i, k))
		}

		if norm != 0 {
			// Form k-th Householder vector.
			if qr.At(k, k) < 0 {
				norm = -norm
			}
			for i := k; i < m; i++ {
				qr.Set(i, k, qr.At(i, k)/norm)
			}
			qr.Set(k, k, qr.At(k, k)+1)

			// Apply transformation to remaining columns.
			for j := k + 1; j < n; j++ {
				var s float64
				for i := k; i < m; i++ {
					s += qr.At(i, k) * qr.At(i, j)
				}
				s /= -qr.At(k, k)
				for i := k; i < m; i++ {
					qr.Set(i, j, qr.At(i, j)+s*qr.At(i, k))
				}
			}
		}
		rDiag[k] = -norm
	}

	return QRFactor{qr, rDiag}
}

// IsFullRank returns whether the R matrix and hence a has full rank.
func (f QRFactor) IsFullRank() bool {
	for _, v := range f.rDiag {
		if v == 0 {
			return false
		}
	}
	return true
}

// H returns the Householder vectors in a lower trapezoidal matrix
// whose columns define the reflections.
func (f QRFactor) H() *Dense {
	qr := f.QR
	m, n := qr.Dims()
	h := NewDense(m, n, nil)
	for i := 0; i < m; i++ {
		for j := 0; j < n; j++ {
			if i >= j {
				h.Set(i, j, qr.At(i, j))
			}
		}
	}
	return h
}

// R returns the upper triangular factor for the QR decomposition.
func (f QRFactor) R() *Dense {
	qr, rDiag := f.QR, f.rDiag
	_, n := qr.Dims()
	r := NewDense(n, n, nil)
	for i, v := range rDiag[:n] {
		for j := 0; j < n; j++ {
			if i < j {
				r.Set(i, j, qr.At(i, j))
			} else if i == j {
				r.Set(i, j, v)
			}
		}
	}
	return r
}

// Q generates and returns the (economy-sized) orthogonal factor.
func (f QRFactor) Q() *Dense {
	qr := f.QR
	m, n := qr.Dims()
	q := NewDense(m, n, nil)

	for k := n - 1; k >= 0; k-- {
		// for i := 0; i < m; i++ {
		// 	q.Set(i, k, 0)
		// }
		q.Set(k, k, 1)
		for j := k; j < n; j++ {
			if qr.At(k, k) != 0 {
				var s float64
				for i := k; i < m; i++ {
					s += qr.At(i, k) * q.At(i, j)
				}
				s /= -qr.At(k, k)
				for i := k; i < m; i++ {
					q.Set(i, j, q.At(i, j)+s*qr.At(i, k))
				}
			}
		}
	}

	return q
}

// Solve computes a least squares solution of a.x = b where b has as many rows as a.
// A matrix x is returned that minimizes the two norm of Q*R*X-B. QRSolve will panic
// if a is not full rank. The matrix b is overwritten during the call.
func (f QRFactor) Solve(b *Dense) (x *Dense) {
	qr := f.QR
	rDiag := f.rDiag
	m, n := qr.Dims()
	bm, bn := b.Dims()
	if bm != m {
		panic(ErrShape)
	}
	if !f.IsFullRank() {
		panic("mat64: matrix is rank deficient")
	}
	nx := bn

	// Compute Y = transpose(Q)*B
	for k := 0; k < n; k++ {
		for j := 0; j < nx; j++ {
			var s float64
			for i := k; i < m; i++ {
				s += qr.At(i, k) * b.At(i, j)
			}
			s /= -qr.At(k, k)

			for i := k; i < m; i++ {
				b.Set(i, j, b.At(i, j)+s*qr.At(i, k))
			}
		}
	}

	// Solve R*X = Y;
	for k := n - 1; k >= 0; k-- {
		for j := 0; j < nx; j++ {
			b.Set(k, j, b.At(k, j)/rDiag[k])
		}
		for i := 0; i < k; i++ {
			for j := 0; j < nx; j++ {
				b.Set(i, j, b.At(i, j)-b.At(k, j)*qr.At(i, k))
			}
		}
	}

	x = NewDense(n, bn, use(b.mat.Data, n*bn))
	return x
}
<|endoftext|>


<commit_before>// Copyright © 2015 Steve Francia <spf@spf13.com>.
// Copyright 2013 tsuru authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package mem

import (
	"bytes"
	"errors"
	"io"
	"os"
	"path/filepath"
	"sync"
	"sync/atomic"
)

import "time"

const FilePathSeparator = string(filepath.Separator)

type File struct {
	// atomic requires 64-bit alignment for struct field access
	at           int64
	readDirCount int64
	closed       bool
	readOnly     bool
	fileData     *FileData
}

func NewFileHandle(data *FileData) *File {
	return &File{fileData: data}
}

func NewReadOnlyFileHandle(data *FileData) *File {
	return &File{fileData: data, readOnly: true}
}

func (f File) Data() *FileData {
	return f.fileData
}

type FileData struct {
	sync.Mutex
	name    string
	data    []byte
	memDir  Dir
	dir     bool
	mode    os.FileMode
	modtime time.Time
}

func (d *FileData) Name() string {
	d.Lock()
	defer d.Unlock()
	return d.name
}

func CreateFile(name string) *FileData {
	return &FileData{name: name, mode: os.ModeTemporary, modtime: time.Now()}
}

func CreateDir(name string) *FileData {
	return &FileData{name: name, memDir: &DirMap{}, dir: true}
}

func ChangeFileName(f *FileData, newname string) {
	f.Lock()
	f.name = newname
	f.Unlock()
}

func SetMode(f *FileData, mode os.FileMode) {
	f.Lock()
	f.mode = mode
	f.Unlock()
}

func SetModTime(f *FileData, mtime time.Time) {
	f.Lock()
	setModTime(f, mtime)
	f.Unlock()
}

func setModTime(f *FileData, mtime time.Time) {
	f.modtime = mtime
}

func GetFileInfo(f *FileData) *FileInfo {
	return &FileInfo{f}
}

func (f *File) Open() error {
	atomic.StoreInt64(&f.at, 0)
	atomic.StoreInt64(&f.readDirCount, 0)
	f.fileData.Lock()
	f.closed = false
	f.fileData.Unlock()
	return nil
}

func (f *File) Close() error {
	f.fileData.Lock()
	f.closed = true
	if !f.readOnly {
		setModTime(f.fileData, time.Now())
	}
	f.fileData.Unlock()
	return nil
}

func (f *File) Name() string {
	return f.fileData.Name()
}

func (f *File) Stat() (os.FileInfo, error) {
	return &FileInfo{f.fileData}, nil
}

func (f *File) Sync() error {
	return nil
}

func (f *File) Readdir(count int) (res []os.FileInfo, err error) {
	var outLength int64

	f.fileData.Lock()
	files := f.fileData.memDir.Files()[f.readDirCount:]
	if count > 0 {
		if len(files) < count {
			outLength = int64(len(files))
		} else {
			outLength = int64(count)
		}
		if len(files) == 0 {
			err = io.EOF
		}
	} else {
		outLength = int64(len(files))
	}
	f.readDirCount += outLength
	f.fileData.Unlock()

	res = make([]os.FileInfo, outLength)
	for i := range res {
		res[i] = &FileInfo{files[i]}
	}

	return res, err
}

func (f *File) Readdirnames(n int) (names []string, err error) {
	fi, err := f.Readdir(n)
	names = make([]string, len(fi))
	for i, f := range fi {
		_, names[i] = filepath.Split(f.Name())
	}
	return names, err
}

func (f *File) Read(b []byte) (n int, err error) {
	f.fileData.Lock()
	defer f.fileData.Unlock()
	if f.closed == true {
		return 0, ErrFileClosed
	}
	if len(b) > 0 && int(f.at) == len(f.fileData.data) {
		return 0, io.EOF
	}
	if int(f.at) > len(f.fileData.data) {
		return 0, io.ErrUnexpectedEOF
	}
	if len(f.fileData.data)-int(f.at) >= len(b) {
		n = len(b)
	} else {
		n = len(f.fileData.data) - int(f.at)
	}
	copy(b, f.fileData.data[f.at:f.at+int64(n)])
	atomic.AddInt64(&f.at, int64(n))
	return
}

func (f *File) ReadAt(b []byte, off int64) (n int, err error) {
	atomic.StoreInt64(&f.at, off)
	return f.Read(b)
}

func (f *File) Truncate(size int64) error {
	if f.closed == true {
		return ErrFileClosed
	}
	if f.readOnly {
		return &os.PathError{Op: "truncate", Path: f.fileData.name, Err: errors.New("file handle is read only")}
	}
	if size < 0 {
		return ErrOutOfRange
	}
	if size > int64(len(f.fileData.data)) {
		diff := size - int64(len(f.fileData.data))
		f.fileData.data = append(f.fileData.data, bytes.Repeat([]byte{00}, int(diff))...)
	} else {
		f.fileData.data = f.fileData.data[0:size]
	}
	setModTime(f.fileData, time.Now())
	return nil
}

func (f *File) Seek(offset int64, whence int) (int64, error) {
	if f.closed == true {
		return 0, ErrFileClosed
	}
	switch whence {
	case 0:
		atomic.StoreInt64(&f.at, offset)
	case 1:
		atomic.AddInt64(&f.at, int64(offset))
	case 2:
		atomic.StoreInt64(&f.at, int64(len(f.fileData.data))+offset)
	}
	return f.at, nil
}

func (f *File) Write(b []byte) (n int, err error) {
	if f.readOnly {
		return 0, &os.PathError{Op: "write", Path: f.fileData.name, Err: errors.New("file handle is read only")}
	}
	n = len(b)
	cur := atomic.LoadInt64(&f.at)
	f.fileData.Lock()
	defer f.fileData.Unlock()
	diff := cur - int64(len(f.fileData.data))
	var tail []byte
	if n+int(cur) < len(f.fileData.data) {
		tail = f.fileData.data[n+int(cur):]
	}
	if diff > 0 {
		f.fileData.data = append(bytes.Repeat([]byte{00}, int(diff)), b...)
		f.fileData.data = append(f.fileData.data, tail...)
	} else {
		f.fileData.data = append(f.fileData.data[:cur], b...)
		f.fileData.data = append(f.fileData.data, tail...)
	}
	setModTime(f.fileData, time.Now())

	atomic.StoreInt64(&f.at, int64(len(f.fileData.data)))
	return
}

func (f *File) WriteAt(b []byte, off int64) (n int, err error) {
	atomic.StoreInt64(&f.at, off)
	return f.Write(b)
}

func (f *File) WriteString(s string) (ret int, err error) {
	return f.Write([]byte(s))
}

func (f *File) Info() *FileInfo {
	return &FileInfo{f.fileData}
}

type FileInfo struct {
	*FileData
}

// Implements os.FileInfo
func (s *FileInfo) Name() string {
	s.Lock()
	_, name := filepath.Split(s.name)
	s.Unlock()
	return name
}
func (s *FileInfo) Mode() os.FileMode {
	s.Lock()
	defer s.Unlock()
	return s.mode
}
func (s *FileInfo) ModTime() time.Time {
	s.Lock()
	defer s.Unlock()
	return s.modtime
}
func (s *FileInfo) IsDir() bool {
	s.Lock()
	defer s.Unlock()
	return s.dir
}
func (s *FileInfo) Sys() interface{} { return nil }
func (s *FileInfo) Size() int64 {
	if s.IsDir() {
		return int64(42)
	}
	s.Lock()
	defer s.Unlock()
	return int64(len(s.data))
}

var (
	ErrFileClosed        = errors.New("File is closed")
	ErrOutOfRange        = errors.New("Out of range")
	ErrTooLarge          = errors.New("Too large")
	ErrFileNotFound      = os.ErrNotExist
	ErrFileExists        = os.ErrExist
	ErrDestinationExists = os.ErrExist
)
<commit_msg>Return closed error in mem.File.Write() after Close()<commit_after>// Copyright © 2015 Steve Francia <spf@spf13.com>.
// Copyright 2013 tsuru authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package mem

import (
	"bytes"
	"errors"
	"io"
	"os"
	"path/filepath"
	"sync"
	"sync/atomic"
)

import "time"

const FilePathSeparator = string(filepath.Separator)

type File struct {
	// atomic requires 64-bit alignment for struct field access
	at           int64
	readDirCount int64
	closed       bool
	readOnly     bool
	fileData     *FileData
}

func NewFileHandle(data *FileData) *File {
	return &File{fileData: data}
}

func NewReadOnlyFileHandle(data *FileData) *File {
	return &File{fileData: data, readOnly: true}
}

func (f File) Data() *FileData {
	return f.fileData
}

type FileData struct {
	sync.Mutex
	name    string
	data    []byte
	memDir  Dir
	dir     bool
	mode    os.FileMode
	modtime time.Time
}

func (d *FileData) Name() string {
	d.Lock()
	defer d.Unlock()
	return d.name
}

func CreateFile(name string) *FileData {
	return &FileData{name: name, mode: os.ModeTemporary, modtime: time.Now()}
}

func CreateDir(name string) *FileData {
	return &FileData{name: name, memDir: &DirMap{}, dir: true}
}

func ChangeFileName(f *FileData, newname string) {
	f.Lock()
	f.name = newname
	f.Unlock()
}

func SetMode(f *FileData, mode os.FileMode) {
	f.Lock()
	f.mode = mode
	f.Unlock()
}

func SetModTime(f *FileData, mtime time.Time) {
	f.Lock()
	setModTime(f, mtime)
	f.Unlock()
}

func setModTime(f *FileData, mtime time.Time) {
	f.modtime = mtime
}

func GetFileInfo(f *FileData) *FileInfo {
	return &FileInfo{f}
}

func (f *File) Open() error {
	atomic.StoreInt64(&f.at, 0)
	atomic.StoreInt64(&f.readDirCount, 0)
	f.fileData.Lock()
	f.closed = false
	f.fileData.Unlock()
	return nil
}

func (f *File) Close() error {
	f.fileData.Lock()
	f.closed = true
	if !f.readOnly {
		setModTime(f.fileData, time.Now())
	}
	f.fileData.Unlock()
	return nil
}

func (f *File) Name() string {
	return f.fileData.Name()
}

func (f *File) Stat() (os.FileInfo, error) {
	return &FileInfo{f.fileData}, nil
}

func (f *File) Sync() error {
	return nil
}

func (f *File) Readdir(count int) (res []os.FileInfo, err error) {
	var outLength int64

	f.fileData.Lock()
	files := f.fileData.memDir.Files()[f.readDirCount:]
	if count > 0 {
		if len(files) < count {
			outLength = int64(len(files))
		} else {
			outLength = int64(count)
		}
		if len(files) == 0 {
			err = io.EOF
		}
	} else {
		outLength = int64(len(files))
	}
	f.readDirCount += outLength
	f.fileData.Unlock()

	res = make([]os.FileInfo, outLength)
	for i := range res {
		res[i] = &FileInfo{files[i]}
	}

	return res, err
}

func (f *File) Readdirnames(n int) (names []string, err error) {
	fi, err := f.Readdir(n)
	names = make([]string, len(fi))
	for i, f := range fi {
		_, names[i] = filepath.Split(f.Name())
	}
	return names, err
}

func (f *File) Read(b []byte) (n int, err error) {
	f.fileData.Lock()
	defer f.fileData.Unlock()
	if f.closed == true {
		return 0, ErrFileClosed
	}
	if len(b) > 0 && int(f.at) == len(f.fileData.data) {
		return 0, io.EOF
	}
	if int(f.at) > len(f.fileData.data) {
		return 0, io.ErrUnexpectedEOF
	}
	if len(f.fileData.data)-int(f.at) >= len(b) {
		n = len(b)
	} else {
		n = len(f.fileData.data) - int(f.at)
	}
	copy(b, f.fileData.data[f.at:f.at+int64(n)])
	atomic.AddInt64(&f.at, int64(n))
	return
}

func (f *File) ReadAt(b []byte, off int64) (n int, err error) {
	atomic.StoreInt64(&f.at, off)
	return f.Read(b)
}

func (f *File) Truncate(size int64) error {
	if f.closed == true {
		return ErrFileClosed
	}
	if f.readOnly {
		return &os.PathError{Op: "truncate", Path: f.fileData.name, Err: errors.New("file handle is read only")}
	}
	if size < 0 {
		return ErrOutOfRange
	}
	if size > int64(len(f.fileData.data)) {
		diff := size - int64(len(f.fileData.data))
		f.fileData.data = append(f.fileData.data, bytes.Repeat([]byte{00}, int(diff))...)
	} else {
		f.fileData.data = f.fileData.data[0:size]
	}
	setModTime(f.fileData, time.Now())
	return nil
}

func (f *File) Seek(offset int64, whence int) (int64, error) {
	if f.closed == true {
		return 0, ErrFileClosed
	}
	switch whence {
	case 0:
		atomic.StoreInt64(&f.at, offset)
	case 1:
		atomic.AddInt64(&f.at, int64(offset))
	case 2:
		atomic.StoreInt64(&f.at, int64(len(f.fileData.data))+offset)
	}
	return f.at, nil
}

func (f *File) Write(b []byte) (n int, err error) {
	if f.closed == true {
		return 0, ErrFileClosed
	}
	if f.readOnly {
		return 0, &os.PathError{Op: "write", Path: f.fileData.name, Err: errors.New("file handle is read only")}
	}
	n = len(b)
	cur := atomic.LoadInt64(&f.at)
	f.fileData.Lock()
	defer f.fileData.Unlock()
	diff := cur - int64(len(f.fileData.data))
	var tail []byte
	if n+int(cur) < len(f.fileData.data) {
		tail = f.fileData.data[n+int(cur):]
	}
	if diff > 0 {
		f.fileData.data = append(bytes.Repeat([]byte{00}, int(diff)), b...)
		f.fileData.data = append(f.fileData.data, tail...)
	} else {
		f.fileData.data = append(f.fileData.data[:cur], b...)
		f.fileData.data = append(f.fileData.data, tail...)
	}
	setModTime(f.fileData, time.Now())

	atomic.StoreInt64(&f.at, int64(len(f.fileData.data)))
	return
}

func (f *File) WriteAt(b []byte, off int64) (n int, err error) {
	atomic.StoreInt64(&f.at, off)
	return f.Write(b)
}

func (f *File) WriteString(s string) (ret int, err error) {
	return f.Write([]byte(s))
}

func (f *File) Info() *FileInfo {
	return &FileInfo{f.fileData}
}

type FileInfo struct {
	*FileData
}

// Implements os.FileInfo
func (s *FileInfo) Name() string {
	s.Lock()
	_, name := filepath.Split(s.name)
	s.Unlock()
	return name
}
func (s *FileInfo) Mode() os.FileMode {
	s.Lock()
	defer s.Unlock()
	return s.mode
}
func (s *FileInfo) ModTime() time.Time {
	s.Lock()
	defer s.Unlock()
	return s.modtime
}
func (s *FileInfo) IsDir() bool {
	s.Lock()
	defer s.Unlock()
	return s.dir
}
func (s *FileInfo) Sys() interface{} { return nil }
func (s *FileInfo) Size() int64 {
	if s.IsDir() {
		return int64(42)
	}
	s.Lock()
	defer s.Unlock()
	return int64(len(s.data))
}

var (
	ErrFileClosed        = errors.New("File is closed")
	ErrOutOfRange        = errors.New("Out of range")
	ErrTooLarge          = errors.New("Too large")
	ErrFileNotFound      = os.ErrNotExist
	ErrFileExists        = os.ErrExist
	ErrDestinationExists = os.ErrExist
)
<|endoftext|>


<commit_before>package metacpan

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

// hosts
const (
	apiHost  = "api.metacpan.org"
	htmlHost = "metacpan.org"
)

// APIs
const (
	APISearchAutocomplete = "/v0/search/autocomplete"
	APISearchDistribution = "/v0/distribution/_search"
)

func request(urlStr string) ([]byte, error) {
	resp, err := http.DefaultClient.Get(fmt.Sprintf("https://%s%s", apiHost, urlStr))

	if err != nil {
		fmt.Println("error at request", urlStr)
		return nil, err
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		fmt.Println("error at read response body.")
		return nil, err
	}

	return body, nil
}
<commit_msg>Upgrade host and URLs to v1<commit_after>package metacpan

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

// hosts
const (
	apiHost  = "fastapi.metacpan.org"
	htmlHost = "metacpan.org"
)

// APIs
const (
	APISearchAutocomplete = "/v1/search/autocomplete"
	APISearchDistribution = "/v1/distribution/_search"
)

func request(urlStr string) ([]byte, error) {
	resp, err := http.DefaultClient.Get(fmt.Sprintf("https://%s%s", apiHost, urlStr))

	if err != nil {
		fmt.Println("error at request", urlStr)
		return nil, err
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		fmt.Println("error at read response body.")
		return nil, err
	}

	return body, nil
}
<|endoftext|>


<commit_before>package security

import (
	"fmt"

	"github.com/dertseha/everoute/travel"
	"github.com/dertseha/everoute/universe"
)

func travelCostType(security universe.TrueSecurity) string {
	return fmt.Sprintf("security%02d", int(security.Rounded()*10))
}

func travelCost(security universe.TrueSecurity, value float64) universe.TravelCost {
	return travel.AddingTravelCost(travelCostType(security), value)
}

func sumSecurityCosts(costSum *travel.TravelCostSum, from int, to int) float64 {
	var result = 0.0

	for i := from; i <= to; i++ {
		var security = universe.TrueSecurity(float64(i) / 10.0)
		var nullCost = travelCost(security, 0)

		result += costSum.Cost(nullCost).Value()
	}

	return result
}
<commit_msg>Precalculating null security costs<commit_after>package security

import (
	"fmt"

	"github.com/dertseha/everoute/travel"
	"github.com/dertseha/everoute/universe"
)

func travelCostType(security universe.TrueSecurity) string {
	return fmt.Sprintf("security%02d", int(security.Rounded()*10))
}

func travelCost(security universe.TrueSecurity, value float64) universe.TravelCost {
	return travel.AddingTravelCost(travelCostType(security), value)
}

var sumSecurityCosts func(*travel.TravelCostSum, int, int) float64 = (func() func(*travel.TravelCostSum, int, int) float64 {
	var nullCosts = make(map[int]universe.TravelCost)

	for i := 0; i <= 10; i++ {
		nullCosts[i] = travelCost(universe.TrueSecurity(float64(i)/10.0), 0)
	}

	return func(costSum *travel.TravelCostSum, from int, to int) float64 {
		var result = 0.0

		for i := from; i <= to; i++ {
			result += costSum.Cost(nullCosts[i]).Value()
		}

		return result
	}
})()
<|endoftext|>


<commit_before>/**
 * Copyright (C) 2015 Hewlett Packard Enterprise Development LP
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

//Package lint implements linting methods
package lint

import (
	"fmt"
	"os"
	"os/exec"
	"strings"

	"bytes"

	"bufio"
	"container/list"
	"io"
	"regexp"

	log "github.com/Sirupsen/logrus"
	"github.com/lagarciag/codenanny/config"
	"github.com/lagarciag/codenanny/installer"
)

var lintersFlag = map[string]string{
	"aligncheck":  `aligncheck .:^(?:[^:]+: )?(?P<path>[^:]+):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.+)$`,
	"deadcode":    `deadcode  `,
	"dupl":        `dupl -plumbing -threshold {duplthreshold} ./*.go:^(?P<path>[^\s][^:]+?\.go):(?P<line>\d+)-\d+:\s*(?P<message>.*)$`,
	"errcheck":    `errcheck -abspath`,
	"goconst":     `goconst`,
	"gocyclo":     `gocyclo -over {mincyclo} .:^(?P<cyclo>\d+)\s+\S+\s(?P<function>\S+)\s+(?P<path>[^:]+):(?P<line>\d+):(\d+)$`,
	"gofmt":       `gofmt -l -s ./*.go:^(?P<path>[^\n]+)$`,
	"goimports":   `goimports -w`,
	"golint":      "golint -set_exit_status ",
	"gotype":      "gotype -e {tests=-a} .:PATH:LINE:COL:MESSAGE",
	"ineffassign": `ineffassign -n .:PATH:LINE:COL:MESSAGE`,
	"interfacer":  `interfacer ./:PATH:LINE:COL:MESSAGE`,
	"lll":         `lll -g -l {maxlinelength} ./*.go:PATH:LINE:MESSAGE`,
	"structcheck": `structcheck {tests=-t} .:^(?:[^:]+: )?(?P<path>[^:]+):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.+)$`,
	"test":        `go test:^--- FAIL: .*$\s+(?P<path>[^:]+):(?P<line>\d+): (?P<message>.*)$`,
	"testify":     `go test:Location:\s+(?P<path>[^:]+):(?P<line>\d+)$\s+Error:\s+(?P<message>[^\n]+)`,
	"varcheck":    `varcheck .:^(?:[^:]+: )?(?P<path>[^:]+):(?P<line>\d+):(?P<col>\d+):[\s\t]+(?P<message>.*)$`,
	"vet":         "go vet ",
	"vetshadow":   "go tool vet --shadow ./*.go:PATH:LINE:MESSAGE",
	"unconvert":   "unconvert .:PATH:LINE:COL:MESSAGE",
	"gosimple":    "gosimple ",
	"staticcheck": "staticcheck .:PATH:LINE:COL:MESSAGE",
	"misspell":    "misspell ./*.go:PATH:LINE:COL:MESSAGE",
}

var packageLinters = []string{
	"errcheck",
	"golint",
	"vet",
	"gosimple",
}
var dirLinters = []string{
	"goimports",
	"goconst",
}

//CheckPackages runs linters and code checkers in the passed list of packages
func CheckPackages(listOfPackages []string) (err error) {
	//Find out what the Root Path is
	var tmpErr error
	var errCount int
	log.Debug("Checking pakages...", listOfPackages)
	cmd := exec.Command("git", "rev-parse", "--show-toplevel")
	tmpRootPath, err := cmd.Output()
	if err != nil {
		return err
	}

	//Trim return character
	rootPath := strings.TrimSpace(string(tmpRootPath))
	err = os.Chdir(rootPath)
	if err != nil {
		return err
	}
	log.Debug("Root path is:", rootPath)
	for _, aPackage := range listOfPackages {
		log.Debug("Checking package:", aPackage)
		for _, linter := range packageLinters {
			if !installer.DisabledTool[linter] {
				log.Debug("Running package checker:", linter)
				cmdString := lintersFlag[linter]
				splitCmd := strings.Split(cmdString, " ")
				msg := fmt.Sprintf("CMD: %s %s %s", splitCmd[0], splitCmd[1], aPackage)
				log.Debug(msg)
				cmd := exec.Command(splitCmd[0], splitCmd[1], aPackage)
				out, err := cmd.CombinedOutput()
				if err != nil {
					//Check patterns here
					errList, _ := readErrorsFromChecker(out, linter)
					if len(errList) > 0 {
						errCount++
						tmpErr = fmt.Errorf("%s found errors", linter)
						log.Error(tmpErr)
					} else {
						log.Warnf("%s found Errors but an error ingnore matched", linter)
						err = nil
					}
				}
			} else {
				log.Warn("Could not run disabled tool:", linter)
			}
		}
	}
	if tmpErr != nil {
		err = fmt.Errorf("Found %d package linter errors", errCount)
	}
	return err
}

func readErrorsFromChecker(cherrs []byte, tool string) (retList []string, err error) {
	var errEOF error
	var aLine string
	var pattern string
	var match = false
	patterns := config.GlobalConfig.IgnorePattern

	listOfPatterns, foundPattern := patterns[tool]
	log.Debug("PATTERNS", listOfPatterns)
	if foundPattern {
		log.Debug("Found patterns for tool:", tool)
		log.Debug("Found patterns for tool:", listOfPatterns)
		for patID, pat := range listOfPatterns {
			if patID == 0 {
				pattern = pat
			} else {
				pattern = fmt.Sprintf("%s|%s", pattern, pat)
			}
		}
		log.Debug("Pattern to exclude:", pattern)
	}

	errList := list.New()
	aReader := bytes.NewReader(cherrs)
	r1 := bufio.NewReader(aReader)
	for errEOF != io.EOF {
		aLine, errEOF = r1.ReadString(10) //  line was defined before
		aLine = strings.Trim(aLine, "\n")
		if foundPattern {
			match, _ = regexp.MatchString(pattern, aLine)
			if match {
				log.Debug("------>>>> MATCH:", aLine)
				log.Debug("------>>>> PATTERN:", pattern)
			}
		}
		if !match && aLine != "" {
			errList.PushBack(aLine)
			log.Errorf("%s:%s",tool,aLine)
		} else {
			if aLine != "" {
				log.Warnf("%s:%s",tool,aLine)
			}
		}
		match = false
	}
	retList = make([]string, errList.Len())
	count := 0
	for e := errList.Front(); e != nil; e = e.Next() {
		retList[count] = e.Value.(string)
		count++
	}
	return retList, err
}

//CheckDirs runs linters and checkers on directories provided in listOfDirs
func CheckDirs(listOfDirs []string) (err error) {
	//Find out what the Root Path is
	cmd := exec.Command("git", "rev-parse", "--show-toplevel")
	tmpRootPath, err := cmd.Output()
	if err != nil {
		return err
	}

	//Trim return character
	rootPath := strings.TrimSpace(string(tmpRootPath))
	err = os.Chdir(rootPath)
	if err != nil {
		return err
	}

	for _, aDir := range listOfDirs {
		log.Debug("Checking dir:", aDir)
		for _, linter := range dirLinters {
			if !installer.DisabledTool[linter] {
				log.Debug("Running dir checker:", linter)
				cmdString := lintersFlag[linter]
				splitCmd := strings.Split(cmdString, " ")
				var msg string
				var cmd *exec.Cmd
				if len(splitCmd) == 2 {
					msg = fmt.Sprintf("CMD: %s %s %s", splitCmd[0], splitCmd[1], aDir)
					log.Debug(msg)
					cmd = exec.Command(splitCmd[0], splitCmd[1], aDir)
				} else if len(splitCmd) == 1 {
					msg = fmt.Sprintf("CMD: %s %s ", splitCmd[0], aDir)
					log.Debug(msg)
					cmd = exec.Command(splitCmd[0], aDir)
				} else {
					log.Error("CMD:", splitCmd[0])
					log.Error("LENTH:", len(splitCmd))
					log.Fatal("Handle this error")
				}

				out, err := cmd.CombinedOutput()
				if err != nil {
					log.Debug("args:", cmd.Args)
					err = fmt.Errorf("%s found error in:%s", linter, string(out))
					log.Error(err)
					return err
				}
			} else {
				log.Warn("Could not run disabled tool:", linter)
			}

		}

	}

	return nil
}
<commit_msg>Linting files<commit_after>/**
 * Copyright (C) 2015 Hewlett Packard Enterprise Development LP
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

//Package lint implements linting methods
package lint

import (
	"fmt"
	"os"
	"os/exec"
	"strings"

	"bytes"

	"bufio"
	"container/list"
	"io"
	"regexp"

	log "github.com/Sirupsen/logrus"
	"github.com/lagarciag/codenanny/config"
	"github.com/lagarciag/codenanny/installer"
)

var lintersFlag = map[string]string{
	"aligncheck":  `aligncheck .:^(?:[^:]+: )?(?P<path>[^:]+):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.+)$`,
	"deadcode":    `deadcode  `,
	"dupl":        `dupl -plumbing -threshold {duplthreshold} ./*.go:^(?P<path>[^\s][^:]+?\.go):(?P<line>\d+)-\d+:\s*(?P<message>.*)$`,
	"errcheck":    `errcheck -abspath`,
	"goconst":     `goconst`,
	"gocyclo":     `gocyclo -over {mincyclo} .:^(?P<cyclo>\d+)\s+\S+\s(?P<function>\S+)\s+(?P<path>[^:]+):(?P<line>\d+):(\d+)$`,
	"gofmt":       `gofmt -l -s ./*.go:^(?P<path>[^\n]+)$`,
	"goimports":   `goimports -w`,
	"golint":      "golint -set_exit_status ",
	"gotype":      "gotype -e {tests=-a} .:PATH:LINE:COL:MESSAGE",
	"ineffassign": `ineffassign -n .:PATH:LINE:COL:MESSAGE`,
	"interfacer":  `interfacer ./:PATH:LINE:COL:MESSAGE`,
	"lll":         `lll -g -l {maxlinelength} ./*.go:PATH:LINE:MESSAGE`,
	"structcheck": `structcheck {tests=-t} .:^(?:[^:]+: )?(?P<path>[^:]+):(?P<line>\d+):(?P<col>\d+):\s*(?P<message>.+)$`,
	"test":        `go test:^--- FAIL: .*$\s+(?P<path>[^:]+):(?P<line>\d+): (?P<message>.*)$`,
	"testify":     `go test:Location:\s+(?P<path>[^:]+):(?P<line>\d+)$\s+Error:\s+(?P<message>[^\n]+)`,
	"varcheck":    `varcheck .:^(?:[^:]+: )?(?P<path>[^:]+):(?P<line>\d+):(?P<col>\d+):[\s\t]+(?P<message>.*)$`,
	"vet":         "go vet ",
	"vetshadow":   "go tool vet --shadow ./*.go:PATH:LINE:MESSAGE",
	"unconvert":   "unconvert .:PATH:LINE:COL:MESSAGE",
	"gosimple":    "gosimple ",
	"staticcheck": "staticcheck .:PATH:LINE:COL:MESSAGE",
	"misspell":    "misspell ./*.go:PATH:LINE:COL:MESSAGE",
}

var packageLinters = []string{
	"errcheck",
	"golint",
	"vet",
	"gosimple",
}
var dirLinters = []string{
	"goimports",
	"goconst",
}

//CheckPackages runs linters and code checkers in the passed list of packages
func CheckPackages(listOfPackages []string) (err error) {
	//Find out what the Root Path is
	var tmpErr error
	var errCount int
	log.Debug("Checking pakages...", listOfPackages)
	cmd := exec.Command("git", "rev-parse", "--show-toplevel")
	tmpRootPath, err := cmd.Output()
	if err != nil {
		return err
	}

	//Trim return character
	rootPath := strings.TrimSpace(string(tmpRootPath))
	err = os.Chdir(rootPath)
	if err != nil {
		return err
	}
	log.Debug("Root path is:", rootPath)
	for _, aPackage := range listOfPackages {
		log.Debug("Checking package:", aPackage)
		for _, linter := range packageLinters {
			if !installer.DisabledTool[linter] {
				log.Debug("Running package checker:", linter)
				cmdString := lintersFlag[linter]
				splitCmd := strings.Split(cmdString, " ")
				msg := fmt.Sprintf("CMD: %s %s %s", splitCmd[0], splitCmd[1], aPackage)
				log.Debug(msg)
				cmd := exec.Command(splitCmd[0], splitCmd[1], aPackage)
				out, err := cmd.CombinedOutput()
				if err != nil {
					//Check patterns here
					errList, _ := readErrorsFromChecker(out, linter)
					if len(errList) > 0 {
						errCount++
						tmpErr = fmt.Errorf("%s found errors", linter)
						log.Error(tmpErr)
					} else {
						log.Warnf("%s found Errors but an error ingnore matched", linter)
						err = nil
					}
				}
			} else {
				log.Warn("Could not run disabled tool:", linter)
			}
		}
	}
	if tmpErr != nil {
		err = fmt.Errorf("Found %d package linter errors", errCount)
	}
	return err
}

func readErrorsFromChecker(cherrs []byte, tool string) (retList []string, err error) {
	var errEOF error
	var aLine string
	var pattern string
	var match = false
	patterns := config.GlobalConfig.IgnorePattern

	listOfPatterns, foundPattern := patterns[tool]
	log.Debug("PATTERNS", listOfPatterns)
	if foundPattern {
		log.Debug("Found patterns for tool:", tool)
		log.Debug("Found patterns for tool:", listOfPatterns)
		for patID, pat := range listOfPatterns {
			if patID == 0 {
				pattern = pat
			} else {
				pattern = fmt.Sprintf("%s|%s", pattern, pat)
			}
		}
		log.Debug("Pattern to exclude:", pattern)
	}

	errList := list.New()
	aReader := bytes.NewReader(cherrs)
	r1 := bufio.NewReader(aReader)
	for errEOF != io.EOF {
		aLine, errEOF = r1.ReadString(10) //  line was defined before
		aLine = strings.Trim(aLine, "\n")
		if foundPattern {
			match, _ = regexp.MatchString(pattern, aLine)
			if match {
				log.Debug("------>>>> MATCH:", aLine)
				log.Debug("------>>>> PATTERN:", pattern)
			}
		}
		if !match && aLine != "" {
			errList.PushBack(aLine)
			log.Errorf("%s:%s", tool, aLine)
		} else {
			if aLine != "" {
				log.Warnf("%s:%s", tool, aLine)
			}
		}
		match = false
	}
	retList = make([]string, errList.Len())
	count := 0
	for e := errList.Front(); e != nil; e = e.Next() {
		retList[count] = e.Value.(string)
		count++
	}
	return retList, err
}

//CheckDirs runs linters and checkers on directories provided in listOfDirs
func CheckDirs(listOfDirs []string) (err error) {
	//Find out what the Root Path is
	cmd := exec.Command("git", "rev-parse", "--show-toplevel")
	tmpRootPath, err := cmd.Output()
	if err != nil {
		return err
	}

	//Trim return character
	rootPath := strings.TrimSpace(string(tmpRootPath))
	err = os.Chdir(rootPath)
	if err != nil {
		return err
	}

	for _, aDir := range listOfDirs {
		log.Debug("Checking dir:", aDir)
		for _, linter := range dirLinters {
			if !installer.DisabledTool[linter] {
				log.Debug("Running dir checker:", linter)
				cmdString := lintersFlag[linter]
				splitCmd := strings.Split(cmdString, " ")
				var msg string
				var cmd *exec.Cmd
				if len(splitCmd) == 2 {
					msg = fmt.Sprintf("CMD: %s %s %s", splitCmd[0], splitCmd[1], aDir)
					log.Debug(msg)
					cmd = exec.Command(splitCmd[0], splitCmd[1], aDir)
				} else if len(splitCmd) == 1 {
					msg = fmt.Sprintf("CMD: %s %s ", splitCmd[0], aDir)
					log.Debug(msg)
					cmd = exec.Command(splitCmd[0], aDir)
				} else {
					log.Error("CMD:", splitCmd[0])
					log.Error("LENTH:", len(splitCmd))
					log.Fatal("Handle this error")
				}

				out, err := cmd.CombinedOutput()
				if err != nil {
					log.Debug("args:", cmd.Args)
					err = fmt.Errorf("%s found error in:%s", linter, string(out))
					log.Error(err)
					return err
				}
			} else {
				log.Warn("Could not run disabled tool:", linter)
			}

		}

	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2014 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 main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

var hookFile = filepath.FromSlash(".git/hooks/commit-msg")

const usage = `Usage: %s [command]

The review command is a wrapper for the git command that provides a simple
interface to the "single-commit feature branch" development model.

Available comands:

	create <name>

		Create a local feature branch with the provided name
		and commit the staged changes to it.

	commit

		Amend feature branch HEAD with the staged changes.

	diff

		View differences between remote branch HEAD and
		the feature branch HEAD.
		(The differences introduced by this change.)

	upload

		Upload HEAD commit to the code review server.

	sync

		Fetch changes from the remote repository and merge them to the
		current branch, rebasing the HEAD commit (if any) on top of
		them.

	pending

		Show local feature branches and their head commits.

`

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, usage, os.Args[0])
		os.Exit(2)
	}
	flag.Parse()

	goToRepoRoot()
	installHook()

	switch flag.Arg(0) {
	case "create", "cr":
		name := flag.Arg(1)
		if name == "" {
			flag.Usage()
		}
		create(name)
	case "commit", "co":
		commit()
	case "diff", "d":
		diff()
	case "upload", "u":
		upload()
	case "sync", "s":
		sync()
	case "pending", "p":
		pending()
	default:
		flag.Usage()
	}
}

func create(name string) {
	if !hasStagedChanges() {
		dief("No staged changes. Did you forget to \"git add\" your files?\n")
	}
	if !isOnMaster() {
		dief("You must run create from the master branch. " +
			"(\"git checkout master\".)")
	}
	fmt.Printf("Creating and checking out branch: %v\n", name)
	run("git", "checkout", "-b", name)
	fmt.Printf("Committing staged changes to branch.\n")
	run("git", "commit")
}

func commit() {
	if !hasStagedChanges() {
		dief(`No staged changes. Did you forget to "git add" your files?\n`)
	}
	if isOnMaster() {
		dief("Can't commit to master branch.\n")
	}
	fmt.Printf("Amending head commit with staged changes.\n")
	run("git", "commit", "--amend", "-C", "HEAD")
}

func diff() {
	run("git", "diff", "HEAD^", "HEAD")
}

func upload() {
	if isOnMaster() {
		dief("Can't upload from master branch.\n")
	}
	fmt.Printf("Pushing commit to Gerrit code review server.\n")
	run("git", "push", "origin", "HEAD:refs/for/master")
}

func sync() {
	fmt.Printf("Fetching changes from remote repo.\n")
	run("git", "fetch")
	if isOnMaster() {
		run("git", "pull", "--ff-only")
		return
	}
	fmt.Printf("Rebasing head commit atop origin/master.\n")
	run("git", "rebase", "origin/master")
}

func pending() {
	dief("not implemented\n")
}

func hasStagedChanges() bool {
	status, err := exec.Command("git", "status", "-s").CombinedOutput()
	if err != nil {
		dief("%s\nchecking for staged changes: %v\n", status, err)
	}
	for _, s := range strings.Split(string(status), "\n") {
		if strings.HasPrefix(s, "A  ") ||
			strings.HasPrefix(s, "M  ") ||
			strings.HasPrefix(s, "D  ") {
			return true
		}
	}
	return false
}

func isOnMaster() bool {
	branch, err := exec.Command("git", "branch").CombinedOutput()
	if err != nil {
		dief("%s\nchecking current branch: %v\n", branch, err)
	}
	for _, s := range strings.Split(string(branch), "\n") {
		if strings.HasPrefix(s, "* ") {
			return s == "* master"
		}
	}
	return false
}

func goToRepoRoot() {
	prevDir, err := os.Getwd()
	if err != nil {
		dief("could not get current directory: %v\n", err)
	}
	for {
		if _, err := os.Stat(".git"); err == nil {
			return
		}
		if err := os.Chdir(".."); err != nil {
			dief("could not chdir: %v\n", err)
		}
		currentDir, err := os.Getwd()
		if err != nil {
			dief("could not get current directory: %v\n", err)
		}
		if currentDir == prevDir {
			dief("Git root not found. Run from within the Git tree please.\n")
		}
		prevDir = currentDir
	}
}

func installHook() {
	_, err := os.Stat(hookFile)
	if err == nil {
		return
	}
	if !os.IsNotExist(err) {
		dief("checking for hook file: %v\n", err)
	}
	fmt.Printf("Presubmit hook to add Change-Id to commit messages is missing.\n"+
		"Now automatically creating it at %v.\n\n", hookFile)
	hookContent := []byte(commitMsgHook)
	if err := ioutil.WriteFile(hookFile, hookContent, 0700); err != nil {
		dief("writing hook file: %v\n", err)
	}
}

func dief(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, format, args...)
	os.Exit(1)
}

func run(command string, args ...string) {
	cmd := exec.Command(command, args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		dief("%v\n", err)
	}
}
<commit_msg>better usage message<commit_after>// Copyright 2014 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 main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

var hookFile = filepath.FromSlash(".git/hooks/commit-msg")

const usage = `Usage: %s [command]
Type "%s help" for more information.
`

const help = `Usage: %s [command]

The review command is a wrapper for the git command that provides a simple
interface to the "single-commit feature branch" development model.

Available comands:

	create <name>
		Create a local branch with the provided name
		and commit the staged changes to it.

	commit
		Amend local branch HEAD commit with the staged changes.

	diff
		View differences between remote branch HEAD and
		the local branch HEAD.
		(The differences introduced by this change.)

	upload
		Upload HEAD commit to the code review server.

	sync
		Fetch changes from the remote repository and merge them to the
		current branch, rebasing the HEAD commit (if any) on top of
		them.

	pending
		Show local branches and their head commits.

`

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, usage, os.Args[0], os.Args[0])
		os.Exit(2)
	}
	flag.Parse()

	goToRepoRoot()
	installHook()

	switch flag.Arg(0) {
	case "help":
		fmt.Fprintf(os.Stdout, help, os.Args[0])
	case "create", "cr":
		name := flag.Arg(1)
		if name == "" {
			flag.Usage()
		}
		create(name)
	case "commit", "co":
		commit()
	case "diff", "d":
		diff()
	case "upload", "u":
		upload()
	case "sync", "s":
		sync()
	case "pending", "p":
		pending()
	default:
		flag.Usage()
	}
}

func create(name string) {
	if !hasStagedChanges() {
		dief("No staged changes. Did you forget to \"git add\" your files?\n")
	}
	if !isOnMaster() {
		dief("You must run create from the master branch. " +
			"(\"git checkout master\".)")
	}
	fmt.Printf("Creating and checking out branch: %v\n", name)
	run("git", "checkout", "-b", name)
	fmt.Printf("Committing staged changes to branch.\n")
	run("git", "commit")
}

func commit() {
	if !hasStagedChanges() {
		dief(`No staged changes. Did you forget to "git add" your files?\n`)
	}
	if isOnMaster() {
		dief("Can't commit to master branch.\n")
	}
	fmt.Printf("Amending head commit with staged changes.\n")
	run("git", "commit", "--amend", "-C", "HEAD")
}

func diff() {
	run("git", "diff", "HEAD^", "HEAD")
}

func upload() {
	if isOnMaster() {
		dief("Can't upload from master branch.\n")
	}
	fmt.Printf("Pushing commit to Gerrit code review server.\n")
	run("git", "push", "origin", "HEAD:refs/for/master")
}

func sync() {
	fmt.Printf("Fetching changes from remote repo.\n")
	run("git", "fetch")
	if isOnMaster() {
		run("git", "pull", "--ff-only")
		return
	}
	fmt.Printf("Rebasing head commit atop origin/master.\n")
	run("git", "rebase", "origin/master")
}

func pending() {
	dief("not implemented\n")
}

func hasStagedChanges() bool {
	status, err := exec.Command("git", "status", "-s").CombinedOutput()
	if err != nil {
		dief("%s\nchecking for staged changes: %v\n", status, err)
	}
	for _, s := range strings.Split(string(status), "\n") {
		if strings.HasPrefix(s, "A  ") ||
			strings.HasPrefix(s, "M  ") ||
			strings.HasPrefix(s, "D  ") {
			return true
		}
	}
	return false
}

func isOnMaster() bool {
	branch, err := exec.Command("git", "branch").CombinedOutput()
	if err != nil {
		dief("%s\nchecking current branch: %v\n", branch, err)
	}
	for _, s := range strings.Split(string(branch), "\n") {
		if strings.HasPrefix(s, "* ") {
			return s == "* master"
		}
	}
	return false
}

func goToRepoRoot() {
	prevDir, err := os.Getwd()
	if err != nil {
		dief("could not get current directory: %v\n", err)
	}
	for {
		if _, err := os.Stat(".git"); err == nil {
			return
		}
		if err := os.Chdir(".."); err != nil {
			dief("could not chdir: %v\n", err)
		}
		currentDir, err := os.Getwd()
		if err != nil {
			dief("could not get current directory: %v\n", err)
		}
		if currentDir == prevDir {
			dief("Git root not found. Run from within the Git tree please.\n")
		}
		prevDir = currentDir
	}
}

func installHook() {
	_, err := os.Stat(hookFile)
	if err == nil {
		return
	}
	if !os.IsNotExist(err) {
		dief("checking for hook file: %v\n", err)
	}
	fmt.Printf("Presubmit hook to add Change-Id to commit messages is missing.\n"+
		"Now automatically creating it at %v.\n\n", hookFile)
	hookContent := []byte(commitMsgHook)
	if err := ioutil.WriteFile(hookFile, hookContent, 0700); err != nil {
		dief("writing hook file: %v\n", err)
	}
}

func dief(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, format, args...)
	os.Exit(1)
}

func run(command string, args ...string) {
	cmd := exec.Command(command, args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		dief("%v\n", err)
	}
}
<|endoftext|>