<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 agreedto 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 consultopo implements topo.Server with consul as the backend.
*/
package consultopo

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"sync"

	"github.com/hashicorp/consul/api"

	"vitess.io/vitess/go/vt/log"
	"vitess.io/vitess/go/vt/topo"
)

var (
	consulAuthClientStaticFile = flag.String("consul_auth_client_static_file", "", "JSON File to read the topos/tokens from.")
)

// AuthClientCred credential to use for consul clusters
type AuthClientCred struct {
	// ACLToken when provided, the client will use this token when making requests to the Consul server.
	ACLToken string `json:"acl_token,omitempty"`
}

// Factory is the consul topo.Factory implementation.
type Factory struct{}

// HasGlobalReadOnlyCell is part of the topo.Factory interface.
func (f Factory) HasGlobalReadOnlyCell(serverAddr, root string) bool {
	return false
}

// Create is part of the topo.Factory interface.
func (f Factory) Create(cell, serverAddr, root string) (topo.Conn, error) {
	return NewServer(cell, serverAddr, root)
}

func getClientConfig() (creds map[string]*AuthClientCred, err error) {
	creds = make(map[string]*AuthClientCred)

	if *consulAuthClientStaticFile == "" {
		// Not configured, nothing to do.
		log.Infof("Consul client auth is not set up. consul_auth_client_static_file was not provided")
		return creds, nil
	}

	data, err := ioutil.ReadFile(*consulAuthClientStaticFile)
	if err != nil {
		err = fmt.Errorf("Failed to read consul_auth_client_static_file file: %v", err)
		return creds, err
	}

	if err := json.Unmarshal(data, &creds); err != nil {
		err = fmt.Errorf(fmt.Sprintf("Error parsing auth server config: %v", err))
	}
	return creds, nil
}

// Server is the implementation of topo.Server for consul.
type Server struct {
	// client is the consul api client.
	client *api.Client
	kv     *api.KV

	// root is the root path for this client.
	root string

	// mu protects the following fields.
	mu sync.Mutex
	// locks is a map of *lockInstance structures.
	// The key is the filepath of the Lock file.
	locks map[string]*lockInstance
}

// lockInstance keeps track of one lock held by this client.
type lockInstance struct {
	// lock has the api.Lock structure.
	lock *api.Lock

	// done is closed when the lock is release by this process.
	done chan struct{}
}

// NewServer returns a new consultopo.Server.
func NewServer(cell, serverAddr, root string) (*Server, error) {
	creds, err := getClientConfig()
	if err != nil {
		return nil, err
	}
	cfg := api.DefaultConfig()
	cfg.Address = serverAddr
	if creds[cell] != nil {
		cfg.Token = creds[cell].ACLToken
	}
	client, err := api.NewClient(cfg)
	if err != nil {
		return nil, err
	}

	return &Server{
		client: client,
		kv:     client.KV(),
		root:   root,
		locks:  make(map[string]*lockInstance),
	}, nil
}

// Close implements topo.Server.Close.
// It will nil out the global and cells fields, so any attempt to
// re-use this server will panic.
func (s *Server) Close() {
	s.client = nil
	s.kv = nil
	s.mu.Lock()
	defer s.mu.Unlock()
	s.locks = nil
}

func init() {
	topo.RegisterFactory("consul", Factory{})
}
<commit_msg>Address PR review feedback<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 agreedto 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 consultopo implements topo.Server with consul as the backend.
*/
package consultopo

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"sync"

	"github.com/hashicorp/consul/api"

	"vitess.io/vitess/go/vt/log"
	"vitess.io/vitess/go/vt/topo"
)

var (
	consulAuthClientStaticFile = flag.String("consul_auth_static_file", "", "JSON File to read the topos/tokens from.")
)

// ClientAuthCred credential to use for consul clusters
type ClientAuthCred struct {
	// ACLToken when provided, the client will use this token when making requests to the Consul server.
	ACLToken string `json:"acl_token,omitempty"`
}

// Factory is the consul topo.Factory implementation.
type Factory struct{}

// HasGlobalReadOnlyCell is part of the topo.Factory interface.
func (f Factory) HasGlobalReadOnlyCell(serverAddr, root string) bool {
	return false
}

// Create is part of the topo.Factory interface.
func (f Factory) Create(cell, serverAddr, root string) (topo.Conn, error) {
	return NewServer(cell, serverAddr, root)
}

func getClientCreds() (creds map[string]*ClientAuthCred, err error) {
	creds = make(map[string]*ClientAuthCred)

	if *consulAuthClientStaticFile == "" {
		// Not configured, nothing to do.
		log.Infof("Consul client auth is not set up. consul_auth_static_file was not provided")
		return nil, nil
	}

	data, err := ioutil.ReadFile(*consulAuthClientStaticFile)
	if err != nil {
		err = fmt.Errorf("Failed to read consul_auth_static_file file: %v", err)
		return creds, err
	}

	if err := json.Unmarshal(data, &creds); err != nil {
		err = fmt.Errorf(fmt.Sprintf("Error parsing consul_auth_static_file: %v", err))
		return creds, err
	}
	return creds, nil
}

// Server is the implementation of topo.Server for consul.
type Server struct {
	// client is the consul api client.
	client *api.Client
	kv     *api.KV

	// root is the root path for this client.
	root string

	// mu protects the following fields.
	mu sync.Mutex
	// locks is a map of *lockInstance structures.
	// The key is the filepath of the Lock file.
	locks map[string]*lockInstance
}

// lockInstance keeps track of one lock held by this client.
type lockInstance struct {
	// lock has the api.Lock structure.
	lock *api.Lock

	// done is closed when the lock is release by this process.
	done chan struct{}
}

// NewServer returns a new consultopo.Server.
func NewServer(cell, serverAddr, root string) (*Server, error) {
	creds, err := getClientCreds()
	if err != nil {
		return nil, err
	}
	cfg := api.DefaultConfig()
	cfg.Address = serverAddr
	if creds != nil && creds[cell] != nil {
		cfg.Token = creds[cell].ACLToken
	} else {
		log.Warningf("Client auth not configured for cell: %v", cell)
	}
	client, err := api.NewClient(cfg)
	if err != nil {
		return nil, err
	}

	return &Server{
		client: client,
		kv:     client.KV(),
		root:   root,
		locks:  make(map[string]*lockInstance),
	}, nil
}

// Close implements topo.Server.Close.
// It will nil out the global and cells fields, so any attempt to
// re-use this server will panic.
func (s *Server) Close() {
	s.client = nil
	s.kv = nil
	s.mu.Lock()
	defer s.mu.Unlock()
	s.locks = nil
}

func init() {
	topo.RegisterFactory("consul", Factory{})
}
<|endoftext|>


<commit_before>package google

import (
	"fmt"
	"strings"
	"time"

	"github.com/hashicorp/terraform/helper/schema"

	"google.golang.org/api/sqladmin/v1beta4"
)

func resourceSqlDatabase() *schema.Resource {
	return &schema.Resource{
		Create: resourceSqlDatabaseCreate,
		Read:   resourceSqlDatabaseRead,
		Update: resourceSqlDatabaseUpdate,
		Delete: resourceSqlDatabaseDelete,
		Importer: &schema.ResourceImporter{
			State: resourceSqlDatabaseImport,
		},

		Schema: map[string]*schema.Schema{
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"instance": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"project": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},

			"self_link": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"charset": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"collation": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
		},
		Timeouts: &schema.ResourceTimeout{
			Create: schema.DefaultTimeout(15 * time.Minute),
			Update: schema.DefaultTimeout(10 * time.Minute),
			Delete: schema.DefaultTimeout(10 * time.Minute),
		},
	}
}

func resourceSqlDatabaseCreate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	project, err := getProject(d, config)
	if err != nil {
		return err
	}

	database_name := d.Get("name").(string)
	instance_name := d.Get("instance").(string)
	d.SetId(instance_name + ":" + database_name)

	db := &sqladmin.Database{
		Name:      database_name,
		Instance:  instance_name,
		Charset:   d.Get("charset").(string),
		Collation: d.Get("collation").(string),
	}

	mutexKV.Lock(instanceMutexKey(project, instance_name))
	defer mutexKV.Unlock(instanceMutexKey(project, instance_name))
	op, err := config.clientSqlAdmin.Databases.Insert(project, instance_name,
		db).Do()

	if err != nil {
		return fmt.Errorf("Error, failed to insert "+
			"database %s into instance %s: %s", database_name,
			instance_name, err)
	}

	err = sqladminOperationWaitTime(config, op, project, "Insert Database", int(d.Timeout(schema.TimeoutCreate).Minutes()))

	if err != nil {
		return fmt.Errorf("Error, failure waiting for insertion of %s "+
			"into %s: %s", database_name, instance_name, err)
	}

	return resourceSqlDatabaseRead(d, meta)
}

func resourceSqlDatabaseRead(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	project, err := getProject(d, config)
	if err != nil {
		return err
	}

	s := strings.Split(d.Id(), ":")

	if len(s) != 2 {
		return fmt.Errorf("Error, failure importing database %s. "+
			"ID format is instance:name", d.Id())
	}

	instance_name := s[0]
	database_name := s[1]

	db, err := config.clientSqlAdmin.Databases.Get(project, instance_name,
		database_name).Do()

	if err != nil {
		return handleNotFoundError(err, d, fmt.Sprintf("SQL Database %q in instance %q", database_name, instance_name))
	}

	d.Set("instance", db.Instance)
	d.Set("name", db.Name)
	d.Set("self_link", db.SelfLink)
	d.SetId(instance_name + ":" + database_name)
	d.Set("charset", db.Charset)
	d.Set("collation", db.Collation)
	d.Set("project", project)

	return nil
}

func resourceSqlDatabaseUpdate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	project, err := getProject(d, config)
	if err != nil {
		return err
	}

	database_name := d.Get("name").(string)
	instance_name := d.Get("instance").(string)

	db := &sqladmin.Database{
		Name:      database_name,
		Instance:  instance_name,
		Charset:   d.Get("charset").(string),
		Collation: d.Get("collation").(string),
	}

	mutexKV.Lock(instanceMutexKey(project, instance_name))
	defer mutexKV.Unlock(instanceMutexKey(project, instance_name))
	op, err := config.clientSqlAdmin.Databases.Update(project, instance_name, database_name,
		db).Do()

	if err != nil {
		return fmt.Errorf("Error, failed to update "+
			"database %s in instance %s: %s", database_name,
			instance_name, err)
	}

	err = sqladminOperationWaitTime(config, op, project, "Update Database", int(d.Timeout(schema.TimeoutUpdate).Minutes()))

	if err != nil {
		return fmt.Errorf("Error, failure waiting for update of %s "+
			"into %s: %s", database_name, instance_name, err)
	}

	return resourceSqlDatabaseRead(d, meta)
}

func resourceSqlDatabaseDelete(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	project, err := getProject(d, config)
	if err != nil {
		return err
	}

	database_name := d.Get("name").(string)
	instance_name := d.Get("instance").(string)

	mutexKV.Lock(instanceMutexKey(project, instance_name))
	defer mutexKV.Unlock(instanceMutexKey(project, instance_name))
	op, err := config.clientSqlAdmin.Databases.Delete(project, instance_name,
		database_name).Do()

	if err != nil {
		return fmt.Errorf("Error, failed to delete"+
			"database %s in instance %s: %s", database_name,
			instance_name, err)
	}

	err = sqladminOperationWaitTime(config, op, project, "Delete Database", int(d.Timeout(schema.TimeoutDelete).Minutes()))

	if err != nil {
		return fmt.Errorf("Error, failure waiting for deletion of %s "+
			"in %s: %s", database_name, instance_name, err)
	}

	return nil
}

func resourceSqlDatabaseImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
	config := meta.(*Config)
	parseImportId([]string{
		"projects/(?P<project>[^/]+)/instances/(?P<instance>[^/]+)/databases/(?P<name>[^/]+)",
		"instances/(?P<instance>[^/]+)/databases/(?P<name>[^/]+)",
		"(?P<project>[^/]+)/(?P<instance>[^/]+)/(?P<name>[^/]+)",
		"(?P<instance>[^/]+)/(?P<name>[^/]+)",
		"(?P<instance>[^/]+):(?P<name>[^/]+)",
	}, d, config)

	// Replace import id for the resource id
	id, err := replaceVars(d, config, "{{instance}}:{{name}}")
	if err != nil {
		return nil, fmt.Errorf("Error constructing id: %s", err)
	}
	d.SetId(id)

	return []*schema.ResourceData{d}, nil
}
<commit_msg>add retries for all calls in sql database resource<commit_after>package google

import (
	"fmt"
	"strings"
	"time"

	"github.com/hashicorp/terraform/helper/schema"

	"google.golang.org/api/sqladmin/v1beta4"
)

func resourceSqlDatabase() *schema.Resource {
	return &schema.Resource{
		Create: resourceSqlDatabaseCreate,
		Read:   resourceSqlDatabaseRead,
		Update: resourceSqlDatabaseUpdate,
		Delete: resourceSqlDatabaseDelete,
		Importer: &schema.ResourceImporter{
			State: resourceSqlDatabaseImport,
		},

		Schema: map[string]*schema.Schema{
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"instance": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"project": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},

			"self_link": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"charset": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"collation": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
		},
		Timeouts: &schema.ResourceTimeout{
			Create: schema.DefaultTimeout(15 * time.Minute),
			Update: schema.DefaultTimeout(10 * time.Minute),
			Delete: schema.DefaultTimeout(10 * time.Minute),
		},
	}
}

func resourceSqlDatabaseCreate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	project, err := getProject(d, config)
	if err != nil {
		return err
	}

	database_name := d.Get("name").(string)
	instance_name := d.Get("instance").(string)
	d.SetId(instance_name + ":" + database_name)

	db := &sqladmin.Database{
		Name:      database_name,
		Instance:  instance_name,
		Charset:   d.Get("charset").(string),
		Collation: d.Get("collation").(string),
	}

	mutexKV.Lock(instanceMutexKey(project, instance_name))
	defer mutexKV.Unlock(instanceMutexKey(project, instance_name))

	var op *sqladmin.Operation
	err = retryTime(func() error {
		op, err = config.clientSqlAdmin.Databases.Insert(project, instance_name, db).Do()
		return err
	}, 5 /* minutes */)

	if err != nil {
		return fmt.Errorf("Error, failed to insert "+
			"database %s into instance %s: %s", database_name,
			instance_name, err)
	}

	err = sqladminOperationWaitTime(config, op, project, "Insert Database", int(d.Timeout(schema.TimeoutCreate).Minutes()))

	if err != nil {
		return fmt.Errorf("Error, failure waiting for insertion of %s "+
			"into %s: %s", database_name, instance_name, err)
	}

	return resourceSqlDatabaseRead(d, meta)
}

func resourceSqlDatabaseRead(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	project, err := getProject(d, config)
	if err != nil {
		return err
	}

	s := strings.Split(d.Id(), ":")

	if len(s) != 2 {
		return fmt.Errorf("Error, failure importing database %s. "+
			"ID format is instance:name", d.Id())
	}

	instance_name := s[0]
	database_name := s[1]

	var db *sqladmin.Database
	err = retryTime(func() error {
		db, err = config.clientSqlAdmin.Databases.Get(project, instance_name, database_name).Do()
		return err
	}, 5 /* minutes */)

	if err != nil {
		return handleNotFoundError(err, d, fmt.Sprintf("SQL Database %q in instance %q", database_name, instance_name))
	}

	d.Set("instance", db.Instance)
	d.Set("name", db.Name)
	d.Set("self_link", db.SelfLink)
	d.SetId(instance_name + ":" + database_name)
	d.Set("charset", db.Charset)
	d.Set("collation", db.Collation)
	d.Set("project", project)

	return nil
}

func resourceSqlDatabaseUpdate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	project, err := getProject(d, config)
	if err != nil {
		return err
	}

	database_name := d.Get("name").(string)
	instance_name := d.Get("instance").(string)

	db := &sqladmin.Database{
		Name:      database_name,
		Instance:  instance_name,
		Charset:   d.Get("charset").(string),
		Collation: d.Get("collation").(string),
	}

	mutexKV.Lock(instanceMutexKey(project, instance_name))
	defer mutexKV.Unlock(instanceMutexKey(project, instance_name))

	var op *sqladmin.Operation
	err = retryTime(func() error {
		op, err = config.clientSqlAdmin.Databases.Update(project, instance_name, database_name, db).Do()
		return err
	}, 5 /* minutes */)

	if err != nil {
		return fmt.Errorf("Error, failed to update "+
			"database %s in instance %s: %s", database_name,
			instance_name, err)
	}

	err = sqladminOperationWaitTime(config, op, project, "Update Database", int(d.Timeout(schema.TimeoutUpdate).Minutes()))

	if err != nil {
		return fmt.Errorf("Error, failure waiting for update of %s "+
			"into %s: %s", database_name, instance_name, err)
	}

	return resourceSqlDatabaseRead(d, meta)
}

func resourceSqlDatabaseDelete(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	project, err := getProject(d, config)
	if err != nil {
		return err
	}

	database_name := d.Get("name").(string)
	instance_name := d.Get("instance").(string)

	mutexKV.Lock(instanceMutexKey(project, instance_name))
	defer mutexKV.Unlock(instanceMutexKey(project, instance_name))

	var op *sqladmin.Operation
	err = retryTime(func() error {
		op, err = config.clientSqlAdmin.Databases.Delete(project, instance_name, database_name).Do()
		return err
	}, 5 /* minutes */)

	if err != nil {
		return fmt.Errorf("Error, failed to delete"+
			"database %s in instance %s: %s", database_name,
			instance_name, err)
	}

	err = sqladminOperationWaitTime(config, op, project, "Delete Database", int(d.Timeout(schema.TimeoutDelete).Minutes()))

	if err != nil {
		return fmt.Errorf("Error, failure waiting for deletion of %s "+
			"in %s: %s", database_name, instance_name, err)
	}

	return nil
}

func resourceSqlDatabaseImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
	config := meta.(*Config)
	parseImportId([]string{
		"projects/(?P<project>[^/]+)/instances/(?P<instance>[^/]+)/databases/(?P<name>[^/]+)",
		"instances/(?P<instance>[^/]+)/databases/(?P<name>[^/]+)",
		"(?P<project>[^/]+)/(?P<instance>[^/]+)/(?P<name>[^/]+)",
		"(?P<instance>[^/]+)/(?P<name>[^/]+)",
		"(?P<instance>[^/]+):(?P<name>[^/]+)",
	}, d, config)

	// Replace import id for the resource id
	id, err := replaceVars(d, config, "{{instance}}:{{name}}")
	if err != nil {
		return nil, fmt.Errorf("Error constructing id: %s", err)
	}
	d.SetId(id)

	return []*schema.ResourceData{d}, nil
}
<|endoftext|>


<commit_before>package commands

import (
	"fmt"
	"io"
	"os"
	"path/filepath"
	"sort"
	"strings"

	"github.com/git-lfs/git-lfs/git/odb"
	"github.com/git-lfs/git-lfs/tools"
	"github.com/spf13/cobra"
)

var MigrateInfoCommand = NewCommand("info", migrateInfoCommand)

var (
	// migrateInfoTopN is a flag given to the git-lfs-migrate(1) subcommand
	// 'info' which specifies how many info entries to show by default.
	migrateInfoTopN int
)

func migrateInfoCommand(cmd *cobra.Command, args []string) {
	exts := make(map[string]int64)

	migrate(cmd, args, func(path string, b *odb.Blob) (*odb.Blob, error) {
		ext := fmt.Sprintf("*%s", filepath.Ext(path))
		if len(ext) > 1 {
			exts[ext] = exts[ext] + b.Size
		}

		return b, nil
	})

	entries := EntriesBySize(MapToEntries(exts))
	sort.Sort(sort.Reverse(entries))

	migrateInfoTopN = tools.ClampInt(migrateInfoTopN, 0, len(entries))

	entries = entries[:tools.MaxInt(0, migrateInfoTopN)]

	entries.Print(os.Stderr)
}

// MigrateInfoEntry represents a tuple of filetype to total size taken by that
// file type.
type MigrateInfoEntry struct {
	// Qualifier is the filepath's extension.
	Qualifier string
	// Size is the total size in bytes taken by that filepath's extension.
	Size int64
}

// MapToEntries creates a set of `*MigrateInfoEntry`'s for a given map of
// filepath extensions to file size in bytes.
func MapToEntries(exts map[string]int64) []*MigrateInfoEntry {
	entries := make([]*MigrateInfoEntry, 0, len(exts))
	for qualifier, size := range exts {
		entries = append(entries, &MigrateInfoEntry{
			Qualifier: qualifier,
			Size:      size,
		})
	}

	return entries
}

// EntriesBySize is an implementation of sort.Interface that sorts a set of
// `*MigrateInfoEntry`'s
type EntriesBySize []*MigrateInfoEntry

// Len returns the total length of the set of `*MigrateInfoEntry`'s.
func (e EntriesBySize) Len() int { return len(e) }

// Less returns the whether or not the MigrateInfoEntry given at `i` takes up
// less total size than the MigrateInfoEntry given at `j`.
func (e EntriesBySize) Less(i, j int) bool { return e[i].Size < e[j].Size }

// Swap swaps the entries given at i, j.
func (e EntriesBySize) Swap(i, j int) { e[i], e[j] = e[j], e[i] }

// LongestQualifier returns the string length of the longest qualifier in the
// set.
func (e EntriesBySize) LongestQualifier() int {
	var longest int
	for _, entry := range e {
		longest = tools.MaxInt(longest, len(entry.Qualifier))
	}

	return longest
}

// Print formats the `*MigrateInfoEntry`'s in the set and prints them to the
// given io.Writer, "to", returning "n" the number of bytes written, and any
// error, if one occurred.
func (e EntriesBySize) Print(to io.Writer) (int, error) {
	output := make([]string, 0, len(e))

	longest := e.LongestQualifier()

	for _, entry := range e {
		offset := longest - len(entry.Qualifier)
		padding := strings.Repeat(" ", tools.MaxInt(0, offset))
		bytes := humanizeBytes(entry.Size)

		line := fmt.Sprintf("%s%s %s", entry.Qualifier, padding, bytes)

		output = append(output, line)
	}

	return fmt.Fprintln(to, strings.Join(output, "\n"))
}

func init() {
	MigrateInfoCommand.Flags().IntVar(&migrateInfoTopN, "top", 5, "--top=<n>")
}
<commit_msg>commands/migrate_info: fix arguments to tools.ClampInt<commit_after>package commands

import (
	"fmt"
	"io"
	"os"
	"path/filepath"
	"sort"
	"strings"

	"github.com/git-lfs/git-lfs/git/odb"
	"github.com/git-lfs/git-lfs/tools"
	"github.com/spf13/cobra"
)

var MigrateInfoCommand = NewCommand("info", migrateInfoCommand)

var (
	// migrateInfoTopN is a flag given to the git-lfs-migrate(1) subcommand
	// 'info' which specifies how many info entries to show by default.
	migrateInfoTopN int
)

func migrateInfoCommand(cmd *cobra.Command, args []string) {
	exts := make(map[string]int64)

	migrate(cmd, args, func(path string, b *odb.Blob) (*odb.Blob, error) {
		ext := fmt.Sprintf("*%s", filepath.Ext(path))
		if len(ext) > 1 {
			exts[ext] = exts[ext] + b.Size
		}

		return b, nil
	})

	entries := EntriesBySize(MapToEntries(exts))
	sort.Sort(sort.Reverse(entries))

	migrateInfoTopN = tools.ClampInt(migrateInfoTopN, len(entries), 0)

	entries = entries[:tools.MaxInt(0, migrateInfoTopN)]

	entries.Print(os.Stderr)
}

// MigrateInfoEntry represents a tuple of filetype to total size taken by that
// file type.
type MigrateInfoEntry struct {
	// Qualifier is the filepath's extension.
	Qualifier string
	// Size is the total size in bytes taken by that filepath's extension.
	Size int64
}

// MapToEntries creates a set of `*MigrateInfoEntry`'s for a given map of
// filepath extensions to file size in bytes.
func MapToEntries(exts map[string]int64) []*MigrateInfoEntry {
	entries := make([]*MigrateInfoEntry, 0, len(exts))
	for qualifier, size := range exts {
		entries = append(entries, &MigrateInfoEntry{
			Qualifier: qualifier,
			Size:      size,
		})
	}

	return entries
}

// EntriesBySize is an implementation of sort.Interface that sorts a set of
// `*MigrateInfoEntry`'s
type EntriesBySize []*MigrateInfoEntry

// Len returns the total length of the set of `*MigrateInfoEntry`'s.
func (e EntriesBySize) Len() int { return len(e) }

// Less returns the whether or not the MigrateInfoEntry given at `i` takes up
// less total size than the MigrateInfoEntry given at `j`.
func (e EntriesBySize) Less(i, j int) bool { return e[i].Size < e[j].Size }

// Swap swaps the entries given at i, j.
func (e EntriesBySize) Swap(i, j int) { e[i], e[j] = e[j], e[i] }

// LongestQualifier returns the string length of the longest qualifier in the
// set.
func (e EntriesBySize) LongestQualifier() int {
	var longest int
	for _, entry := range e {
		longest = tools.MaxInt(longest, len(entry.Qualifier))
	}

	return longest
}

// Print formats the `*MigrateInfoEntry`'s in the set and prints them to the
// given io.Writer, "to", returning "n" the number of bytes written, and any
// error, if one occurred.
func (e EntriesBySize) Print(to io.Writer) (int, error) {
	output := make([]string, 0, len(e))

	longest := e.LongestQualifier()

	for _, entry := range e {
		offset := longest - len(entry.Qualifier)
		padding := strings.Repeat(" ", tools.MaxInt(0, offset))
		bytes := humanizeBytes(entry.Size)

		line := fmt.Sprintf("%s%s %s", entry.Qualifier, padding, bytes)

		output = append(output, line)
	}

	return fmt.Fprintln(to, strings.Join(output, "\n"))
}

func init() {
	MigrateInfoCommand.Flags().IntVar(&migrateInfoTopN, "top", 5, "--top=<n>")
}
<|endoftext|>


<commit_before>package fastentity

import (
	"fmt"
	"testing"
)

var resume_store *Store

func init() {
	var err error
	resume_store, err = Load("data")
	if err != nil {
		fmt.Printf("Failed to load test resume store: %v", err)
	}
}

func TestHash(t *testing.T) {
	strs := map[string]string{
		"golang developer":   "gol016",
		"San Francisco, USA": "san018",
		"PHP":                "php003",
		"本語":                 "本語002",
		"C":                  "c001", // Single char entity
	}
	for original, hashexpected := range strs {
		hashed := hash([]rune(original))
		if hashexpected != hashed {
			t.Errorf("Failed to hash  %s (%s)", original, hashed)
		}
	}
}

func TestFind(t *testing.T) {
	str := []rune("日 本語. jack was a golang developer from sydney, for someone. San Francisco, USA... Or so they say. Maybe PHP, or PDX. Jody Shipway\\u0007\\n\\u0007")

	store := New("locations", "jobTitles") // Intentionally not initialising "skills"
	store.Add("locations", []rune("San Francisco, USA"))
	store.Add("jobTitles", []rune("golang developer"))
	store.Add("skills", []rune("PHP"), []rune("本語"), []rune("PRC"))
	store.Add("last", []rune("shipway")) // Intentionally adding garbled unicode

	results := store.FindAll(str)
	for group, found := range results {
		switch group {
		case "locations":
			ok := false
			for _, f := range found {
				if string(f) == "San Francisco, USA" {
					ok = true
				}
			}
			if !ok {
				t.Errorf("Failed to find location entity 'San Francisco, USA'")
			}
		case "skills":
			ok, ok2 := false, false
			for _, f := range found {
				if string(f) == "PHP" {
					ok = true
				}
				if string(f) == "本語" {
					ok2 = true
				}
			}
			if !ok {
				t.Errorf("Failed to find skill entity 'PHP'")
			}
			if !ok2 {
				t.Errorf("Failed to find skill entity '本語'")
			}
		case "jobTitles":
			ok := false
			for _, f := range found {
				if string(f) == "golang developer" {
					ok = true
				}
			}
			if !ok {
				t.Errorf("Failed to find jobTitle entity 'golang developer'")
			}
		case "last":
			ok := false
			for _, f := range found {
				if string(f) == "Shipway" {
					ok = true
				}
			}
			if !ok {
				t.Errorf("Failed to find last name entity 'Shipway'")
			}
		}
	}
}

// Approximates finding entities in a resume size document
func BenchmarkFind(b *testing.B) {
	b.StopTimer()
	str := []rune("Jim Smith,  Bleeker Street Houston, Texas 77034  (315) 555-5145  jimsmith@example.com  Objective: Seeking a position in an accounting field where I can utilize my skills and abilities in the field of tax oriented job that offers professional tax accountant.  Educational Details:  Bachelor of Science in Accounting University of Houston, 1989 Master of Science of Taxation University of New York, 1990  Master of Business Administration in Finance University of New York, 1992  Summary of Qualifications:  •  6+ years of tax and accounting experience.  •  Experience in establishing corporate tax department.  •  Experience working in global business environment.  •  Experience in using technology tools to leverage data, increase process and tax return efficiency, and complete work.  •  Able to research tax issues, apply practical tax experience.  Skills:  •  Excellent technical writing and editing skills.  •  Strong verbal communication skills.  •  Strong influencing skills across business functions.  •  Advanced computer skills.  •  Excellent accounting skills.  Computer Skills:  Lotus, Excel, Ami Pro, WordPerfect, ProComm Plus, Spreadsheet Auditor, Flowcharting III. Professional Experience:  Leading Commercial Printer, Houston, TX, 1996-2000 Tax Accountant  Responsibilities:  •  Prepared individual, partnership, corporate and other types of tax returns.  •  Did research on various tax matters.  •  Ensured that all sales and use tax returns are filed timely and accurately.  •  Prepared written communication for sales and use tax issues.  •  Collected information for all sales tax, use tax, and personal property tax audits.  •  Performed other duties as assigned.  Hipping Agency, Friendswood, TX, 1992-1995  Tax Staff Accountant  Responsibilities:  •  Established a 401K plan for company employees, enhancing the company's benefits package.  •  Prepared payroll, sales, use & property & commercial rent returns.  •  Responded to both client and government inquiries.  •  Devised the spreadsheet packages, financial statements and tax filings.  •  Ensured that all legal fees and push down entries for separate companies are recorded  ")
	b.StartTimer()
	for n := 0; n < b.N; n++ {
		resume_store.FindAll(str)
	}
}

func TestSaveLoad(t *testing.T) {
	store := New("locations", "jobTitles", "skills")
	store.Add("locations", []rune("San Francisco, USA"))
	store.Add("jobTitles", []rune("golang developer"))
	store.Add("skills", []rune("PHP"), []rune("本語"), []rune("PRC"))
	err := store.Save("/tmp")
	if err != nil {
		t.Errorf("Failed to save store")
	}

	store, err = Load("/tmp")
	if err != nil {
		t.Errorf("Failed to load store from disk")
	}
	for name, _ := range store.Lookup {
		if name != "locations" && name != "jobTitles" && name != "skills" {
			t.Errorf("Groups were not named what they should be. Got '%s'", name)
		}
	}
}
<commit_msg>Fix tests to reference Store.groups instead of Store.Lookups.<commit_after>package fastentity

import (
	"fmt"
	"testing"
)

var resume_store *Store

func init() {
	var err error
	resume_store, err = Load("data")
	if err != nil {
		fmt.Printf("Failed to load test resume store: %v", err)
	}
}

func TestHash(t *testing.T) {
	strs := map[string]string{
		"golang developer":   "gol016",
		"San Francisco, USA": "san018",
		"PHP":                "php003",
		"本語":                 "本語002",
		"C":                  "c001", // Single char entity
	}
	for original, hashexpected := range strs {
		hashed := hash([]rune(original))
		if hashexpected != hashed {
			t.Errorf("Failed to hash  %s (%s)", original, hashed)
		}
	}
}

func TestFind(t *testing.T) {
	str := []rune("日 本語. jack was a golang developer from sydney, for someone. San Francisco, USA... Or so they say. Maybe PHP, or PDX. Jody Shipway\\u0007\\n\\u0007")

	store := New("locations", "jobTitles") // Intentionally not initialising "skills"
	store.Add("locations", []rune("San Francisco, USA"))
	store.Add("jobTitles", []rune("golang developer"))
	store.Add("skills", []rune("PHP"), []rune("本語"), []rune("PRC"))
	store.Add("last", []rune("shipway")) // Intentionally adding garbled unicode

	results := store.FindAll(str)
	for group, found := range results {
		switch group {
		case "locations":
			ok := false
			for _, f := range found {
				if string(f) == "San Francisco, USA" {
					ok = true
				}
			}
			if !ok {
				t.Errorf("Failed to find location entity 'San Francisco, USA'")
			}
		case "skills":
			ok, ok2 := false, false
			for _, f := range found {
				if string(f) == "PHP" {
					ok = true
				}
				if string(f) == "本語" {
					ok2 = true
				}
			}
			if !ok {
				t.Errorf("Failed to find skill entity 'PHP'")
			}
			if !ok2 {
				t.Errorf("Failed to find skill entity '本語'")
			}
		case "jobTitles":
			ok := false
			for _, f := range found {
				if string(f) == "golang developer" {
					ok = true
				}
			}
			if !ok {
				t.Errorf("Failed to find jobTitle entity 'golang developer'")
			}
		case "last":
			ok := false
			for _, f := range found {
				if string(f) == "Shipway" {
					ok = true
				}
			}
			if !ok {
				t.Errorf("Failed to find last name entity 'Shipway'")
			}
		}
	}
}

// Approximates finding entities in a resume size document
func BenchmarkFind(b *testing.B) {
	b.StopTimer()
	str := []rune("Jim Smith,  Bleeker Street Houston, Texas 77034  (315) 555-5145  jimsmith@example.com  Objective: Seeking a position in an accounting field where I can utilize my skills and abilities in the field of tax oriented job that offers professional tax accountant.  Educational Details:  Bachelor of Science in Accounting University of Houston, 1989 Master of Science of Taxation University of New York, 1990  Master of Business Administration in Finance University of New York, 1992  Summary of Qualifications:  •  6+ years of tax and accounting experience.  •  Experience in establishing corporate tax department.  •  Experience working in global business environment.  •  Experience in using technology tools to leverage data, increase process and tax return efficiency, and complete work.  •  Able to research tax issues, apply practical tax experience.  Skills:  •  Excellent technical writing and editing skills.  •  Strong verbal communication skills.  •  Strong influencing skills across business functions.  •  Advanced computer skills.  •  Excellent accounting skills.  Computer Skills:  Lotus, Excel, Ami Pro, WordPerfect, ProComm Plus, Spreadsheet Auditor, Flowcharting III. Professional Experience:  Leading Commercial Printer, Houston, TX, 1996-2000 Tax Accountant  Responsibilities:  •  Prepared individual, partnership, corporate and other types of tax returns.  •  Did research on various tax matters.  •  Ensured that all sales and use tax returns are filed timely and accurately.  •  Prepared written communication for sales and use tax issues.  •  Collected information for all sales tax, use tax, and personal property tax audits.  •  Performed other duties as assigned.  Hipping Agency, Friendswood, TX, 1992-1995  Tax Staff Accountant  Responsibilities:  •  Established a 401K plan for company employees, enhancing the company's benefits package.  •  Prepared payroll, sales, use & property & commercial rent returns.  •  Responded to both client and government inquiries.  •  Devised the spreadsheet packages, financial statements and tax filings.  •  Ensured that all legal fees and push down entries for separate companies are recorded  ")
	b.StartTimer()
	for n := 0; n < b.N; n++ {
		resume_store.FindAll(str)
	}
}

func TestSaveLoad(t *testing.T) {
	store := New("locations", "jobTitles", "skills")
	store.Add("locations", []rune("San Francisco, USA"))
	store.Add("jobTitles", []rune("golang developer"))
	store.Add("skills", []rune("PHP"), []rune("本語"), []rune("PRC"))
	err := store.Save("/tmp")
	if err != nil {
		t.Errorf("Failed to save store")
	}

	store, err = Load("/tmp")
	if err != nil {
		t.Errorf("Failed to load store from disk")
	}
	for name, _ := range store.groups {
		if name != "locations" && name != "jobTitles" && name != "skills" {
			t.Errorf("Groups were not named what they should be. Got '%s'", name)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	slog "log"
	"net"
	"time"

	"github.com/cockroachdb/cmux"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"

	"github.com/shunfei/cronsun"
	"github.com/shunfei/cronsun/conf"
	"github.com/shunfei/cronsun/event"
	"github.com/shunfei/cronsun/log"
	"github.com/shunfei/cronsun/web"
)

var (
	level    = flag.Int("l", 0, "log level, -1:debug, 0:info, 1:warn, 2:error")
	confFile = flag.String("conf", "conf/files/base.json", "config file path")
)

func main() {
	flag.Parse()

	lcf := zap.NewDevelopmentConfig()
	lcf.Level.SetLevel(zapcore.Level(*level))
	lcf.Development = false
	logger, err := lcf.Build(zap.AddCallerSkip(1))
	if err != nil {
		slog.Fatalln("new log err:", err.Error())
	}
	log.SetLogger(logger.Sugar())

	if err = cronsun.Init(*confFile, true); err != nil {
		log.Errorf(err.Error())
		return
	}
	web.EnsureJobLogIndex()

	l, err := net.Listen("tcp", conf.Config.Web.BindAddr)
	if err != nil {
		log.Errorf(err.Error())
		return
	}

	// Create a cmux.
	m := cmux.New(l)
	httpL := m.Match(cmux.HTTP1Fast())
	httpServer, err := web.InitServer()
	if err != nil {
		log.Errorf(err.Error())
		return
	}

	if conf.Config.Mail.Enable {
		var noticer cronsun.Noticer

		if len(conf.Config.Mail.HttpAPI) > 0 {
			noticer = &cronsun.HttpAPI{}
		} else {
			mailer, err := cronsun.NewMail(30 * time.Second)
			if err != nil {
				log.Errorf(err.Error())
				return
			}
			noticer = mailer
		}
		go cronsun.StartNoticer(noticer)
	}

	period := int64(conf.Config.Web.LogCleaner.EveryMinute)
	var stopCleaner func(interface{})
	if period > 0 {
		closeChan := web.RunLogCleaner(time.Duration(period)*time.Minute, time.Duration(conf.Config.Web.LogCleaner.ExpirationDays)*time.Hour*24)
		stopCleaner = func(i interface{}) {
			close(closeChan)
		}
	}

	go func() {
		err := httpServer.Serve(httpL)
		if err != nil {
			panic(err.Error())
		}
	}()

	go m.Serve()

	log.Infof("cronsun web server started on %s, Ctrl+C or send kill sign to exit", conf.Config.Web.BindAddr)
	// 注册退出事件
	event.On(event.EXIT, conf.Exit, stopCleaner)
	// 监听退出信号
	event.Wait()
	event.Emit(event.EXIT, nil)
	log.Infof("exit success")
}
<commit_msg>Added flag 'network', resolved #76<commit_after>package main

import (
	"flag"
	slog "log"
	"net"
	"time"

	"github.com/cockroachdb/cmux"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"

	"github.com/shunfei/cronsun"
	"github.com/shunfei/cronsun/conf"
	"github.com/shunfei/cronsun/event"
	"github.com/shunfei/cronsun/log"
	"github.com/shunfei/cronsun/web"
)

var (
	level    = flag.Int("l", 0, "log level, -1:debug, 0:info, 1:warn, 2:error")
	confFile = flag.String("conf", "conf/files/base.json", "config file path")
	network  = flag.String("network", "", "network protocol of listen address: ipv4/ipv6, or empty use both")
)

func main() {
	flag.Parse()

	lcf := zap.NewDevelopmentConfig()
	lcf.Level.SetLevel(zapcore.Level(*level))
	lcf.Development = false
	logger, err := lcf.Build(zap.AddCallerSkip(1))
	if err != nil {
		slog.Fatalln("new log err:", err.Error())
	}
	log.SetLogger(logger.Sugar())

	if err = cronsun.Init(*confFile, true); err != nil {
		log.Errorf(err.Error())
		return
	}
	web.EnsureJobLogIndex()

	l, err := net.Listen(checkNetworkProtocol(*network), conf.Config.Web.BindAddr)
	if err != nil {
		log.Errorf(err.Error())
		return
	}

	// Create a cmux.
	m := cmux.New(l)
	httpL := m.Match(cmux.HTTP1Fast())
	httpServer, err := web.InitServer()
	if err != nil {
		log.Errorf(err.Error())
		return
	}

	if conf.Config.Mail.Enable {
		var noticer cronsun.Noticer

		if len(conf.Config.Mail.HttpAPI) > 0 {
			noticer = &cronsun.HttpAPI{}
		} else {
			mailer, err := cronsun.NewMail(30 * time.Second)
			if err != nil {
				log.Errorf(err.Error())
				return
			}
			noticer = mailer
		}
		go cronsun.StartNoticer(noticer)
	}

	period := int64(conf.Config.Web.LogCleaner.EveryMinute)
	var stopCleaner func(interface{})
	if period > 0 {
		closeChan := web.RunLogCleaner(time.Duration(period)*time.Minute, time.Duration(conf.Config.Web.LogCleaner.ExpirationDays)*time.Hour*24)
		stopCleaner = func(i interface{}) {
			close(closeChan)
		}
	}

	go func() {
		err := httpServer.Serve(httpL)
		if err != nil {
			panic(err.Error())
		}
	}()

	go m.Serve()

	log.Infof("cronsun web server started on %s, Ctrl+C or send kill sign to exit", conf.Config.Web.BindAddr)
	// 注册退出事件
	event.On(event.EXIT, conf.Exit, stopCleaner)
	// 监听退出信号
	event.Wait()
	event.Emit(event.EXIT, nil)
	log.Infof("exit success")
}

func checkNetworkProtocol(p string) string {
	switch p {
	case "ipv4":
		return "tcp4"
	case "ipv6":
		return "tcp6"
	}

	return "tcp"
}
<|endoftext|>


<commit_before>// Copyright 2018 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 vgo

import (
	"bytes"
	"cmd/go/internal/base"
	"cmd/go/internal/cfg"
	"cmd/go/internal/modconv"
	"cmd/go/internal/modfetch"
	"cmd/go/internal/modfetch/codehost"
	"cmd/go/internal/modfile"
	"cmd/go/internal/module"
	"cmd/go/internal/mvs"
	"cmd/go/internal/search"
	"cmd/go/internal/semver"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
)

var (
	cwd         string
	enabled     = MustBeVgo
	MustBeVgo   = mustBeVgo()
	initialized bool

	ModRoot  string
	modFile  *modfile.File
	excluded map[module.Version]bool
	Target   module.Version

	gopath string
	srcV   string
)

func BinDir() string {
	if !Enabled() {
		panic("vgo.Bin")
	}
	return filepath.Join(gopath, "bin")
}

func init() {
	flag.BoolVar(&MustBeVgo, "vgo", MustBeVgo, "require use of modules")
}

// mustBeVgo reports whether we are invoked as vgo
// (as opposed to go).
// If so, we only support builds with go.mod files.
func mustBeVgo() bool {
	name := os.Args[0]
	name = name[strings.LastIndex(name, "/")+1:]
	name = name[strings.LastIndex(name, `\`)+1:]
	return strings.HasPrefix(name, "vgo")
}

func Init() {
	if initialized {
		return
	}
	initialized = true

	// If this is testgo - the test binary during cmd/go tests - then
	// do not let it look for a go.mod. Only use vgo support if the
	// global -vgo flag has been passed on the command line.
	if base := filepath.Base(os.Args[0]); (base == "testgo" || base == "testgo.exe") && !MustBeVgo {
		return
	}

	var err error
	cwd, err = os.Getwd()
	if err != nil {
		base.Fatalf("go: %v", err)
	}

	root, _ := FindModuleRoot(cwd, "", MustBeVgo)
	if root == "" {
		// If invoked as vgo, insist on a mod file.
		if MustBeVgo {
			base.Fatalf("cannot determine module root; please create a go.mod file there")
		}
		return
	}
	enabled = true
	ModRoot = root
	search.SetModRoot(root)
}

func Enabled() bool {
	if !initialized {
		panic("vgo: Enabled called before Init")
	}
	return enabled
}

func InitMod() {
	if Init(); !Enabled() || modFile != nil {
		return
	}

	list := filepath.SplitList(cfg.BuildContext.GOPATH)
	if len(list) == 0 || list[0] == "" {
		base.Fatalf("missing $GOPATH")
	}
	gopath = list[0]
	if _, err := os.Stat(filepath.Join(gopath, "go.mod")); err == nil {
		base.Fatalf("$GOPATH/go.mod exists but should not")
	}
	srcV = filepath.Join(list[0], "src/v")
	codehost.WorkRoot = filepath.Join(srcV, "cache/vcswork")

	gomod := filepath.Join(ModRoot, "go.mod")
	data, err := ioutil.ReadFile(gomod)
	if err != nil {
		legacyModInit()
		return
	}

	f, err := modfile.Parse(gomod, data, fixVersion)
	if err != nil {
		// Errors returned by modfile.Parse begin with file:line.
		base.Fatalf("vgo: errors parsing go.mod:\n%s\n", err)
	}
	modFile = f

	if len(f.Syntax.Stmt) == 0 || f.Module == nil {
		// Empty mod file. Must add module path.
		path, err := FindModulePath(ModRoot)
		if err != nil {
			base.Fatalf("vgo: %v", err)
		}
		f.AddModuleStmt(path)
	}

	excluded = make(map[module.Version]bool)
	for _, x := range f.Exclude {
		excluded[x.Mod] = true
	}
	Target = f.Module.Mod
	writeGoMod()
}

func allowed(m module.Version) bool {
	return !excluded[m]
}

func legacyModInit() {
	path, err := FindModulePath(ModRoot)
	if err != nil {
		base.Fatalf("vgo: %v", err)
	}
	modFile = new(modfile.File)
	modFile.AddModuleStmt(path)
	Target = module.Version{Path: path}

	for _, name := range altConfigs {
		cfg := filepath.Join(ModRoot, name)
		data, err := ioutil.ReadFile(cfg)
		if err == nil {
			convert := modconv.Converters[name]
			if convert == nil {
				return
			}
			if err := modfetch.ConvertLegacyConfig(modFile, cfg, data); err != nil {
				base.Fatalf("vgo: %v", err)
			}
			return
		}
	}

	base.Fatalf("vgo: internal error: cannot find legacy config file (it was here a minute ago!)")
}

var altConfigs = []string{
	"Gopkg.lock",

	"GLOCKFILE",
	"Godeps/Godeps.json",
	"dependencies.tsv",
	"glide.lock",
	"vendor.conf",
	"vendor.yml",
	"vendor/manifest",
	"vendor/vendor.json",

	".git/config",
}

// Exported only for testing.
func FindModuleRoot(dir, limit string, legacyConfigOK bool) (root, file string) {
	dir = filepath.Clean(dir)
	dir1 := dir
	limit = filepath.Clean(limit)

	// Look for enclosing go.mod.
	for {
		if _, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil {
			return dir, "go.mod"
		}
		if dir == limit {
			break
		}
		d := filepath.Dir(dir)
		if d == dir {
			break
		}
		dir = d
	}

	// Failing that, look for enclosing alternate version config.
	if legacyConfigOK {
		dir = dir1
		for {
			for _, name := range altConfigs {
				if _, err := os.Stat(filepath.Join(dir, name)); err == nil {
					return dir, name
				}
			}
			if dir == limit {
				break
			}
			d := filepath.Dir(dir)
			if d == dir {
				break
			}
			dir = d
		}
	}

	return "", ""
}

// Exported only for testing.
func FindModulePath(dir string) (string, error) {
	for _, dir := range filepath.SplitList(cfg.BuildContext.GOPATH) {
		src := filepath.Join(dir, "src") + string(filepath.Separator)
		if strings.HasPrefix(dir, src) {
			return filepath.ToSlash(dir[len(src):]), nil
		}
	}

	// Cast about for import comments,
	// first in top-level directory, then in subdirectories.
	list, _ := ioutil.ReadDir(dir)
	for _, info := range list {
		if info.Mode().IsRegular() && strings.HasSuffix(info.Name(), ".go") {
			if com := findImportComment(filepath.Join(dir, info.Name())); com != "" {
				return com, nil
			}
		}
	}
	for _, info1 := range list {
		if info1.IsDir() {
			files, _ := ioutil.ReadDir(filepath.Join(dir, info1.Name()))
			for _, info2 := range files {
				if info2.Mode().IsRegular() && strings.HasSuffix(info2.Name(), ".go") {
					if com := findImportComment(filepath.Join(dir, info1.Name(), info2.Name())); com != "" {
						return path.Dir(com), nil
					}
				}
			}
		}
	}

	// Look for Godeps.json declaring import path.
	data, _ := ioutil.ReadFile(filepath.Join(dir, "Godeps/Godeps.json"))
	var cfg struct{ ImportPath string }
	json.Unmarshal(data, &cfg)
	if cfg.ImportPath != "" {
		return cfg.ImportPath, nil
	}

	// Look for vendor.json declaring import path.
	data, _ = ioutil.ReadFile(filepath.Join(dir, "vendor/vendor.json"))
	var cfg2 struct{ RootPath string }
	json.Unmarshal(data, &cfg2)
	if cfg2.RootPath != "" {
		return cfg2.RootPath, nil
	}

	// Look for .git/config with github origin as last resort.
	data, _ = ioutil.ReadFile(filepath.Join(dir, ".git/config"))
	if m := gitOriginRE.FindSubmatch(data); m != nil {
		return "github.com/" + string(m[1]), nil
	}

	return "", fmt.Errorf("cannot determine module path for source directory %s (outside GOPATH, no import comments)", dir)
}

var (
	gitOriginRE     = regexp.MustCompile(`(?m)^\[remote "origin"\]\r?\n\turl = (?:https://github.com/|git@github.com:|gh:)([^/]+/[^/]+?)(\.git)?\r?\n`)
	importCommentRE = regexp.MustCompile(`(?m)^package[ \t]+[^ \t\r\n/]+[ \t]+//[ \t]+import[ \t]+(\"[^"]+\")[ \t]*\r?\n`)
)

func findImportComment(file string) string {
	data, err := ioutil.ReadFile(file)
	if err != nil {
		return ""
	}
	m := importCommentRE.FindSubmatch(data)
	if m == nil {
		return ""
	}
	path, err := strconv.Unquote(string(m[1]))
	if err != nil {
		return ""
	}
	return path
}

func writeGoMod() {
	writeModHash()

	if buildList != nil {
		min, err := mvs.Req(Target, buildList, newReqs())
		if err != nil {
			base.Fatalf("vgo: %v", err)
		}
		modFile.SetRequire(min)
	}

	file := filepath.Join(ModRoot, "go.mod")
	old, _ := ioutil.ReadFile(file)
	new, err := modFile.Format()
	if err != nil {
		base.Fatalf("vgo: %v", err)
	}
	if bytes.Equal(old, new) {
		return
	}
	if err := ioutil.WriteFile(file, new, 0666); err != nil {
		base.Fatalf("vgo: %v", err)
	}
}

func fixVersion(path, vers string) (string, error) {
	// Special case: remove the old -gopkgin- hack.
	if strings.HasPrefix(path, "gopkg.in/") && strings.Contains(vers, "-gopkgin-") {
		vers = vers[strings.Index(vers, "-gopkgin-")+len("-gopkgin-"):]
	}

	// fixVersion is called speculatively on every
	// module, version pair from every go.mod file.
	// Avoid the query if it looks OK.
	_, pathMajor, ok := module.SplitPathVersion(path)
	if !ok {
		return "", fmt.Errorf("malformed module path: %s", path)
	}
	if semver.IsValid(vers) && vers == semver.Canonical(vers) && module.MatchPathMajor(vers, pathMajor) {
		return vers, nil
	}

	info, err := modfetch.Query(path, vers, nil)
	if err != nil {
		return "", err
	}
	return info.Version, nil
}
<commit_msg>cmd/go/internal/vgo: do not shadow GOPATH dir var<commit_after>// Copyright 2018 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 vgo

import (
	"bytes"
	"cmd/go/internal/base"
	"cmd/go/internal/cfg"
	"cmd/go/internal/modconv"
	"cmd/go/internal/modfetch"
	"cmd/go/internal/modfetch/codehost"
	"cmd/go/internal/modfile"
	"cmd/go/internal/module"
	"cmd/go/internal/mvs"
	"cmd/go/internal/search"
	"cmd/go/internal/semver"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
)

var (
	cwd         string
	enabled     = MustBeVgo
	MustBeVgo   = mustBeVgo()
	initialized bool

	ModRoot  string
	modFile  *modfile.File
	excluded map[module.Version]bool
	Target   module.Version

	gopath string
	srcV   string
)

func BinDir() string {
	if !Enabled() {
		panic("vgo.Bin")
	}
	return filepath.Join(gopath, "bin")
}

func init() {
	flag.BoolVar(&MustBeVgo, "vgo", MustBeVgo, "require use of modules")
}

// mustBeVgo reports whether we are invoked as vgo
// (as opposed to go).
// If so, we only support builds with go.mod files.
func mustBeVgo() bool {
	name := os.Args[0]
	name = name[strings.LastIndex(name, "/")+1:]
	name = name[strings.LastIndex(name, `\`)+1:]
	return strings.HasPrefix(name, "vgo")
}

func Init() {
	if initialized {
		return
	}
	initialized = true

	// If this is testgo - the test binary during cmd/go tests - then
	// do not let it look for a go.mod. Only use vgo support if the
	// global -vgo flag has been passed on the command line.
	if base := filepath.Base(os.Args[0]); (base == "testgo" || base == "testgo.exe") && !MustBeVgo {
		return
	}

	var err error
	cwd, err = os.Getwd()
	if err != nil {
		base.Fatalf("go: %v", err)
	}

	root, _ := FindModuleRoot(cwd, "", MustBeVgo)
	if root == "" {
		// If invoked as vgo, insist on a mod file.
		if MustBeVgo {
			base.Fatalf("cannot determine module root; please create a go.mod file there")
		}
		return
	}
	enabled = true
	ModRoot = root
	search.SetModRoot(root)
}

func Enabled() bool {
	if !initialized {
		panic("vgo: Enabled called before Init")
	}
	return enabled
}

func InitMod() {
	if Init(); !Enabled() || modFile != nil {
		return
	}

	list := filepath.SplitList(cfg.BuildContext.GOPATH)
	if len(list) == 0 || list[0] == "" {
		base.Fatalf("missing $GOPATH")
	}
	gopath = list[0]
	if _, err := os.Stat(filepath.Join(gopath, "go.mod")); err == nil {
		base.Fatalf("$GOPATH/go.mod exists but should not")
	}
	srcV = filepath.Join(list[0], "src/v")
	codehost.WorkRoot = filepath.Join(srcV, "cache/vcswork")

	gomod := filepath.Join(ModRoot, "go.mod")
	data, err := ioutil.ReadFile(gomod)
	if err != nil {
		legacyModInit()
		return
	}

	f, err := modfile.Parse(gomod, data, fixVersion)
	if err != nil {
		// Errors returned by modfile.Parse begin with file:line.
		base.Fatalf("vgo: errors parsing go.mod:\n%s\n", err)
	}
	modFile = f

	if len(f.Syntax.Stmt) == 0 || f.Module == nil {
		// Empty mod file. Must add module path.
		path, err := FindModulePath(ModRoot)
		if err != nil {
			base.Fatalf("vgo: %v", err)
		}
		f.AddModuleStmt(path)
	}

	excluded = make(map[module.Version]bool)
	for _, x := range f.Exclude {
		excluded[x.Mod] = true
	}
	Target = f.Module.Mod
	writeGoMod()
}

func allowed(m module.Version) bool {
	return !excluded[m]
}

func legacyModInit() {
	path, err := FindModulePath(ModRoot)
	if err != nil {
		base.Fatalf("vgo: %v", err)
	}
	modFile = new(modfile.File)
	modFile.AddModuleStmt(path)
	Target = module.Version{Path: path}

	for _, name := range altConfigs {
		cfg := filepath.Join(ModRoot, name)
		data, err := ioutil.ReadFile(cfg)
		if err == nil {
			convert := modconv.Converters[name]
			if convert == nil {
				return
			}
			if err := modfetch.ConvertLegacyConfig(modFile, cfg, data); err != nil {
				base.Fatalf("vgo: %v", err)
			}
			return
		}
	}

	base.Fatalf("vgo: internal error: cannot find legacy config file (it was here a minute ago!)")
}

var altConfigs = []string{
	"Gopkg.lock",

	"GLOCKFILE",
	"Godeps/Godeps.json",
	"dependencies.tsv",
	"glide.lock",
	"vendor.conf",
	"vendor.yml",
	"vendor/manifest",
	"vendor/vendor.json",

	".git/config",
}

// Exported only for testing.
func FindModuleRoot(dir, limit string, legacyConfigOK bool) (root, file string) {
	dir = filepath.Clean(dir)
	dir1 := dir
	limit = filepath.Clean(limit)

	// Look for enclosing go.mod.
	for {
		if _, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil {
			return dir, "go.mod"
		}
		if dir == limit {
			break
		}
		d := filepath.Dir(dir)
		if d == dir {
			break
		}
		dir = d
	}

	// Failing that, look for enclosing alternate version config.
	if legacyConfigOK {
		dir = dir1
		for {
			for _, name := range altConfigs {
				if _, err := os.Stat(filepath.Join(dir, name)); err == nil {
					return dir, name
				}
			}
			if dir == limit {
				break
			}
			d := filepath.Dir(dir)
			if d == dir {
				break
			}
			dir = d
		}
	}

	return "", ""
}

// Exported only for testing.
func FindModulePath(dir string) (string, error) {
	for _, gpdir := range filepath.SplitList(cfg.BuildContext.GOPATH) {
		src := filepath.Join(gpdir, "src") + string(filepath.Separator)
		if strings.HasPrefix(dir, src) {
			return filepath.ToSlash(dir[len(src):]), nil
		}
	}

	// Cast about for import comments,
	// first in top-level directory, then in subdirectories.
	list, _ := ioutil.ReadDir(dir)
	for _, info := range list {
		if info.Mode().IsRegular() && strings.HasSuffix(info.Name(), ".go") {
			if com := findImportComment(filepath.Join(dir, info.Name())); com != "" {
				return com, nil
			}
		}
	}
	for _, info1 := range list {
		if info1.IsDir() {
			files, _ := ioutil.ReadDir(filepath.Join(dir, info1.Name()))
			for _, info2 := range files {
				if info2.Mode().IsRegular() && strings.HasSuffix(info2.Name(), ".go") {
					if com := findImportComment(filepath.Join(dir, info1.Name(), info2.Name())); com != "" {
						return path.Dir(com), nil
					}
				}
			}
		}
	}

	// Look for Godeps.json declaring import path.
	data, _ := ioutil.ReadFile(filepath.Join(dir, "Godeps/Godeps.json"))
	var cfg struct{ ImportPath string }
	json.Unmarshal(data, &cfg)
	if cfg.ImportPath != "" {
		return cfg.ImportPath, nil
	}

	// Look for vendor.json declaring import path.
	data, _ = ioutil.ReadFile(filepath.Join(dir, "vendor/vendor.json"))
	var cfg2 struct{ RootPath string }
	json.Unmarshal(data, &cfg2)
	if cfg2.RootPath != "" {
		return cfg2.RootPath, nil
	}

	// Look for .git/config with github origin as last resort.
	data, _ = ioutil.ReadFile(filepath.Join(dir, ".git/config"))
	if m := gitOriginRE.FindSubmatch(data); m != nil {
		return "github.com/" + string(m[1]), nil
	}

	return "", fmt.Errorf("cannot determine module path for source directory %s (outside GOPATH, no import comments)", dir)
}

var (
	gitOriginRE     = regexp.MustCompile(`(?m)^\[remote "origin"\]\r?\n\turl = (?:https://github.com/|git@github.com:|gh:)([^/]+/[^/]+?)(\.git)?\r?\n`)
	importCommentRE = regexp.MustCompile(`(?m)^package[ \t]+[^ \t\r\n/]+[ \t]+//[ \t]+import[ \t]+(\"[^"]+\")[ \t]*\r?\n`)
)

func findImportComment(file string) string {
	data, err := ioutil.ReadFile(file)
	if err != nil {
		return ""
	}
	m := importCommentRE.FindSubmatch(data)
	if m == nil {
		return ""
	}
	path, err := strconv.Unquote(string(m[1]))
	if err != nil {
		return ""
	}
	return path
}

func writeGoMod() {
	writeModHash()

	if buildList != nil {
		min, err := mvs.Req(Target, buildList, newReqs())
		if err != nil {
			base.Fatalf("vgo: %v", err)
		}
		modFile.SetRequire(min)
	}

	file := filepath.Join(ModRoot, "go.mod")
	old, _ := ioutil.ReadFile(file)
	new, err := modFile.Format()
	if err != nil {
		base.Fatalf("vgo: %v", err)
	}
	if bytes.Equal(old, new) {
		return
	}
	if err := ioutil.WriteFile(file, new, 0666); err != nil {
		base.Fatalf("vgo: %v", err)
	}
}

func fixVersion(path, vers string) (string, error) {
	// Special case: remove the old -gopkgin- hack.
	if strings.HasPrefix(path, "gopkg.in/") && strings.Contains(vers, "-gopkgin-") {
		vers = vers[strings.Index(vers, "-gopkgin-")+len("-gopkgin-"):]
	}

	// fixVersion is called speculatively on every
	// module, version pair from every go.mod file.
	// Avoid the query if it looks OK.
	_, pathMajor, ok := module.SplitPathVersion(path)
	if !ok {
		return "", fmt.Errorf("malformed module path: %s", path)
	}
	if semver.IsValid(vers) && vers == semver.Canonical(vers) && module.MatchPathMajor(vers, pathMajor) {
		return vers, nil
	}

	info, err := modfetch.Query(path, vers, nil)
	if err != nil {
		return "", err
	}
	return info.Version, nil
}
<|endoftext|>


<commit_before>package sender

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/briandowns/spinner"

	log "github.com/cihub/seelog"
	"github.com/gorilla/websocket"
	"github.com/pkg/errors"
	"github.com/schollz/croc/src/compress"
	"github.com/schollz/croc/src/crypt"
	"github.com/schollz/croc/src/logger"
	"github.com/schollz/croc/src/models"
	"github.com/schollz/croc/src/utils"
	"github.com/schollz/croc/src/zipper"
	"github.com/schollz/pake"
	"github.com/schollz/progressbar/v2"
	"github.com/tscholl2/siec"
)

var DebugLevel string

// Send is the async call to send data
func Send(done chan struct{}, c *websocket.Conn, fname string, codephrase string) {
	logger.SetLogLevel(DebugLevel)
	log.Debugf("sending %s", fname)
	err := send(c, fname, codephrase)
	if err != nil {
		if strings.HasPrefix(err.Error(), "websocket: close 100") {
			err = nil
		}
		if err == nil {
			fmt.Fprintf(os.Stderr, "Transfer complete")
		} else {
			fmt.Fprintf(os.Stderr, err.Error())
		}
	}
	done <- struct{}{}
}

func send(c *websocket.Conn, fname string, codephrase string) (err error) {
	// check that the file exists
	fname, err = filepath.Abs(fname)
	_, filename := filepath.Split(fname)
	f, err := os.Open(fname)
	if err != nil {
		return
	}
	fstat, err := f.Stat()
	if err != nil {
		return err
	}

	// get stats about the file
	fstats := models.FileStats{filename, fstat.Size(), fstat.ModTime(), fstat.IsDir(), fstat.Name()}
	if fstats.IsDir {
		// zip the directory
		fstats.SentName, err = zipper.ZipFile(fname, true)
		// remove the file when leaving
		defer os.Remove(fstats.SentName)
		fname = fstats.SentName
		if err != nil {
			return
		}
		f.Close()
		// reopen file
		f, err = os.Open(fstats.SentName)
		if err != nil {
			return
		}
		fstat, err := f.Stat()
		if err != nil {
			return err
		}
		// get new size
		fstats.Size = fstat.Size()
	}

	// get ready to generate session key
	var sessionKey []byte

	// start a spinner
	spin := spinner.New(spinner.CharSets[9], 100*time.Millisecond)
	spin.Suffix = " wating for recipient..."
	spin.Start()

	// pick an elliptic curve
	curve := siec.SIEC255()
	// both parties should have a weak key
	pw := []byte(codephrase)
	// initialize sender P ("0" indicates sender)
	P, err := pake.Init(pw, 0, curve, 100*time.Millisecond)
	if err != nil {
		return
	}

	step := 0
	for {
		messageType, message, errRead := c.ReadMessage()
		if errRead != nil {
			return errRead
		}
		if messageType == websocket.PongMessage || messageType == websocket.PingMessage {
			continue
		}
		log.Debugf("got %d: %s", messageType, message)
		switch step {
		case 0:
			// send pake data
			log.Debugf("[%d] first, P sends u to Q", step)
			c.WriteMessage(websocket.BinaryMessage, P.Bytes())
			// start PAKE spinnner
			spin.Stop()
			spin.Suffix = " performing PAKE..."
			spin.Start()
		case 1:
			// P recieves H(k),v from Q
			log.Debugf("[%d] P computes k, H(k), sends H(k) to Q", step)
			if err := P.Update(message); err != nil {
				return err
			}
			c.WriteMessage(websocket.BinaryMessage, P.Bytes())
			sessionKey, _ = P.SessionKey()
			// check(err)
			log.Debugf("%x\n", sessionKey)
		case 2:
			log.Debugf("[%d] recipient declares readiness for file info", step)
			if !bytes.Equal(message, []byte("ready")) {
				return errors.New("recipient refused file")
			}
			fstatsBytes, err := json.Marshal(fstats)
			if err != nil {
				return err
			}
			log.Debugf("%s\n", fstatsBytes)
			c.WriteMessage(websocket.BinaryMessage, fstatsBytes)
		case 3:
			spin.Stop()

			log.Debugf("[%d] recipient declares readiness for file data", step)
			if !bytes.Equal(message, []byte("ready")) {
				return errors.New("recipient refused file")
			}

			fmt.Fprintf(os.Stderr, "Sending...\n")
			// send file, compure hash simultaneously
			buffer := make([]byte, 1024*512)
			bar := progressbar.NewOptions(
				int(fstats.Size),
				progressbar.OptionSetRenderBlankState(true),
				progressbar.OptionSetBytes(int(fstats.Size)),
				progressbar.OptionSetWriter(os.Stderr),
			)
			for {
				bytesread, err := f.Read(buffer)
				bar.Add(bytesread)
				if bytesread > 0 {
					// do compression
					compressedBytes := compress.Compress(buffer[:bytesread])
					// compressedBytes := buffer[:bytesread]

					// do encryption
					enc := crypt.Encrypt(compressedBytes, sessionKey, true)
					encBytes, err := json.Marshal(enc)
					if err != nil {
						return err
					}

					// send message
					err = c.WriteMessage(websocket.BinaryMessage, encBytes)
					if err != nil {
						err = errors.Wrap(err, "problem writing message")
						return err
					}
					// wait for ok
					c.ReadMessage()
				}
				if err != nil {
					if err != io.EOF {
						fmt.Println(err)
					}
					break
				}
			}

			bar.Finish()
			log.Debug("send hash to finish file")
			fileHash, err := utils.HashFile(fname)
			if err != nil {
				return err
			}
			c.WriteMessage(websocket.TextMessage, fileHash)
		case 4:
			log.Debugf("[%d] determing whether it went ok", step)
			if bytes.Equal(message, []byte("ok")) {
				log.Debug("file transfered successfully")
				return nil
			} else {
				return errors.New("file not transfered succesfully")
			}
		default:
			return fmt.Errorf("unknown step")
		}
		step++
	}
}
<commit_msg>better spinner<commit_after>package sender

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/briandowns/spinner"

	log "github.com/cihub/seelog"
	"github.com/gorilla/websocket"
	"github.com/pkg/errors"
	"github.com/schollz/croc/src/compress"
	"github.com/schollz/croc/src/crypt"
	"github.com/schollz/croc/src/logger"
	"github.com/schollz/croc/src/models"
	"github.com/schollz/croc/src/utils"
	"github.com/schollz/croc/src/zipper"
	"github.com/schollz/pake"
	"github.com/schollz/progressbar/v2"
	"github.com/tscholl2/siec"
)

var DebugLevel string

// Send is the async call to send data
func Send(done chan struct{}, c *websocket.Conn, fname string, codephrase string) {
	logger.SetLogLevel(DebugLevel)
	log.Debugf("sending %s", fname)
	err := send(c, fname, codephrase)
	if err != nil {
		if strings.HasPrefix(err.Error(), "websocket: close 100") {
			err = nil
		}
		if err == nil {
			fmt.Fprintf(os.Stderr, "Transfer complete")
		} else {
			fmt.Fprintf(os.Stderr, err.Error())
		}
	}
	done <- struct{}{}
}

func send(c *websocket.Conn, fname string, codephrase string) (err error) {
	// check that the file exists
	fname, err = filepath.Abs(fname)
	_, filename := filepath.Split(fname)
	f, err := os.Open(fname)
	if err != nil {
		return
	}
	fstat, err := f.Stat()
	if err != nil {
		return err
	}

	// get stats about the file
	fstats := models.FileStats{filename, fstat.Size(), fstat.ModTime(), fstat.IsDir(), fstat.Name()}
	if fstats.IsDir {
		// zip the directory
		fstats.SentName, err = zipper.ZipFile(fname, true)
		// remove the file when leaving
		defer os.Remove(fstats.SentName)
		fname = fstats.SentName
		if err != nil {
			return
		}
		f.Close()
		// reopen file
		f, err = os.Open(fstats.SentName)
		if err != nil {
			return
		}
		fstat, err := f.Stat()
		if err != nil {
			return err
		}
		// get new size
		fstats.Size = fstat.Size()
	}

	// get ready to generate session key
	var sessionKey []byte

	// start a spinner
	spin := spinner.New(spinner.CharSets[9], 100*time.Millisecond)

	// pick an elliptic curve
	curve := siec.SIEC255()
	// both parties should have a weak key
	pw := []byte(codephrase)
	// initialize sender P ("0" indicates sender)
	P, err := pake.Init(pw, 0, curve, 100*time.Millisecond)
	if err != nil {
		return
	}

	step := 0
	for {
		messageType, message, errRead := c.ReadMessage()
		if errRead != nil {
			return errRead
		}
		if messageType == websocket.PongMessage || messageType == websocket.PingMessage {
			continue
		}
		log.Debugf("got %d: %s", messageType, message)
		switch step {
		case 0:
			// send pake data
			log.Debugf("[%d] first, P sends u to Q", step)
			c.WriteMessage(websocket.BinaryMessage, P.Bytes())
			// start PAKE spinnner
			spin.Suffix = " performing PAKE..."
			spin.Start()
		case 1:
			// P recieves H(k),v from Q
			log.Debugf("[%d] P computes k, H(k), sends H(k) to Q", step)
			if err := P.Update(message); err != nil {
				return err
			}
			c.WriteMessage(websocket.BinaryMessage, P.Bytes())
			sessionKey, _ = P.SessionKey()
			// check(err)
			log.Debugf("%x\n", sessionKey)

			// wait for readiness
			spin.Stop()
			spin.Suffix = " waiting for recipient ok..."
			spin.Start()
		case 2:
			log.Debugf("[%d] recipient declares readiness for file info", step)
			if !bytes.Equal(message, []byte("ready")) {
				return errors.New("recipient refused file")
			}
			fstatsBytes, err := json.Marshal(fstats)
			if err != nil {
				return err
			}
			log.Debugf("%s\n", fstatsBytes)
			c.WriteMessage(websocket.BinaryMessage, fstatsBytes)
		case 3:
			spin.Stop()

			log.Debugf("[%d] recipient declares readiness for file data", step)
			if !bytes.Equal(message, []byte("ready")) {
				return errors.New("recipient refused file")
			}

			fmt.Fprintf(os.Stderr, "Sending...\n")
			// send file, compure hash simultaneously
			buffer := make([]byte, 1024*512)
			bar := progressbar.NewOptions(
				int(fstats.Size),
				progressbar.OptionSetRenderBlankState(true),
				progressbar.OptionSetBytes(int(fstats.Size)),
				progressbar.OptionSetWriter(os.Stderr),
			)
			for {
				bytesread, err := f.Read(buffer)
				bar.Add(bytesread)
				if bytesread > 0 {
					// do compression
					compressedBytes := compress.Compress(buffer[:bytesread])
					// compressedBytes := buffer[:bytesread]

					// do encryption
					enc := crypt.Encrypt(compressedBytes, sessionKey, true)
					encBytes, err := json.Marshal(enc)
					if err != nil {
						return err
					}

					// send message
					err = c.WriteMessage(websocket.BinaryMessage, encBytes)
					if err != nil {
						err = errors.Wrap(err, "problem writing message")
						return err
					}
					// wait for ok
					c.ReadMessage()
				}
				if err != nil {
					if err != io.EOF {
						fmt.Println(err)
					}
					break
				}
			}

			bar.Finish()
			log.Debug("send hash to finish file")
			fileHash, err := utils.HashFile(fname)
			if err != nil {
				return err
			}
			c.WriteMessage(websocket.TextMessage, fileHash)
		case 4:
			log.Debugf("[%d] determing whether it went ok", step)
			if bytes.Equal(message, []byte("ok")) {
				log.Debug("file transfered successfully")
				return nil
			} else {
				return errors.New("file not transfered succesfully")
			}
		default:
			return fmt.Errorf("unknown step")
		}
		step++
	}
}
<|endoftext|>


<commit_before>package blockdiag

import (
	"sort"
	"strings"
	"testing"
)

func TestShouldParser(t *testing.T) {
	for _, test := range []struct {
		description string
		input       string
		nodes       []string
		edges       []string
		attributes  map[string]string
	}{
		{
			"Empty diagram",
			`
blockdiag {}
`,
			[]string{},
			[]string{},
			map[string]string{},
		},
		{
			"Single Node",
			`
blockdiag {
	A;
}
`,
			[]string{"A"},
			[]string{},
			map[string]string{},
		},
		{
			// TODO Add test case for node chain without tailing ;
			"Node chain",
			`
blockdiag {
	A -> B;
}
`,
			[]string{"A", "B"},
			[]string{"A|B"},
			map[string]string{},
		},
		{
			"Multiple chains, using same nodes",
			`
blockdiag {
	A -> B -> C;
	A -> D;
}
`,
			[]string{"A", "B", "C", "D"},
			[]string{"A|B", "A|D", "B|C"},
			map[string]string{},
		},
		{
			"Self reference",
			`
blockdiag {
	A -> A;
}
`,
			[]string{"A"},
			[]string{"A|A"},
			map[string]string{},
		},
		{
			"Comment",
			`
# Comment
blockdiag # Comment
{
# Comment
	A; # Comment
# Comment
} # Comment
`,
			[]string{"A"},
			[]string{},
			map[string]string{},
		},
		{
			"Multi Char Node Names",
			`
blockdiag
{
	MultiCharNodeName1;
}
`,
			[]string{"MultiCharNodeName1"},
			[]string{},
			map[string]string{},
		},
		{
			"Digramm Attributes",
			`
blockdiag
{
	node_width = 128;
	A;
}
`,
			[]string{"A"},
			[]string{},
			map[string]string{
				"node_width": "128",
			},
		},
		{
			"Digramm type 'diagram'",
			`
diagram
{
	A;
}
`,
			[]string{"A"},
			[]string{},
			map[string]string{},
		},
	} {
		got, err := ParseReader("shouldparse.diag", strings.NewReader(test.input))
		if err != nil {
			t.Fatalf("%s: parse error: %s with input %s", test.description, err, test.input)
		}
		gotDiag, ok := got.(Diag)
		if !ok {
			t.Fatalf("%s: assertion error: %s should parse to diag", test.description, test.input)
		}
		if gotDiag.NodesString() != strings.Join(test.nodes, ", ") {
			t.Fatalf("%s: nodes error: %s, expected '%s', got: '%s'", test.description, test.input, strings.Join(test.nodes, ", "), gotDiag.NodesString())
		}
		if gotDiag.EdgesString() != strings.Join(test.edges, ", ") {
			t.Fatalf("%s edges error: %s, expected '%s', got: '%s'", test.description, test.input, strings.Join(test.edges, ", "), gotDiag.EdgesString())
		}

		var attributes []string
		for key, value := range test.attributes {
			attributes = append(attributes, key+"="+value)
		}
		sort.Strings(attributes)
		if gotDiag.AttributesString() != strings.Join(attributes, "\n") {
			t.Fatalf("%s attributes error: %s, expected '%s', got: '%s'", test.description, test.input, strings.Join(attributes, "\n"), gotDiag.AttributesString())
		}
	}
}

func TestShouldNotParse(t *testing.T) {
	for _, test := range []struct {
		description string
		input       string
	}{
		{
			"No block",
			`
blockdiag
`,
		},
	} {
		_, err := ParseReader("shouldnotparse.diag", strings.NewReader(test.input))
		if err == nil {
			t.Fatalf("%s: should not parse, but didn't give an error with input %s", test.description, test.input)
		}
	}
}

func TestCircular(t *testing.T) {
	for _, test := range []struct {
		input    string
		circular bool
	}{
		{
			`
blockdiag{
	A;
}
`,
			false,
		},
		{
			`
blockdiag{
	A -> B -> C;
}
`,
			false,
		},
		{
			`
blockdiag{
	A -> A;
}
`,
			false,
		},
		{
			`
blockdiag{
	A -> B -> C -> A;
}
`,
			true,
		},
	} {
		got, err := ParseReader("shouldnotparse.diag", strings.NewReader(test.input))
		if err != nil {
			t.Fatalf("should not parse, but didn't give an error with input %s", test.input)
		}
		gotDiag, ok := got.(Diag)
		if !ok {
			t.Fatalf("assertion error: %s should parse to diag", test.input)
		}
		if gotDiag.FindCircular() != test.circular {
			t.Fatalf("expect %s to be circular == %t", test.input, test.circular)
		}
	}
}

func TestGetStartNodes(t *testing.T) {
	for _, test := range []struct {
		input      string
		startNodes []string
	}{
		{
			`
blockdiag{
	A -> B -> C;
}
`,
			[]string{"A"},
		},
		{
			`
blockdiag {
	A -> B -> C;
	D;
	E -> F;
}
`,
			[]string{"A", "D", "E"},
		},
		{
			`
blockdiag {
	D;
	E -> F;
	A -> B -> C;
}
`,
			[]string{"A", "D", "E"},
		},
	} {
		got, err := ParseReader("placeingrid.diag", strings.NewReader(test.input))
		if err != nil {
			t.Fatalf("should not parse, but didn't give an error with input %s", test.input)
		}
		gotDiag, ok := got.(Diag)
		if !ok {
			t.Fatalf("assertion error: %s should parse to diag", test.input)
		}
		// if gotDiag.PlaceInGrid() != test.circular {
		// 	t.Fatalf("expect %s to be circular == %t", test.input, test.circular)
		// }
		startNodes := gotDiag.getStartNodes()
		if len(startNodes) != len(test.startNodes) {
			t.Fatalf("Start Nodes count wrong, expected: %s, got: %s", strings.Join(test.startNodes, ", "), startNodes)
		}
		sort.Strings(test.startNodes)
		for i, n := range startNodes {
			if n.Name != test.startNodes[i] {
				t.Fatalf("Start Nodes do not match, expected: %s, got: %s", strings.Join(test.startNodes, ", "), startNodes)
			}
		}
	}
}

func TestPlaceInGrid(t *testing.T) {
	for _, test := range []struct {
		input  string
		output string
	}{
		{
			`
blockdiag{
	A -> B -> C;
}
`, `[A] [B] [C]
`,
		},
		{
			`
blockdiag{
	A -> B -> C;
	B -> D;
	A -> E -> C;
}
`, `[A] [B] [C]
        [D]
    [E]
`,
		}, {
			`
blockdiag{
	A -> B -> C -> B; # Circular with proper Start-Node
}
`, `[A] [B] [C]
`,
		}, {
			`
blockdiag{
	A -> B -> C -> A; # Circular without Start-Node
}
`, `[A] [B] [C]
`,
		}, {
			`
blockdiag{
	A; B; C; D; E; F; G; H; I; J; K; # 11 Rows
}
`, `[A]
[B]
[C]
[D]
[E]
[F]
[G]
[H]
[I]
[J]
[K]
`,
		}, {
			`
blockdiag{
	A -> B -> C -> D -> E -> F -> G -> H -> I -> J -> K; # 11 Cols
}
`, `[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K]
`,
		},
	} {
		got, err := ParseReader("placeingrid.diag", strings.NewReader(test.input))
		if err != nil {
			t.Fatalf("should not parse, but didn't give an error with input %s", test.input)
		}
		gotDiag, ok := got.(Diag)
		if !ok {
			t.Fatalf("assertion error: %s should parse to diag", test.input)
		}
		gotDiag.PlaceInGrid()
		if gotDiag.GridString() != test.output {
			t.Fatalf("expected: \n%s, got: \n%s", strings.Replace(test.output, " ", "\u00B7", -1), strings.Replace(gotDiag.GridString(), " ", "\u00B7", -1))
		}
	}
}

func TestDiagString(t *testing.T) {
	for _, test := range []struct {
		input  string
		output string
	}{
		{
			`
blockdiag{
	# One node, no connections
	A;
}
`, `
[A]
`,
		},
		{
			`
blockdiag{
	# Two nodes, no connections
	A;
	B;
}
`, `
[A]

[B]
`,
		},
		{
			`
blockdiag{
	# Two connected nodes
	A -> B;
}
`, `
[A]───>[B]
`,
		},
		{
			`
blockdiag{
	# Two seperate streams
	A -> B;
	C -> D;
}
`, `
[A]───>[B]

[C]───>[D]
`,
		},
		{
			`
blockdiag{
	# From one node to two nodes
	A -> B;
	A -> C;
}
`, `
[A]─┬─>[B]
    │
    └─>[C]
`,
		}, {
			`
blockdiag{
	# From one node to three nodes
	A -> B;
	A -> C;
	A -> D;
}
`, `
[A]─┬─>[B]
    │
    ├─>[C]
    │
    └─>[D]
`,
		}, {
			`
blockdiag{
	# Branch and merge
	A -> B -> D;
	A -> C -> D;
}
`, `
[A]─┬─>[B]─┬─>[D]
    │      │
    └─>[C]─┘
`,
		}, {
			`
blockdiag{
	# Branch and merge two rows
	A -> B -> C -> E;
	A -> D -> E;
}
`, `
[A]─┬─>[B]───>[C]─┬─>[E]
    │             │
    └─>[D]────────┘
`,
		},
		{
			`
blockdiag {
	# Branch and merge two rows with alternative way
	A -> B -> C -> D;
	A -> E -> D;
	E -> F;
}
`, `
[A]─┬─>[B]───>[C]─┬─>[D]
    │      ┌──────┘
    └─>[E]─┴─>[F]
`,
		}, {
			`
blockdiag{
	# Branch and merge over two cols
	A -> B -> E;
	A -> C;
	A -> D -> E;
}
`, `
[A]─┬─>[B]─┬─>[E]
    │      │
    ├─>[C] │
    │      │
    └─>[D]─┘
`,
		},
	} {
		got, err := ParseReader("diagstring.diag", strings.NewReader(test.input))
		if err != nil {
			t.Fatalf("should not parse, but didn't give an error with input %s", test.input)
		}
		gotDiag, ok := got.(Diag)
		if !ok {
			t.Fatalf("assertion error: %s should parse to diag", test.input)
		}
		gotDiag.PlaceInGrid()
		if gotDiag.String() != test.output {
			t.Fatalf("for: \n%s\nexpected: \n%s\ngot: \n%s", test.input, strings.Replace(test.output, " ", "\u00B7", -1), strings.Replace(gotDiag.String(), " ", "\u00B7", -1))
		}
	}
}
<commit_msg>Typos<commit_after>package blockdiag

import (
	"sort"
	"strings"
	"testing"
)

func TestShouldParser(t *testing.T) {
	for _, test := range []struct {
		description string
		input       string
		nodes       []string
		edges       []string
		attributes  map[string]string
	}{
		{
			"Empty diagram",
			`
blockdiag {}
`,
			[]string{},
			[]string{},
			map[string]string{},
		},
		{
			"Single Node",
			`
blockdiag {
	A;
}
`,
			[]string{"A"},
			[]string{},
			map[string]string{},
		},
		{
			// TODO Add test case for node chain without tailing ;
			"Node chain",
			`
blockdiag {
	A -> B;
}
`,
			[]string{"A", "B"},
			[]string{"A|B"},
			map[string]string{},
		},
		{
			"Multiple chains, using same nodes",
			`
blockdiag {
	A -> B -> C;
	A -> D;
}
`,
			[]string{"A", "B", "C", "D"},
			[]string{"A|B", "A|D", "B|C"},
			map[string]string{},
		},
		{
			"Self reference",
			`
blockdiag {
	A -> A;
}
`,
			[]string{"A"},
			[]string{"A|A"},
			map[string]string{},
		},
		{
			"Comment",
			`
# Comment
blockdiag # Comment
{
# Comment
	A; # Comment
# Comment
} # Comment
`,
			[]string{"A"},
			[]string{},
			map[string]string{},
		},
		{
			"Multi Char Node Names",
			`
blockdiag
{
	MultiCharNodeName1;
}
`,
			[]string{"MultiCharNodeName1"},
			[]string{},
			map[string]string{},
		},
		{
			"Digramm Attributes",
			`
blockdiag
{
	node_width = 128;
	A;
}
`,
			[]string{"A"},
			[]string{},
			map[string]string{
				"node_width": "128",
			},
		},
		{
			"Digramm type 'diagram'",
			`
diagram
{
	A;
}
`,
			[]string{"A"},
			[]string{},
			map[string]string{},
		},
	} {
		got, err := ParseReader("shouldparse.diag", strings.NewReader(test.input))
		if err != nil {
			t.Fatalf("%s: parse error: %s with input %s", test.description, err, test.input)
		}
		gotDiag, ok := got.(Diag)
		if !ok {
			t.Fatalf("%s: assertion error: %s should parse to diag", test.description, test.input)
		}
		if gotDiag.NodesString() != strings.Join(test.nodes, ", ") {
			t.Fatalf("%s: nodes error: %s, expected '%s', got: '%s'", test.description, test.input, strings.Join(test.nodes, ", "), gotDiag.NodesString())
		}
		if gotDiag.EdgesString() != strings.Join(test.edges, ", ") {
			t.Fatalf("%s edges error: %s, expected '%s', got: '%s'", test.description, test.input, strings.Join(test.edges, ", "), gotDiag.EdgesString())
		}

		var attributes []string
		for key, value := range test.attributes {
			attributes = append(attributes, key+"="+value)
		}
		sort.Strings(attributes)
		if gotDiag.AttributesString() != strings.Join(attributes, "\n") {
			t.Fatalf("%s attributes error: %s, expected '%s', got: '%s'", test.description, test.input, strings.Join(attributes, "\n"), gotDiag.AttributesString())
		}
	}
}

func TestShouldNotParse(t *testing.T) {
	for _, test := range []struct {
		description string
		input       string
	}{
		{
			"No block",
			`
blockdiag
`,
		},
	} {
		_, err := ParseReader("shouldnotparse.diag", strings.NewReader(test.input))
		if err == nil {
			t.Fatalf("%s: should not parse, but didn't give an error with input %s", test.description, test.input)
		}
	}
}

func TestCircular(t *testing.T) {
	for _, test := range []struct {
		input    string
		circular bool
	}{
		{
			`
blockdiag{
	A;
}
`,
			false,
		},
		{
			`
blockdiag{
	A -> B -> C;
}
`,
			false,
		},
		{
			`
blockdiag{
	A -> A;
}
`,
			false,
		},
		{
			`
blockdiag{
	A -> B -> C -> A;
}
`,
			true,
		},
	} {
		got, err := ParseReader("shouldnotparse.diag", strings.NewReader(test.input))
		if err != nil {
			t.Fatalf("should not parse, but didn't give an error with input %s", test.input)
		}
		gotDiag, ok := got.(Diag)
		if !ok {
			t.Fatalf("assertion error: %s should parse to diag", test.input)
		}
		if gotDiag.FindCircular() != test.circular {
			t.Fatalf("expect %s to be circular == %t", test.input, test.circular)
		}
	}
}

func TestGetStartNodes(t *testing.T) {
	for _, test := range []struct {
		input      string
		startNodes []string
	}{
		{
			`
blockdiag{
	A -> B -> C;
}
`,
			[]string{"A"},
		},
		{
			`
blockdiag {
	A -> B -> C;
	D;
	E -> F;
}
`,
			[]string{"A", "D", "E"},
		},
		{
			`
blockdiag {
	D;
	E -> F;
	A -> B -> C;
}
`,
			[]string{"A", "D", "E"},
		},
	} {
		got, err := ParseReader("placeingrid.diag", strings.NewReader(test.input))
		if err != nil {
			t.Fatalf("should not parse, but didn't give an error with input %s", test.input)
		}
		gotDiag, ok := got.(Diag)
		if !ok {
			t.Fatalf("assertion error: %s should parse to diag", test.input)
		}
		// if gotDiag.PlaceInGrid() != test.circular {
		// 	t.Fatalf("expect %s to be circular == %t", test.input, test.circular)
		// }
		startNodes := gotDiag.getStartNodes()
		if len(startNodes) != len(test.startNodes) {
			t.Fatalf("Start Nodes count wrong, expected: %s, got: %s", strings.Join(test.startNodes, ", "), startNodes)
		}
		sort.Strings(test.startNodes)
		for i, n := range startNodes {
			if n.Name != test.startNodes[i] {
				t.Fatalf("Start Nodes do not match, expected: %s, got: %s", strings.Join(test.startNodes, ", "), startNodes)
			}
		}
	}
}

func TestPlaceInGrid(t *testing.T) {
	for _, test := range []struct {
		input  string
		output string
	}{
		{
			`
blockdiag{
	A -> B -> C;
}
`, `[A] [B] [C]
`,
		},
		{
			`
blockdiag{
	A -> B -> C;
	B -> D;
	A -> E -> C;
}
`, `[A] [B] [C]
        [D]
    [E]
`,
		}, {
			`
blockdiag{
	A -> B -> C -> B; # Circular with proper Start-Node
}
`, `[A] [B] [C]
`,
		}, {
			`
blockdiag{
	A -> B -> C -> A; # Circular without Start-Node
}
`, `[A] [B] [C]
`,
		}, {
			`
blockdiag{
	A; B; C; D; E; F; G; H; I; J; K; # 11 Rows
}
`, `[A]
[B]
[C]
[D]
[E]
[F]
[G]
[H]
[I]
[J]
[K]
`,
		}, {
			`
blockdiag{
	A -> B -> C -> D -> E -> F -> G -> H -> I -> J -> K; # 11 Cols
}
`, `[A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K]
`,
		},
	} {
		got, err := ParseReader("placeingrid.diag", strings.NewReader(test.input))
		if err != nil {
			t.Fatalf("should not parse, but didn't give an error with input %s", test.input)
		}
		gotDiag, ok := got.(Diag)
		if !ok {
			t.Fatalf("assertion error: %s should parse to diag", test.input)
		}
		gotDiag.PlaceInGrid()
		if gotDiag.GridString() != test.output {
			t.Fatalf("expected: \n%s, got: \n%s", strings.Replace(test.output, " ", "\u00B7", -1), strings.Replace(gotDiag.GridString(), " ", "\u00B7", -1))
		}
	}
}

func TestDiagString(t *testing.T) {
	for _, test := range []struct {
		input  string
		output string
	}{
		{
			`
blockdiag{
	# One node, no connections
	A;
}
`, `
[A]
`,
		},
		{
			`
blockdiag{
	# Two nodes, no connections
	A;
	B;
}
`, `
[A]

[B]
`,
		},
		{
			`
blockdiag{
	# Two connected nodes
	A -> B;
}
`, `
[A]───>[B]
`,
		},
		{
			`
blockdiag{
	# Two seperate streams
	A -> B;
	C -> D;
}
`, `
[A]───>[B]

[C]───>[D]
`,
		},
		{
			`
blockdiag{
	# From one node to two nodes
	A -> B;
	A -> C;
}
`, `
[A]─┬─>[B]
    │
    └─>[C]
`,
		}, {
			`
blockdiag{
	# From one node to three nodes
	A -> B;
	A -> C;
	A -> D;
}
`, `
[A]─┬─>[B]
    │
    ├─>[C]
    │
    └─>[D]
`,
		}, {
			`
blockdiag{
	# Branch and merge
	A -> B -> D;
	A -> C -> D;
}
`, `
[A]─┬─>[B]─┬─>[D]
    │      │
    └─>[C]─┘
`,
		}, {
			`
blockdiag{
	# Branch and merge two cols
	A -> B -> C -> E;
	A -> D -> E;
}
`, `
[A]─┬─>[B]───>[C]─┬─>[E]
    │             │
    └─>[D]────────┘
`,
		},
		{
			`
blockdiag {
	# Branch and merge two cols with alternative way
	A -> B -> C -> D;
	A -> E -> D;
	E -> F;
}
`, `
[A]─┬─>[B]───>[C]─┬─>[D]
    │      ┌──────┘
    └─>[E]─┴─>[F]
`,
		}, {
			`
blockdiag{
	# Branch and merge over two rows
	A -> B -> E;
	A -> C;
	A -> D -> E;
}
`, `
[A]─┬─>[B]─┬─>[E]
    │      │
    ├─>[C] │
    │      │
    └─>[D]─┘
`,
		},
	} {
		got, err := ParseReader("diagstring.diag", strings.NewReader(test.input))
		if err != nil {
			t.Fatalf("should not parse, but didn't give an error with input %s", test.input)
		}
		gotDiag, ok := got.(Diag)
		if !ok {
			t.Fatalf("assertion error: %s should parse to diag", test.input)
		}
		gotDiag.PlaceInGrid()
		if gotDiag.String() != test.output {
			t.Fatalf("for: \n%s\nexpected: \n%s\ngot: \n%s", test.input, strings.Replace(test.output, " ", "\u00B7", -1), strings.Replace(gotDiag.String(), " ", "\u00B7", -1))
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 sdb

import (
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"testing"
)

func TestGet(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type GetTest struct {
	domainTest

	item            string
	constistentRead bool
	names           []string

	attributes []Attribute
	err        error
}

func (t *GetTest) SetUp(i *TestInfo) {
	// Call common setup code.
	t.domainTest.SetUp(i)

	// Make the request legal by default.
	t.item = "foo"
}

func (t *GetTest) callDomain() {
	t.attributes, t.err = t.domain.GetAttributes(
		ItemName(t.item),
		t.constistentRead,
		t.names)
}

func init() { RegisterTestSuite(&GetTest{}) }

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *GetTest) ItemNameEmpty() {
	t.item = ""

	// Call
	t.callDomain()

	ExpectThat(t.err, Error(HasSubstr("item")))
	ExpectThat(t.err, Error(HasSubstr("name")))
	ExpectThat(t.err, Error(HasSubstr("empty")))
}

func (t *GetTest) ItemNameInvalid() {
	t.item = "taco\x80\x81\x82"

	// Call
	t.callDomain()

	ExpectThat(t.err, Error(HasSubstr("item")))
	ExpectThat(t.err, Error(HasSubstr("name")))
	ExpectThat(t.err, Error(HasSubstr("UTF-8")))
}

func (t *GetTest) OneAttributeNameEmpty() {
	t.names = []string{"taco", "", "burrito"}

	// Call
	t.callDomain()

	ExpectThat(t.err, Error(HasSubstr("attribute")))
	ExpectThat(t.err, Error(HasSubstr("name")))
	ExpectThat(t.err, Error(HasSubstr("empty")))
}

func (t *GetTest) OneAttributeNameInvalid() {
	t.names = []string{"taco", "\x80\x81\x82", "burrito"}

	// Call
	t.callDomain()

	ExpectThat(t.err, Error(HasSubstr("attribute")))
	ExpectThat(t.err, Error(HasSubstr("name")))
	ExpectThat(t.err, Error(HasSubstr("UTF-8")))
}

func (t *GetTest) InconsistentReadWithNoAttributeNames() {
	ExpectEq("TODO", "")
}

func (t *GetTest) ConsistentRead() {
	ExpectEq("TODO", "")
}

func (t *GetTest) SomeAttributeNames() {
	ExpectEq("TODO", "")
}

func (t *GetTest) ConnReturnsError() {
	ExpectEq("TODO", "")
}

func (t *GetTest) ConnReturnsJunk() {
	ExpectEq("TODO", "")
}

func (t *GetTest) NoAttributesInResponse() {
	ExpectEq("TODO", "")
}

func (t *GetTest) SomeAttributesInResponse() {
	ExpectEq("TODO", "")
}
<commit_msg>GetTest.InconsistentReadWithNoAttributeNames<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 sdb

import (
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"testing"
)

func TestGet(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type GetTest struct {
	domainTest

	item            string
	constistentRead bool
	names           []string

	attributes []Attribute
	err        error
}

func (t *GetTest) SetUp(i *TestInfo) {
	// Call common setup code.
	t.domainTest.SetUp(i)

	// Make the request legal by default.
	t.item = "foo"
}

func (t *GetTest) callDomain() {
	t.attributes, t.err = t.domain.GetAttributes(
		ItemName(t.item),
		t.constistentRead,
		t.names)
}

func init() { RegisterTestSuite(&GetTest{}) }

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *GetTest) ItemNameEmpty() {
	t.item = ""

	// Call
	t.callDomain()

	ExpectThat(t.err, Error(HasSubstr("item")))
	ExpectThat(t.err, Error(HasSubstr("name")))
	ExpectThat(t.err, Error(HasSubstr("empty")))
}

func (t *GetTest) ItemNameInvalid() {
	t.item = "taco\x80\x81\x82"

	// Call
	t.callDomain()

	ExpectThat(t.err, Error(HasSubstr("item")))
	ExpectThat(t.err, Error(HasSubstr("name")))
	ExpectThat(t.err, Error(HasSubstr("UTF-8")))
}

func (t *GetTest) OneAttributeNameEmpty() {
	t.names = []string{"taco", "", "burrito"}

	// Call
	t.callDomain()

	ExpectThat(t.err, Error(HasSubstr("attribute")))
	ExpectThat(t.err, Error(HasSubstr("name")))
	ExpectThat(t.err, Error(HasSubstr("empty")))
}

func (t *GetTest) OneAttributeNameInvalid() {
	t.names = []string{"taco", "\x80\x81\x82", "burrito"}

	// Call
	t.callDomain()

	ExpectThat(t.err, Error(HasSubstr("attribute")))
	ExpectThat(t.err, Error(HasSubstr("name")))
	ExpectThat(t.err, Error(HasSubstr("UTF-8")))
}

func (t *GetTest) InconsistentReadWithNoAttributeNames() {
	t.item = "taco"
	t.constistentRead = false
	t.names = []string{}

	// Call
	t.callDomain()
	AssertNe(nil, t.c.req, "Error: %v", t.err)

	AssertThat(
		getSortedKeys(t.c.req),
		ElementsAre(
			"DomainName",
			"ItemName",
		),
	)

	ExpectEq(t.name, t.c.req["DomainName"])
	ExpectEq("taco", t.c.req["ItemName"])
}

func (t *GetTest) ConsistentRead() {
	ExpectEq("TODO", "")
}

func (t *GetTest) SomeAttributeNames() {
	ExpectEq("TODO", "")
}

func (t *GetTest) ConnReturnsError() {
	ExpectEq("TODO", "")
}

func (t *GetTest) ConnReturnsJunk() {
	ExpectEq("TODO", "")
}

func (t *GetTest) NoAttributesInResponse() {
	ExpectEq("TODO", "")
}

func (t *GetTest) SomeAttributesInResponse() {
	ExpectEq("TODO", "")
}
<|endoftext|>


<commit_before>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 ogletest

import (
	"github.com/jacobsa/ogletest/internal"
	"testing"
)

////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////

// Set up a new test state with empty fields.
func setUpCurrentTest() {
	internal.CurrentTest = &internal.TestState{}
}

////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////

func TestNoCurrentTest(t *testing.T) {
	panicked := false

	defer func() {
		if !panicked {
			t.Errorf("Expected panic; got none.")
		}
	}()

	defer func() {
		if r := recover(); r != nil {
			panicked = true
		}
	}()

	internal.CurrentTest = nil
	ExpectThat(17, Equals(17))
}

func TestNoFailure(t *testing.T) {
}

func TestMatchFalseWithoutMessages(t *testing.T) {
}

func TestMatchUndefinedWithoutMessages(t *testing.T) {
}

func TestFailureWithMatcherMessage(t *testing.T) {
}

func TestFailureWithUserMessage(t *testing.T) {
}

func TestAdditionalFailure(t *testing.T) {
}
<commit_msg>TestNoFailure<commit_after>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 ogletest

import (
	"github.com/jacobsa/ogletest/internal"
	"testing"
)

////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////

// Set up a new test state with empty fields.
func setUpCurrentTest() {
	internal.CurrentTest = &internal.TestState{}
}

////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////

func TestNoCurrentTest(t *testing.T) {
	panicked := false

	defer func() {
		if !panicked {
			t.Errorf("Expected panic; got none.")
		}
	}()

	defer func() {
		if r := recover(); r != nil {
			panicked = true
		}
	}()

	internal.CurrentTest = nil
	ExpectThat(17, Equals(17))
}

func TestNoFailure(t *testing.T) {
	ExpectThat(17, Equals(17))

	expectedLen := 0
	actualLen := len(internal.CurrentTest.FailureRecords)
	if expectedLen != actualLen {
		t.Errorf("Expected %d failures, got %d", expectedLen, actualLen)
	}
}

func TestMatchFalseWithoutMessages(t *testing.T) {
}

func TestMatchUndefinedWithoutMessages(t *testing.T) {
}

func TestFailureWithMatcherMessage(t *testing.T) {
}

func TestFailureWithUserMessage(t *testing.T) {
}

func TestAdditionalFailure(t *testing.T) {
}
<|endoftext|>