<commit_before>package db

import (
	"fmt"
	"net/url"
	"strings"

	"github.com/lxc/lxd/lxd/db/generate/lex"
	"github.com/lxc/lxd/shared"
)

// Mapping holds information for mapping database tables to a Go structure.
type Mapping struct {
	Package    string    // Package of the Go struct
	Name       string    // Name of the Go struct.
	Fields     []*Field  // Metadata about the Go struct.
	Filterable bool      // Whether the Go struct has a Filter companion struct for filtering queries.
	Filters    []*Field  // Metadata about the Go struct used for filter fields.
	Type       TableType // Type of table structure for this Go struct.

}

// TableType represents the logical type of the table defined by the Go struct.
type TableType int

// EntityTable represents the type for any entity that maps to a Go struct.
var EntityTable = TableType(0)

// ReferenceTable represents the type for for any entity that contains an
// 'entity_id' field mapping to a parent entity.
var ReferenceTable = TableType(1)

// AssociationTable represents the type for an entity that associates two
// other entities.
var AssociationTable = TableType(2)

// MapTable represents the type for a table storing key/value pairs.
var MapTable = TableType(3)

// NaturalKey returns the struct fields that can be used as natural key for
// uniquely identifying a row in the underlying table (==.
//
// By convention the natural key field is the one called "Name", unless
// specified otherwise with the `db:natural_key` tags.
func (m *Mapping) NaturalKey() []*Field {
	key := []*Field{}

	for _, field := range m.Fields {
		if field.Config.Get("primary") != "" {
			key = append(key, field)
		}
	}

	if len(key) == 0 {
		// Default primary key.
		key = append(key, m.FieldByName("Name"))
	}

	return key
}

// Identifier returns the field that uniquely identifies this entity.
func (m *Mapping) Identifier() *Field {
	for _, field := range m.NaturalKey() {
		if field.Name == "Name" || field.Name == "Fingerprint" {
			return field
		}
	}

	return nil
}

// ContainsFields checks that the mapping contains fields with the same type
// and name of given ones.
func (m *Mapping) ContainsFields(fields []*Field) bool {
	matches := map[*Field]bool{}

	for _, field := range m.Fields {
		for _, other := range fields {
			if field.Name == other.Name && field.Type.Name == other.Type.Name {
				matches[field] = true
			}
		}
	}

	return len(matches) == len(fields)
}

// FieldByName returns the field with the given name, if any.
func (m *Mapping) FieldByName(name string) *Field {
	for _, field := range m.Fields {
		if field.Name == name {
			return field
		}
	}

	return nil
}

// ActiveFilters returns the active filter fields for the kind of method.
func (m *Mapping) ActiveFilters(kind string) []*Field {
	names := activeFilters(kind)
	fields := []*Field{}
	for _, name := range names {
		field := m.FieldByName(name)
		if field != nil {
			fields = append(fields, field)
		}
	}
	return fields
}

// FieldColumnName returns the column name of the field with the given name,
// prefixed with the entity's table name.
func (m *Mapping) FieldColumnName(name string, table string) string {
	field := m.FieldByName(name)
	return fmt.Sprintf("%s.%s", table, field.Column())
}

// FilterFieldByName returns the field with the given name if that field can be
// used as query filter, an error otherwise.
func (m *Mapping) FilterFieldByName(name string) (*Field, error) {
	for _, filter := range m.Filters {
		if name == filter.Name {
			if filter.Type.Code != TypeColumn {
				return nil, fmt.Errorf("Unknown filter %q not a column", name)
			}

			return filter, nil
		}
	}

	return nil, fmt.Errorf("Unknown filter %q", name)
}

// ColumnFields returns the fields that map directly to a database column,
// either on this table or on a joined one.
func (m *Mapping) ColumnFields(exclude ...string) []*Field {
	fields := []*Field{}

	for _, field := range m.Fields {
		if shared.StringInSlice(field.Name, exclude) {
			continue
		}

		if field.Type.Code == TypeColumn {
			fields = append(fields, field)
		}
	}

	return fields
}

// ScalarFields returns the fields that map directly to a single database
// column on another table that can be joined to this one.
func (m *Mapping) ScalarFields() []*Field {
	fields := []*Field{}

	for _, field := range m.Fields {
		if field.Config.Get("join") != "" || field.Config.Get("leftjoin") != "" {
			fields = append(fields, field)
		}
	}

	return fields
}

// RefFields returns the fields that are one-to-many references to other
// tables.
func (m *Mapping) RefFields() []*Field {
	fields := []*Field{}

	for _, field := range m.Fields {
		if field.Type.Code == TypeSlice || field.Type.Code == TypeMap {
			fields = append(fields, field)
		}
	}

	return fields
}

// FieldArgs converts the given fields to function arguments, rendering their
// name and type.
func (m *Mapping) FieldArgs(fields []*Field, extra ...string) string {
	args := []string{}

	for _, field := range fields {
		name := lex.Minuscule(field.Name)
		if name == "type" {
			name = lex.Minuscule(m.Name) + field.Name
		}

		arg := fmt.Sprintf("%s %s", name, field.Type.Name)
		args = append(args, arg)
	}

	args = append(args, extra...)

	return strings.Join(args, ", ")
}

// FieldParams converts the given fields to function parameters, rendering their
// name.
func (m *Mapping) FieldParams(fields []*Field) string {
	args := make([]string, len(fields))
	for i, field := range fields {
		name := lex.Minuscule(field.Name)
		if name == "type" {
			name = lex.Minuscule(m.Name) + field.Name
		}

		args[i] = name
	}

	return strings.Join(args, ", ")
}

// Field holds all information about a field in a Go struct that is relevant
// for database code generation.
type Field struct {
	Name    string
	Type    Type
	Primary bool // Whether this field is part of the natural primary key.
	Config  url.Values
}

// Stmt must be used only on a non-columnar field. It returns the name of
// statement that should be used to fetch this field. A statement with that
// name must have been generated for the entity at hand.
func (f *Field) Stmt() string {
	switch f.Name {
	case "UsedBy":
		return "used_by"
	default:
		return ""
	}
}

// IsScalar returns true if the field is a scalar column value from a joined table.
func (f *Field) IsScalar() bool {
	return f.JoinConfig() != ""
}

// IsIndirect returns true if the field is a scalar column value from a joined
// table that in turn requires another join.
func (f *Field) IsIndirect() bool {
	return f.IsScalar() && f.Config.Get("via") != ""
}

// IsPrimary returns true if the field part of the natural key.
func (f *Field) IsPrimary() bool {
	return f.Config.Get("primary") != "" || f.Name == "Name"
}

// Column returns the name of the database column the field maps to. The type
// code of the field must be TypeColumn.
func (f *Field) Column() string {
	if f.Type.Code != TypeColumn {
		panic("attempt to get column name of non-column field")
	}

	column := lex.Snake(f.Name)

	join := f.JoinConfig()
	if join != "" {
		column = fmt.Sprintf("%s AS %s", join, column)
	}

	return column
}

func (f Field) JoinConfig() string {
	join := f.Config.Get("join")
	if join == "" {
		join = f.Config.Get("leftjoin")
	}

	return join
}

// ScalarTableColumn gets the table and column from the join configuration.
func (f Field) ScalarTableColumn() (string, string, error) {
	join := f.JoinConfig()

	if join == "" {
		return "", "", fmt.Errorf("Missing join config for field %q", f.Name)
	}

	joinFields := strings.Split(join, ".")
	if len(joinFields) != 2 {
		return "", "", fmt.Errorf("Join config must be of the format <table>.<column> for field %q", f.Name)
	}

	return joinFields[0], joinFields[1], nil
}

// FieldNames returns the names of the given fields.
func FieldNames(fields []*Field) []string {
	names := []string{}
	for _, f := range fields {
		names = append(names, f.Name)
	}

	return names
}

// Type holds all information about a field in a field type that is relevant
// for database code generation.
type Type struct {
	Name string
	Code int
}

// Possible type code.
const (
	TypeColumn = iota
	TypeSlice
	TypeMap
)
<commit_msg>lxd/db/generate/db/mapping: Add field-to-sql clause conversion helpers<commit_after>package db

import (
	"fmt"
	"go/ast"
	"net/url"
	"strings"

	"github.com/lxc/lxd/lxd/db/generate/lex"
	"github.com/lxc/lxd/shared"
)

// Mapping holds information for mapping database tables to a Go structure.
type Mapping struct {
	Package    string    // Package of the Go struct
	Name       string    // Name of the Go struct.
	Fields     []*Field  // Metadata about the Go struct.
	Filterable bool      // Whether the Go struct has a Filter companion struct for filtering queries.
	Filters    []*Field  // Metadata about the Go struct used for filter fields.
	Type       TableType // Type of table structure for this Go struct.

}

// TableType represents the logical type of the table defined by the Go struct.
type TableType int

// EntityTable represents the type for any entity that maps to a Go struct.
var EntityTable = TableType(0)

// ReferenceTable represents the type for for any entity that contains an
// 'entity_id' field mapping to a parent entity.
var ReferenceTable = TableType(1)

// AssociationTable represents the type for an entity that associates two
// other entities.
var AssociationTable = TableType(2)

// MapTable represents the type for a table storing key/value pairs.
var MapTable = TableType(3)

// NaturalKey returns the struct fields that can be used as natural key for
// uniquely identifying a row in the underlying table (==.
//
// By convention the natural key field is the one called "Name", unless
// specified otherwise with the `db:natural_key` tags.
func (m *Mapping) NaturalKey() []*Field {
	key := []*Field{}

	for _, field := range m.Fields {
		if field.Config.Get("primary") != "" {
			key = append(key, field)
		}
	}

	if len(key) == 0 {
		// Default primary key.
		key = append(key, m.FieldByName("Name"))
	}

	return key
}

// Identifier returns the field that uniquely identifies this entity.
func (m *Mapping) Identifier() *Field {
	for _, field := range m.NaturalKey() {
		if field.Name == "Name" || field.Name == "Fingerprint" {
			return field
		}
	}

	return nil
}

// TableName determines the table associated to the struct.
// - Individual fields may bypass this with their own `sql=<table>.<column>` tags.
// - The override `table=<name>` directive key is checked first.
// - The struct name itself is used to approximate the table name if none of the above apply.
func (m *Mapping) TableName(entity string, override string) string {
	table := entityTable(entity, override)
	if m.Type == ReferenceTable || m.Type == MapTable {
		table = "%s_" + table
	}

	return table
}

// ContainsFields checks that the mapping contains fields with the same type
// and name of given ones.
func (m *Mapping) ContainsFields(fields []*Field) bool {
	matches := map[*Field]bool{}

	for _, field := range m.Fields {
		for _, other := range fields {
			if field.Name == other.Name && field.Type.Name == other.Type.Name {
				matches[field] = true
			}
		}
	}

	return len(matches) == len(fields)
}

// FieldByName returns the field with the given name, if any.
func (m *Mapping) FieldByName(name string) *Field {
	for _, field := range m.Fields {
		if field.Name == name {
			return field
		}
	}

	return nil
}

// ActiveFilters returns the active filter fields for the kind of method.
func (m *Mapping) ActiveFilters(kind string) []*Field {
	names := activeFilters(kind)
	fields := []*Field{}
	for _, name := range names {
		field := m.FieldByName(name)
		if field != nil {
			fields = append(fields, field)
		}
	}
	return fields
}

// FieldColumnName returns the column name of the field with the given name,
// prefixed with the entity's table name.
func (m *Mapping) FieldColumnName(name string, table string) string {
	field := m.FieldByName(name)
	return fmt.Sprintf("%s.%s", table, field.Column())
}

// FilterFieldByName returns the field with the given name if that field can be
// used as query filter, an error otherwise.
func (m *Mapping) FilterFieldByName(name string) (*Field, error) {
	for _, filter := range m.Filters {
		if name == filter.Name {
			if filter.Type.Code != TypeColumn {
				return nil, fmt.Errorf("Unknown filter %q not a column", name)
			}

			return filter, nil
		}
	}

	return nil, fmt.Errorf("Unknown filter %q", name)
}

// ColumnFields returns the fields that map directly to a database column,
// either on this table or on a joined one.
func (m *Mapping) ColumnFields(exclude ...string) []*Field {
	fields := []*Field{}

	for _, field := range m.Fields {
		if shared.StringInSlice(field.Name, exclude) {
			continue
		}

		if field.Type.Code == TypeColumn {
			fields = append(fields, field)
		}
	}

	return fields
}

// ScalarFields returns the fields that map directly to a single database
// column on another table that can be joined to this one.
func (m *Mapping) ScalarFields() []*Field {
	fields := []*Field{}

	for _, field := range m.Fields {
		if field.Config.Get("join") != "" || field.Config.Get("leftjoin") != "" {
			fields = append(fields, field)
		}
	}

	return fields
}

// RefFields returns the fields that are one-to-many references to other
// tables.
func (m *Mapping) RefFields() []*Field {
	fields := []*Field{}

	for _, field := range m.Fields {
		if field.Type.Code == TypeSlice || field.Type.Code == TypeMap {
			fields = append(fields, field)
		}
	}

	return fields
}

// FieldArgs converts the given fields to function arguments, rendering their
// name and type.
func (m *Mapping) FieldArgs(fields []*Field, extra ...string) string {
	args := []string{}

	for _, field := range fields {
		name := lex.Minuscule(field.Name)
		if name == "type" {
			name = lex.Minuscule(m.Name) + field.Name
		}

		arg := fmt.Sprintf("%s %s", name, field.Type.Name)
		args = append(args, arg)
	}

	args = append(args, extra...)

	return strings.Join(args, ", ")
}

// FieldParams converts the given fields to function parameters, rendering their
// name.
func (m *Mapping) FieldParams(fields []*Field) string {
	args := make([]string, len(fields))
	for i, field := range fields {
		name := lex.Minuscule(field.Name)
		if name == "type" {
			name = lex.Minuscule(m.Name) + field.Name
		}

		args[i] = name
	}

	return strings.Join(args, ", ")
}

// Field holds all information about a field in a Go struct that is relevant
// for database code generation.
type Field struct {
	Name    string
	Type    Type
	Primary bool // Whether this field is part of the natural primary key.
	Config  url.Values
}

// Stmt must be used only on a non-columnar field. It returns the name of
// statement that should be used to fetch this field. A statement with that
// name must have been generated for the entity at hand.
func (f *Field) Stmt() string {
	switch f.Name {
	case "UsedBy":
		return "used_by"
	default:
		return ""
	}
}

// IsScalar returns true if the field is a scalar column value from a joined table.
func (f *Field) IsScalar() bool {
	return f.JoinConfig() != ""
}

// IsIndirect returns true if the field is a scalar column value from a joined
// table that in turn requires another join.
func (f *Field) IsIndirect() bool {
	return f.IsScalar() && f.Config.Get("via") != ""
}

// IsPrimary returns true if the field part of the natural key.
func (f *Field) IsPrimary() bool {
	return f.Config.Get("primary") != "" || f.Name == "Name"
}

// Column returns the name of the database column the field maps to. The type
// code of the field must be TypeColumn.
func (f *Field) Column() string {
	if f.Type.Code != TypeColumn {
		panic("attempt to get column name of non-column field")
	}

	column := lex.Snake(f.Name)

	join := f.JoinConfig()
	if join != "" {
		column = fmt.Sprintf("%s AS %s", join, column)
	}

	return column
}

// SelectColumn returns a column name suitable for use with 'SELECT' statements.
// - Applies a `coalesce()` function if the 'coalesce' tag is present.
// - Returns the column in the form '<joinTable>.<joinColumn> AS <column>' if the `join` tag is present.
func (f *Field) SelectColumn(mapping *Mapping, primaryTable string) (string, error) {
	// ReferenceTable and MapTable require specific fields, so parse those instead of checking tags.
	if mapping.Type == ReferenceTable || mapping.Type == MapTable {
		table := primaryTable
		column := fmt.Sprintf("%s.%s", table, lex.Snake(f.Name))
		column = strings.Replace(column, "reference", "%s", -1)

		return column, nil
	}

	tableName, columnName, err := f.SQLConfig()
	if err != nil {
		return "", err
	}

	if tableName == "" {
		tableName = primaryTable
	}

	if columnName == "" {
		columnName = lex.Snake(f.Name)
	}

	var column string
	join := f.JoinConfig()
	if join != "" {
		column = join
	} else {
		column = fmt.Sprintf("%s.%s", tableName, columnName)
	}

	coalesce, ok := f.Config["coalesce"]
	if ok {
		column = fmt.Sprintf("coalesce(%s, %s)", column, coalesce[0])
	}

	if join != "" {
		column = fmt.Sprintf("%s AS %s", column, columnName)
	}

	return column, nil
}

// OrderBy returns a column name suitable for use with the 'ORDER BY' clause.
func (f *Field) OrderBy(mapping *Mapping, primaryTable string) (string, error) {
	// ReferenceTable and MapTable require specific fields, so parse those instead of checking tags.
	if mapping.Type == ReferenceTable || mapping.Type == MapTable {
		table := primaryTable
		column := fmt.Sprintf("%s.%s", table, lex.Snake(f.Name))
		column = strings.Replace(column, "reference", "%s", -1)

		return column, nil
	}

	if f.IsScalar() {
		tableName, _, err := f.ScalarTableColumn()
		if err != nil {
			return "", err
		}

		return tableName + ".id", nil
	}

	tableName, columnName, err := f.SQLConfig()
	if err != nil {
		return "", nil
	}

	if columnName == "" {
		columnName = lex.Snake(f.Name)
	}

	if tableName == "" {
		tableName = primaryTable
	}

	if tableName != "" {
		return fmt.Sprintf("%s.%s", tableName, columnName), nil
	}

	return fmt.Sprintf("%s.%s", entityTable(mapping.Name, tableName), columnName), nil
}

// JoinClause returns an SQL 'JOIN' clause using the 'join'  and 'joinon' tags, if present.
func (f *Field) JoinClause(mapping *Mapping, table string) (string, error) {
	joinTemplate := "\n  JOIN %s ON %s = %s.id"
	if f.Config.Get("join") != "" && f.Config.Get("leftjoin") != "" {
		return "", fmt.Errorf("Cannot join and leftjoin at the same time for field %q of struct %q", f.Name, mapping.Name)
	}

	join := f.JoinConfig()
	if f.Config.Get("leftjoin") != "" {
		joinTemplate = strings.Replace(joinTemplate, "JOIN", "LEFT JOIN", -1)
	}

	joinTable, _, ok := strings.Cut(join, ".")
	if !ok {
		return "", fmt.Errorf("'join' tag for field %q of struct %q must be of form <table>.<column>", f.Name, mapping.Name)
	}

	joinOn := f.Config.Get("joinon")
	if joinOn == "" {
		tableName, columnName, err := f.SQLConfig()
		if err != nil {
			return "", err
		}

		if tableName != "" && columnName != "" {
			joinOn = fmt.Sprintf("%s.%s", tableName, columnName)
		} else {
			joinOn = fmt.Sprintf("%s.%s_id", table, lex.Singular(joinTable))
		}
	}

	_, _, ok = strings.Cut(joinOn, ".")
	if !ok {
		return "", fmt.Errorf("'joinon' tag of field %q of struct %q must be of form '<table>.<column>'", f.Name, mapping.Name)
	}

	return fmt.Sprintf(joinTemplate, joinTable, joinOn, joinTable), nil
}

// InsertColumn returns a column name and parameter value suitable for an 'INSERT', 'UPDATE', or 'DELETE' statement.
// - If a 'join' tag is present, the package will be searched for the corresponding 'jointableID' registered statement
// to select the ID to insert into this table.
// - If a 'joinon' tag is present, but this table is not among the conditions, then the join will be considered indirect,
// and an empty string will be returned.
func (f *Field) InsertColumn(pkg *ast.Package, mapping *Mapping, primaryTable string) (string, string, error) {
	var column string
	var value string
	var err error
	if f.IsScalar() {
		tableName, columnName, err := f.SQLConfig()
		if err != nil {
			return "", "", err
		}

		if tableName == "" {
			tableName = primaryTable
		}

		// If there is a 'joinon' tag present without this table in the condition, then assume there is no column for this field.
		joinOn := f.Config.Get("joinon")
		if joinOn != "" {
			before, _, ok := strings.Cut(joinOn, ".")
			if !ok {
				return "", "", fmt.Errorf("'joinon' tag of field %q of struct %q must be of form '<table>.<column>'", f.Name, mapping.Name)
			}

			if tableName != before {
				return "", "", nil
			}
		}

		if columnName != "" {
			column = columnName
		} else {
			column = lex.Snake(f.Name) + "_id"
		}

		table, _, ok := strings.Cut(f.JoinConfig(), ".")
		if !ok {
			return "", "", fmt.Errorf("'join' tag of field %q of struct %q must be of form <table>.<column>", f.Name, mapping.Name)
		}

		joinStmt, err := ParseStmt(pkg, stmtCodeVar(lex.Singular(table), "ID"))
		if err != nil {
			return "", "", fmt.Errorf("Failed to find existing primary key statement for field %q of struct %q: %w", f.Name, mapping.Name, err)
		}

		value = fmt.Sprintf("(%s)", strings.Replace(strings.Replace(joinStmt, "`", "", -1), "\n", "", -1))
		value = strings.Replace(value, "  ", " ", -1)
	} else {
		column, err = f.SelectColumn(mapping, primaryTable)
		if err != nil {
			return "", "", err
		}

		// Strip the table name and coalesce function if present.
		_, column, _ = strings.Cut(column, ".")
		column, _, _ = strings.Cut(column, ",")

		if mapping.Type == ReferenceTable || mapping.Type == MapTable {
			column = strings.Replace(column, "reference", "%s", -1)
		}

		value = "?"
	}

	return column, value, nil
}

func (f Field) JoinConfig() string {
	join := f.Config.Get("join")
	if join == "" {
		join = f.Config.Get("leftjoin")
	}

	return join
}

// SQLConfig returns the table and column specified by the 'sql' config key, if present.
func (f Field) SQLConfig() (string, string, error) {
	where := f.Config.Get("sql")

	if where == "" {
		return "", "", nil
	}

	table, column, ok := strings.Cut(where, ".")
	if !ok {
		return "", "", fmt.Errorf("'sql' config for field %q should be of the form <table>.<column>", f.Name)
	}

	return table, column, nil
}

// ScalarTableColumn gets the table and column from the join configuration.
func (f Field) ScalarTableColumn() (string, string, error) {
	join := f.JoinConfig()

	if join == "" {
		return "", "", fmt.Errorf("Missing join config for field %q", f.Name)
	}

	joinFields := strings.Split(join, ".")
	if len(joinFields) != 2 {
		return "", "", fmt.Errorf("Join config must be of the format <table>.<column> for field %q", f.Name)
	}

	return joinFields[0], joinFields[1], nil
}

// FieldNames returns the names of the given fields.
func FieldNames(fields []*Field) []string {
	names := []string{}
	for _, f := range fields {
		names = append(names, f.Name)
	}

	return names
}

// Type holds all information about a field in a field type that is relevant
// for database code generation.
type Type struct {
	Name string
	Code int
}

// Possible type code.
const (
	TypeColumn = iota
	TypeSlice
	TypeMap
)
<|endoftext|>


<commit_before>package btrfs

import (
	"fmt"
	"github.com/dennwc/ioctl"
	"io"
	"os"
	"path/filepath"
	"strconv"
	"syscall"
)

const SuperMagic = 0x9123683E

func CloneFile(dst, src *os.File) error {
	return iocClone(dst, src)
}

func Open(path string, ro bool) (*FS, error) {
	if ok, err := IsSubVolume(path); err != nil {
		return nil, err
	} else if !ok {
		return nil, ErrNotBtrfs{Path: path}
	}
	var (
		dir *os.File
		err error
	)
	if ro {
		dir, err = os.OpenFile(path, os.O_RDONLY|syscall.O_NOATIME, 0644)
	} else {
		dir, err = os.Open(path)
	}
	if err != nil {
		return nil, err
	} else if st, err := dir.Stat(); err != nil {
		dir.Close()
		return nil, err
	} else if !st.IsDir() {
		dir.Close()
		return nil, fmt.Errorf("not a directory: %s", path)
	}
	return &FS{f: dir}, nil
}

type FS struct {
	f *os.File
}

func (f *FS) Close() error {
	return f.f.Close()
}

type Info struct {
	MaxID          uint64
	NumDevices     uint64
	FSID           FSID
	NodeSize       uint32
	SectorSize     uint32
	CloneAlignment uint32
}

func (f *FS) Info() (out Info, err error) {
	var arg btrfs_ioctl_fs_info_args
	arg, err = iocFsInfo(f.f)
	if err == nil {
		out = Info{
			MaxID:          arg.max_id,
			NumDevices:     arg.num_devices,
			FSID:           arg.fsid,
			NodeSize:       arg.nodesize,
			SectorSize:     arg.sectorsize,
			CloneAlignment: arg.clone_alignment,
		}
	}
	return
}

type DevStats struct {
	WriteErrs uint64
	ReadErrs  uint64
	FlushErrs uint64
	// Checksum error, bytenr error or contents is illegal: this is an
	// indication that the block was damaged during read or write, or written to
	// wrong location or read from wrong location.
	CorruptionErrs uint64
	// An indication that blocks have not been written.
	GenerationErrs uint64
	Unknown        []uint64
}

func (f *FS) GetDevStats(id uint64) (out DevStats, err error) {
	var arg btrfs_ioctl_get_dev_stats
	arg.devid = id
	//arg.nr_items = _BTRFS_DEV_STAT_VALUES_MAX
	arg.flags = 0
	if err = ioctl.Do(f.f, _BTRFS_IOC_GET_DEV_STATS, &arg); err != nil {
		return
	}
	i := 0
	out.WriteErrs = arg.values[i]
	i++
	out.ReadErrs = arg.values[i]
	i++
	out.FlushErrs = arg.values[i]
	i++
	out.CorruptionErrs = arg.values[i]
	i++
	out.GenerationErrs = arg.values[i]
	i++
	if int(arg.nr_items) > i {
		out.Unknown = arg.values[i:arg.nr_items]
	}
	return
}

type FSFeatureFlags struct {
	Compatible   FeatureFlags
	CompatibleRO FeatureFlags
	Incompatible IncompatFeatures
}

func (f *FS) GetFeatures() (out FSFeatureFlags, err error) {
	var arg btrfs_ioctl_feature_flags
	if err = ioctl.Do(f.f, _BTRFS_IOC_GET_FEATURES, &arg); err != nil {
		return
	}
	out = FSFeatureFlags{
		Compatible:   arg.compat_flags,
		CompatibleRO: arg.compat_ro_flags,
		Incompatible: arg.incompat_flags,
	}
	return
}

func (f *FS) GetSupportedFeatures() (out FSFeatureFlags, err error) {
	var arg [3]btrfs_ioctl_feature_flags
	if err = ioctl.Do(f.f, _BTRFS_IOC_GET_SUPPORTED_FEATURES, &arg); err != nil {
		return
	}
	out = FSFeatureFlags{
		Compatible:   arg[0].compat_flags,
		CompatibleRO: arg[0].compat_ro_flags,
		Incompatible: arg[0].incompat_flags,
	}
	//for i, a := range arg {
	//	out[i] = FSFeatureFlags{
	//		Compatible:   a.compat_flags,
	//		CompatibleRO: a.compat_ro_flags,
	//		Incompatible: a.incompat_flags,
	//	}
	//}
	return
}

func (f *FS) GetFlags() (SubvolFlags, error) {
	return iocSubvolGetflags(f.f)
}

func (f *FS) SetFlags(flags SubvolFlags) error {
	return iocSubvolSetflags(f.f, flags)
}

func (f *FS) Sync() (err error) {
	if err = ioctl.Ioctl(f.f, _BTRFS_IOC_START_SYNC, 0); err != nil {
		return
	}
	return ioctl.Ioctl(f.f, _BTRFS_IOC_WAIT_SYNC, 0)
}

func (f *FS) CreateSubVolume(name string) error {
	return CreateSubVolume(filepath.Join(f.f.Name(), name))
}

func (f *FS) DeleteSubVolume(name string) error {
	return DeleteSubVolume(filepath.Join(f.f.Name(), name))
}

func (f *FS) Snapshot(dst string, ro bool) error {
	return SnapshotSubVolume(f.f.Name(), filepath.Join(f.f.Name(), dst), ro)
}

func (f *FS) SnapshotSubVolume(name string, dst string, ro bool) error {
	return SnapshotSubVolume(filepath.Join(f.f.Name(), name),
		filepath.Join(f.f.Name(), dst), ro)
}

func (f *FS) Send(w io.Writer, parent string, subvols ...string) error {
	if parent != "" {
		parent = filepath.Join(f.f.Name(), parent)
	}
	sub := make([]string, 0, len(subvols))
	for _, s := range subvols {
		sub = append(sub, filepath.Join(f.f.Name(), s))
	}
	return Send(w, parent, sub...)
}

func (f *FS) Receive(r io.Reader) error {
	return Receive(r, f.f.Name())
}

func (f *FS) ReceiveTo(r io.Reader, mount string) error {
	return Receive(r, filepath.Join(f.f.Name(), mount))
}

func (f *FS) ListSubvolumes(filter func(SubvolInfo) bool) ([]SubvolInfo, error) {
	m, err := listSubVolumes(f.f, filter)
	if err != nil {
		return nil, err
	}
	out := make([]SubvolInfo, 0, len(m))
	for _, v := range m {
		out = append(out, v)
	}
	return out, nil
}

func (f *FS) SubvolumeByUUID(uuid UUID) (*SubvolInfo, error) {
	id, err := lookupUUIDSubvolItem(f.f, uuid)
	if err != nil {
		return nil, err
	}
	return subvolSearchByRootID(f.f, id, "")
}

func (f *FS) SubvolumeByReceivedUUID(uuid UUID) (*SubvolInfo, error) {
	id, err := lookupUUIDReceivedSubvolItem(f.f, uuid)
	if err != nil {
		return nil, err
	}
	return subvolSearchByRootID(f.f, id, "")
}

func (f *FS) SubvolumeByPath(path string) (*SubvolInfo, error) {
	return subvolSearchByPath(f.f, path)
}

func (f *FS) Usage() (UsageInfo, error) { return spaceUsage(f.f) }

func (f *FS) Balance(flags BalanceFlags) (BalanceProgress, error) {
	args := btrfs_ioctl_balance_args{flags: flags}
	err := iocBalanceV2(f.f, &args)
	return args.stat, err
}

func (f *FS) Resize(size int64) error {
	amount := strconv.FormatInt(size, 10)
	args := &btrfs_ioctl_vol_args{}
	args.SetName(amount)
	if err := iocResize(f.f, args); err != nil {
		return fmt.Errorf("resize failed: %v", err)
	}
	return nil
}

func (f *FS) ResizeToMax() error {
	args := &btrfs_ioctl_vol_args{}
	args.SetName("max")
	if err := iocResize(f.f, args); err != nil {
		return fmt.Errorf("resize failed: %v", err)
	}
	return nil
}
<commit_msg>expose method to get the subvolume id<commit_after>package btrfs

import (
	"fmt"
	"github.com/dennwc/ioctl"
	"io"
	"os"
	"path/filepath"
	"strconv"
	"syscall"
)

const SuperMagic = 0x9123683E

func CloneFile(dst, src *os.File) error {
	return iocClone(dst, src)
}

func Open(path string, ro bool) (*FS, error) {
	if ok, err := IsSubVolume(path); err != nil {
		return nil, err
	} else if !ok {
		return nil, ErrNotBtrfs{Path: path}
	}
	var (
		dir *os.File
		err error
	)
	if ro {
		dir, err = os.OpenFile(path, os.O_RDONLY|syscall.O_NOATIME, 0644)
	} else {
		dir, err = os.Open(path)
	}
	if err != nil {
		return nil, err
	} else if st, err := dir.Stat(); err != nil {
		dir.Close()
		return nil, err
	} else if !st.IsDir() {
		dir.Close()
		return nil, fmt.Errorf("not a directory: %s", path)
	}
	return &FS{f: dir}, nil
}

type FS struct {
	f *os.File
}

func (f *FS) Close() error {
	return f.f.Close()
}

type Info struct {
	MaxID          uint64
	NumDevices     uint64
	FSID           FSID
	NodeSize       uint32
	SectorSize     uint32
	CloneAlignment uint32
}

func (f *FS) SubVolumeID() (uint64, error) {
	id, err := getFileRootID(f.f)
	if err != nil {
		return 0, err
	}
	return uint64(id), nil
}

func (f *FS) Info() (out Info, err error) {
	var arg btrfs_ioctl_fs_info_args
	arg, err = iocFsInfo(f.f)
	if err == nil {
		out = Info{
			MaxID:          arg.max_id,
			NumDevices:     arg.num_devices,
			FSID:           arg.fsid,
			NodeSize:       arg.nodesize,
			SectorSize:     arg.sectorsize,
			CloneAlignment: arg.clone_alignment,
		}
	}
	return
}

type DevStats struct {
	WriteErrs uint64
	ReadErrs  uint64
	FlushErrs uint64
	// Checksum error, bytenr error or contents is illegal: this is an
	// indication that the block was damaged during read or write, or written to
	// wrong location or read from wrong location.
	CorruptionErrs uint64
	// An indication that blocks have not been written.
	GenerationErrs uint64
	Unknown        []uint64
}

func (f *FS) GetDevStats(id uint64) (out DevStats, err error) {
	var arg btrfs_ioctl_get_dev_stats
	arg.devid = id
	//arg.nr_items = _BTRFS_DEV_STAT_VALUES_MAX
	arg.flags = 0
	if err = ioctl.Do(f.f, _BTRFS_IOC_GET_DEV_STATS, &arg); err != nil {
		return
	}
	i := 0
	out.WriteErrs = arg.values[i]
	i++
	out.ReadErrs = arg.values[i]
	i++
	out.FlushErrs = arg.values[i]
	i++
	out.CorruptionErrs = arg.values[i]
	i++
	out.GenerationErrs = arg.values[i]
	i++
	if int(arg.nr_items) > i {
		out.Unknown = arg.values[i:arg.nr_items]
	}
	return
}

type FSFeatureFlags struct {
	Compatible   FeatureFlags
	CompatibleRO FeatureFlags
	Incompatible IncompatFeatures
}

func (f *FS) GetFeatures() (out FSFeatureFlags, err error) {
	var arg btrfs_ioctl_feature_flags
	if err = ioctl.Do(f.f, _BTRFS_IOC_GET_FEATURES, &arg); err != nil {
		return
	}
	out = FSFeatureFlags{
		Compatible:   arg.compat_flags,
		CompatibleRO: arg.compat_ro_flags,
		Incompatible: arg.incompat_flags,
	}
	return
}

func (f *FS) GetSupportedFeatures() (out FSFeatureFlags, err error) {
	var arg [3]btrfs_ioctl_feature_flags
	if err = ioctl.Do(f.f, _BTRFS_IOC_GET_SUPPORTED_FEATURES, &arg); err != nil {
		return
	}
	out = FSFeatureFlags{
		Compatible:   arg[0].compat_flags,
		CompatibleRO: arg[0].compat_ro_flags,
		Incompatible: arg[0].incompat_flags,
	}
	//for i, a := range arg {
	//	out[i] = FSFeatureFlags{
	//		Compatible:   a.compat_flags,
	//		CompatibleRO: a.compat_ro_flags,
	//		Incompatible: a.incompat_flags,
	//	}
	//}
	return
}

func (f *FS) GetFlags() (SubvolFlags, error) {
	return iocSubvolGetflags(f.f)
}

func (f *FS) SetFlags(flags SubvolFlags) error {
	return iocSubvolSetflags(f.f, flags)
}

func (f *FS) Sync() (err error) {
	if err = ioctl.Ioctl(f.f, _BTRFS_IOC_START_SYNC, 0); err != nil {
		return
	}
	return ioctl.Ioctl(f.f, _BTRFS_IOC_WAIT_SYNC, 0)
}

func (f *FS) CreateSubVolume(name string) error {
	return CreateSubVolume(filepath.Join(f.f.Name(), name))
}

func (f *FS) DeleteSubVolume(name string) error {
	return DeleteSubVolume(filepath.Join(f.f.Name(), name))
}

func (f *FS) Snapshot(dst string, ro bool) error {
	return SnapshotSubVolume(f.f.Name(), filepath.Join(f.f.Name(), dst), ro)
}

func (f *FS) SnapshotSubVolume(name string, dst string, ro bool) error {
	return SnapshotSubVolume(filepath.Join(f.f.Name(), name),
		filepath.Join(f.f.Name(), dst), ro)
}

func (f *FS) Send(w io.Writer, parent string, subvols ...string) error {
	if parent != "" {
		parent = filepath.Join(f.f.Name(), parent)
	}
	sub := make([]string, 0, len(subvols))
	for _, s := range subvols {
		sub = append(sub, filepath.Join(f.f.Name(), s))
	}
	return Send(w, parent, sub...)
}

func (f *FS) Receive(r io.Reader) error {
	return Receive(r, f.f.Name())
}

func (f *FS) ReceiveTo(r io.Reader, mount string) error {
	return Receive(r, filepath.Join(f.f.Name(), mount))
}

func (f *FS) ListSubvolumes(filter func(SubvolInfo) bool) ([]SubvolInfo, error) {
	m, err := listSubVolumes(f.f, filter)
	if err != nil {
		return nil, err
	}
	out := make([]SubvolInfo, 0, len(m))
	for _, v := range m {
		out = append(out, v)
	}
	return out, nil
}

func (f *FS) SubvolumeByUUID(uuid UUID) (*SubvolInfo, error) {
	id, err := lookupUUIDSubvolItem(f.f, uuid)
	if err != nil {
		return nil, err
	}
	return subvolSearchByRootID(f.f, id, "")
}

func (f *FS) SubvolumeByReceivedUUID(uuid UUID) (*SubvolInfo, error) {
	id, err := lookupUUIDReceivedSubvolItem(f.f, uuid)
	if err != nil {
		return nil, err
	}
	return subvolSearchByRootID(f.f, id, "")
}

func (f *FS) SubvolumeByPath(path string) (*SubvolInfo, error) {
	return subvolSearchByPath(f.f, path)
}

func (f *FS) Usage() (UsageInfo, error) { return spaceUsage(f.f) }

func (f *FS) Balance(flags BalanceFlags) (BalanceProgress, error) {
	args := btrfs_ioctl_balance_args{flags: flags}
	err := iocBalanceV2(f.f, &args)
	return args.stat, err
}

func (f *FS) Resize(size int64) error {
	amount := strconv.FormatInt(size, 10)
	args := &btrfs_ioctl_vol_args{}
	args.SetName(amount)
	if err := iocResize(f.f, args); err != nil {
		return fmt.Errorf("resize failed: %v", err)
	}
	return nil
}

func (f *FS) ResizeToMax() error {
	args := &btrfs_ioctl_vol_args{}
	args.SetName("max")
	if err := iocResize(f.f, args); err != nil {
		return fmt.Errorf("resize failed: %v", err)
	}
	return nil
}
<|endoftext|>


<commit_before>package awsrules

import (
	"fmt"
	"log"

	"github.com/hashicorp/hcl2/hcl"
	"github.com/wata727/tflint/tflint"
)

// AwsElastiCacheClusterPreviousTypeRule checks whether the resource uses previous generation node type
type AwsElastiCacheClusterPreviousTypeRule struct {
	resourceType      string
	attributeName     string
	previousNodeTypes map[string]bool
}

// NewAwsElastiCacheClusterPreviousTypeRule returns new rule with default attributes
func NewAwsElastiCacheClusterPreviousTypeRule() *AwsElastiCacheClusterPreviousTypeRule {
	return &AwsElastiCacheClusterPreviousTypeRule{
		resourceType:  "aws_elasticache_cluster",
		attributeName: "node_type",
		previousNodeTypes: map[string]bool{
			"cache.m1.small":   true,
			"cache.m1.medium":  true,
			"cache.m1.large":   true,
			"cache.m1.xlarge":  true,
			"cache.m2.xlarge":  true,
			"cache.m2.2xlarge": true,
			"cache.m2.4xlarge": true,
			"cache.c1.xlarge":  true,
			"cache.t1.micro":   true,
		},
	}
}

// Name returns the rule name
func (r *AwsElastiCacheClusterPreviousTypeRule) Name() string {
	return "aws_elasticache_cluster_previous_type"
}

// Enabled returns whether the rule is enabled by default
func (r *AwsElastiCacheClusterPreviousTypeRule) Enabled() bool {
	return true
}

// Severity returns the rule severity
func (r *AwsElastiCacheClusterPreviousTypeRule) Severity() string {
	return tflint.WARNING
}

// Link returns the rule reference link
func (r *AwsElastiCacheClusterPreviousTypeRule) Link() string {
	return tflint.ReferenceLink(r.Name())
}

// Check checks whether the resource's `node_type` is included in the list of previous generation node type
func (r *AwsElastiCacheClusterPreviousTypeRule) Check(runner *tflint.Runner) error {
	log.Printf("[TRACE] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath())

	return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error {
		var nodeType string
		err := runner.EvaluateExpr(attribute.Expr, &nodeType)

		return runner.EnsureNoError(err, func() error {
			if r.previousNodeTypes[nodeType] {
				runner.EmitIssue(
					r,
					fmt.Sprintf("\"%s\" is previous generation node type.", nodeType),
					attribute.Expr.Range(),
				)
			}
			return nil
		})
	})
}
<commit_msg>Update ElastiCache node type list<commit_after>package awsrules

import (
	"fmt"
	"log"

	"github.com/hashicorp/hcl2/hcl"
	"github.com/wata727/tflint/tflint"
)

// AwsElastiCacheClusterPreviousTypeRule checks whether the resource uses previous generation node type
type AwsElastiCacheClusterPreviousTypeRule struct {
	resourceType      string
	attributeName     string
	previousNodeTypes map[string]bool
}

// NewAwsElastiCacheClusterPreviousTypeRule returns new rule with default attributes
func NewAwsElastiCacheClusterPreviousTypeRule() *AwsElastiCacheClusterPreviousTypeRule {
	return &AwsElastiCacheClusterPreviousTypeRule{
		resourceType:  "aws_elasticache_cluster",
		attributeName: "node_type",
		previousNodeTypes: map[string]bool{
			"cache.m1.small":   true,
			"cache.m1.medium":  true,
			"cache.m1.large":   true,
			"cache.m1.xlarge":  true,
			"cache.m2.xlarge":  true,
			"cache.m2.2xlarge": true,
			"cache.m2.4xlarge": true,
			"cache.m3.medium":  true,
			"cache.m3.large":   true,
			"cache.m3.xlarge":  true,
			"cache.m3.2xlarge": true,
			"cache.r3.large":   true,
			"cache.r3.xlarge":  true,
			"cache.r3.2xlarge": true,
			"cache.r3.4xlarge": true,
			"cache.r3.8xlarge": true,
			"cache.c1.xlarge":  true,
			"cache.t1.micro":   true,
		},
	}
}

// Name returns the rule name
func (r *AwsElastiCacheClusterPreviousTypeRule) Name() string {
	return "aws_elasticache_cluster_previous_type"
}

// Enabled returns whether the rule is enabled by default
func (r *AwsElastiCacheClusterPreviousTypeRule) Enabled() bool {
	return true
}

// Severity returns the rule severity
func (r *AwsElastiCacheClusterPreviousTypeRule) Severity() string {
	return tflint.WARNING
}

// Link returns the rule reference link
func (r *AwsElastiCacheClusterPreviousTypeRule) Link() string {
	return tflint.ReferenceLink(r.Name())
}

// Check checks whether the resource's `node_type` is included in the list of previous generation node type
func (r *AwsElastiCacheClusterPreviousTypeRule) Check(runner *tflint.Runner) error {
	log.Printf("[TRACE] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath())

	return runner.WalkResourceAttributes(r.resourceType, r.attributeName, func(attribute *hcl.Attribute) error {
		var nodeType string
		err := runner.EvaluateExpr(attribute.Expr, &nodeType)

		return runner.EnsureNoError(err, func() error {
			if r.previousNodeTypes[nodeType] {
				runner.EmitIssue(
					r,
					fmt.Sprintf("\"%s\" is previous generation node type.", nodeType),
					attribute.Expr.Range(),
				)
			}
			return nil
		})
	})
}
<|endoftext|>


<commit_before>package mocknet

import (
	"context"
	"fmt"
	"math/rand"
	"sync"

	"github.com/libp2p/go-libp2p-core/network"
	"github.com/libp2p/go-libp2p-core/peer"
	"github.com/libp2p/go-libp2p-core/peerstore"

	"github.com/jbenet/goprocess"
	goprocessctx "github.com/jbenet/goprocess/context"

	ma "github.com/multiformats/go-multiaddr"
)

// peernet implements network.Network
type peernet struct {
	mocknet *mocknet // parent

	peer peer.ID
	ps   peerstore.Peerstore

	// conns are actual live connections between peers.
	// many conns could run over each link.
	// **conns are NOT shared between peers**
	connsByPeer map[peer.ID]map[*conn]struct{}
	connsByLink map[*link]map[*conn]struct{}

	// implement network.Network
	streamHandler network.StreamHandler
	connHandler   network.ConnHandler

	notifmu sync.Mutex
	notifs  map[network.Notifiee]struct{}

	proc goprocess.Process
	sync.RWMutex
}

// newPeernet constructs a new peernet
func newPeernet(ctx context.Context, m *mocknet, p peer.ID, ps peerstore.Peerstore) (*peernet, error) {

	n := &peernet{
		mocknet: m,
		peer:    p,
		ps:      ps,

		connsByPeer: map[peer.ID]map[*conn]struct{}{},
		connsByLink: map[*link]map[*conn]struct{}{},

		notifs: make(map[network.Notifiee]struct{}),
	}

	n.proc = goprocessctx.WithContextAndTeardown(ctx, n.teardown)
	return n, nil
}

func (pn *peernet) teardown() error {

	// close the connections
	for _, c := range pn.allConns() {
		c.Close()
	}
	return nil
}

// allConns returns all the connections between this peer and others
func (pn *peernet) allConns() []*conn {
	pn.RLock()
	var cs []*conn
	for _, csl := range pn.connsByPeer {
		for c := range csl {
			cs = append(cs, c)
		}
	}
	pn.RUnlock()
	return cs
}

// Close calls the ContextCloser func
func (pn *peernet) Close() error {
	return pn.proc.Close()
}

func (pn *peernet) Peerstore() peerstore.Peerstore {
	return pn.ps
}

func (pn *peernet) String() string {
	return fmt.Sprintf("<mock.peernet %s - %d conns>", pn.peer, len(pn.allConns()))
}

// handleNewStream is an internal function to trigger the client's handler
func (pn *peernet) handleNewStream(s network.Stream) {
	pn.RLock()
	handler := pn.streamHandler
	pn.RUnlock()
	if handler != nil {
		go handler(s)
	}
}

// handleNewConn is an internal function to trigger the client's handler
func (pn *peernet) handleNewConn(c network.Conn) {
	pn.RLock()
	handler := pn.connHandler
	pn.RUnlock()
	if handler != nil {
		go handler(c)
	}
}

// DialPeer attempts to establish a connection to a given peer.
// Respects the context.
func (pn *peernet) DialPeer(ctx context.Context, p peer.ID) (network.Conn, error) {
	return pn.connect(p)
}

func (pn *peernet) connect(p peer.ID) (*conn, error) {
	if p == pn.peer {
		return nil, fmt.Errorf("attempted to dial self %s", p)
	}

	// first, check if we already have live connections
	pn.RLock()
	cs, found := pn.connsByPeer[p]
	if found && len(cs) > 0 {
		var chosen *conn
		for c := range cs { // because cs is a map
			chosen = c // select first
			break
		}
		pn.RUnlock()
		return chosen, nil
	}
	pn.RUnlock()

	log.Debugf("%s (newly) dialing %s", pn.peer, p)

	// ok, must create a new connection. we need a link
	links := pn.mocknet.LinksBetweenPeers(pn.peer, p)
	if len(links) < 1 {
		return nil, fmt.Errorf("%s cannot connect to %s", pn.peer, p)
	}

	// if many links found, how do we select? for now, randomly...
	// this would be an interesting place to test logic that can measure
	// links (network interfaces) and select properly
	l := links[rand.Intn(len(links))]

	log.Debugf("%s dialing %s openingConn", pn.peer, p)
	// create a new connection with link
	c := pn.openConn(p, l.(*link))
	return c, nil
}

func (pn *peernet) openConn(r peer.ID, l *link) *conn {
	lc, rc := l.newConnPair(pn)
	log.Debugf("%s opening connection to %s", pn.LocalPeer(), lc.RemotePeer())
	pn.addConn(lc)
	pn.notifyAll(func(n network.Notifiee) {
		n.Connected(pn, lc)
	})
	rc.net.remoteOpenedConn(rc)
	return lc
}

func (pn *peernet) remoteOpenedConn(c *conn) {
	log.Debugf("%s accepting connection from %s", pn.LocalPeer(), c.RemotePeer())
	pn.addConn(c)
	pn.handleNewConn(c)
	pn.notifyAll(func(n network.Notifiee) {
		n.Connected(pn, c)
	})
}

// addConn constructs and adds a connection
// to given remote peer over given link
func (pn *peernet) addConn(c *conn) {
	pn.Lock()
	defer pn.Unlock()

	cs, found := pn.connsByPeer[c.RemotePeer()]
	if !found {
		cs = map[*conn]struct{}{}
		pn.connsByPeer[c.RemotePeer()] = cs
	}
	pn.connsByPeer[c.RemotePeer()][c] = struct{}{}

	cs, found = pn.connsByLink[c.link]
	if !found {
		cs = map[*conn]struct{}{}
		pn.connsByLink[c.link] = cs
	}
	pn.connsByLink[c.link][c] = struct{}{}
}

// removeConn removes a given conn
func (pn *peernet) removeConn(c *conn) {
	pn.Lock()
	defer pn.Unlock()

	cs, found := pn.connsByLink[c.link]
	if !found || len(cs) < 1 {
		panic(fmt.Sprintf("attempting to remove a conn that doesnt exist %p", c.link))
	}
	delete(cs, c)

	cs, found = pn.connsByPeer[c.remote]
	if !found {
		panic(fmt.Sprintf("attempting to remove a conn that doesnt exist %v", c.remote))
	}
	delete(cs, c)
}

// Process returns the network's Process
func (pn *peernet) Process() goprocess.Process {
	return pn.proc
}

// LocalPeer the network's LocalPeer
func (pn *peernet) LocalPeer() peer.ID {
	return pn.peer
}

// Peers returns the connected peers
func (pn *peernet) Peers() []peer.ID {
	pn.RLock()
	defer pn.RUnlock()

	peers := make([]peer.ID, 0, len(pn.connsByPeer))
	for _, cs := range pn.connsByPeer {
		for c := range cs {
			peers = append(peers, c.remote)
			break
		}
	}
	return peers
}

// Conns returns all the connections of this peer
func (pn *peernet) Conns() []network.Conn {
	pn.RLock()
	defer pn.RUnlock()

	out := make([]network.Conn, 0, len(pn.connsByPeer))
	for _, cs := range pn.connsByPeer {
		for c := range cs {
			out = append(out, c)
		}
	}
	return out
}

func (pn *peernet) ConnsToPeer(p peer.ID) []network.Conn {
	pn.RLock()
	defer pn.RUnlock()

	cs, found := pn.connsByPeer[p]
	if !found || len(cs) == 0 {
		return nil
	}

	var cs2 []network.Conn
	for c := range cs {
		cs2 = append(cs2, c)
	}
	return cs2
}

// ClosePeer connections to peer
func (pn *peernet) ClosePeer(p peer.ID) error {
	pn.RLock()
	cs, found := pn.connsByPeer[p]
	if !found {
		pn.RUnlock()
		return nil
	}

	var conns []*conn
	for c := range cs {
		conns = append(conns, c)
	}
	pn.RUnlock()
	for _, c := range conns {
		c.Close()
	}
	return nil
}

// BandwidthTotals returns the total amount of bandwidth transferred
func (pn *peernet) BandwidthTotals() (in uint64, out uint64) {
	// need to implement this. probably best to do it in swarm this time.
	// need a "metrics" object
	return 0, 0
}

// Listen tells the network to start listening on given multiaddrs.
func (pn *peernet) Listen(addrs ...ma.Multiaddr) error {
	pn.Peerstore().AddAddrs(pn.LocalPeer(), addrs, peerstore.PermanentAddrTTL)
	return nil
}

// ListenAddresses returns a list of addresses at which this network listens.
func (pn *peernet) ListenAddresses() []ma.Multiaddr {
	return pn.Peerstore().Addrs(pn.LocalPeer())
}

// InterfaceListenAddresses returns a list of addresses at which this network
// listens. It expands "any interface" addresses (/ip4/0.0.0.0, /ip6/::) to
// use the known local interfaces.
func (pn *peernet) InterfaceListenAddresses() ([]ma.Multiaddr, error) {
	return pn.ListenAddresses(), nil
}

// Connectedness returns a state signaling connection capabilities
// For now only returns Connecter || NotConnected. Expand into more later.
func (pn *peernet) Connectedness(p peer.ID) network.Connectedness {
	pn.Lock()
	defer pn.Unlock()

	cs, found := pn.connsByPeer[p]
	if found && len(cs) > 0 {
		return network.Connected
	}
	return network.NotConnected
}

// NewStream returns a new stream to given peer p.
// If there is no connection to p, attempts to create one.
func (pn *peernet) NewStream(ctx context.Context, p peer.ID) (network.Stream, error) {
	c, err := pn.DialPeer(ctx, p)
	if err != nil {
		return nil, err
	}
	return c.NewStream()
}

// SetStreamHandler sets the new stream handler on the Network.
// This operation is threadsafe.
func (pn *peernet) SetStreamHandler(h network.StreamHandler) {
	pn.Lock()
	pn.streamHandler = h
	pn.Unlock()
}

// SetConnHandler sets the new conn handler on the Network.
// This operation is threadsafe.
func (pn *peernet) SetConnHandler(h network.ConnHandler) {
	pn.Lock()
	pn.connHandler = h
	pn.Unlock()
}

// Notify signs up Notifiee to receive signals when events happen
func (pn *peernet) Notify(f network.Notifiee) {
	pn.notifmu.Lock()
	pn.notifs[f] = struct{}{}
	pn.notifmu.Unlock()
}

// StopNotify unregisters Notifiee from receiving signals
func (pn *peernet) StopNotify(f network.Notifiee) {
	pn.notifmu.Lock()
	delete(pn.notifs, f)
	pn.notifmu.Unlock()
}

// notifyAll runs the notification function on all Notifiees
func (pn *peernet) notifyAll(notification func(f network.Notifiee)) {
	pn.notifmu.Lock()
	var wg sync.WaitGroup
	for n := range pn.notifs {
		// make sure we dont block
		// and they dont block each other.
		wg.Add(1)
		go func(n network.Notifiee) {
			defer wg.Done()
			notification(n)
		}(n)
	}
	wg.Wait()
	pn.notifmu.Unlock()
}
<commit_msg>Removed ineffectual assignments<commit_after>package mocknet

import (
	"context"
	"fmt"
	"math/rand"
	"sync"

	"github.com/libp2p/go-libp2p-core/network"
	"github.com/libp2p/go-libp2p-core/peer"
	"github.com/libp2p/go-libp2p-core/peerstore"

	"github.com/jbenet/goprocess"
	goprocessctx "github.com/jbenet/goprocess/context"

	ma "github.com/multiformats/go-multiaddr"
)

// peernet implements network.Network
type peernet struct {
	mocknet *mocknet // parent

	peer peer.ID
	ps   peerstore.Peerstore

	// conns are actual live connections between peers.
	// many conns could run over each link.
	// **conns are NOT shared between peers**
	connsByPeer map[peer.ID]map[*conn]struct{}
	connsByLink map[*link]map[*conn]struct{}

	// implement network.Network
	streamHandler network.StreamHandler
	connHandler   network.ConnHandler

	notifmu sync.Mutex
	notifs  map[network.Notifiee]struct{}

	proc goprocess.Process
	sync.RWMutex
}

// newPeernet constructs a new peernet
func newPeernet(ctx context.Context, m *mocknet, p peer.ID, ps peerstore.Peerstore) (*peernet, error) {

	n := &peernet{
		mocknet: m,
		peer:    p,
		ps:      ps,

		connsByPeer: map[peer.ID]map[*conn]struct{}{},
		connsByLink: map[*link]map[*conn]struct{}{},

		notifs: make(map[network.Notifiee]struct{}),
	}

	n.proc = goprocessctx.WithContextAndTeardown(ctx, n.teardown)
	return n, nil
}

func (pn *peernet) teardown() error {

	// close the connections
	for _, c := range pn.allConns() {
		c.Close()
	}
	return nil
}

// allConns returns all the connections between this peer and others
func (pn *peernet) allConns() []*conn {
	pn.RLock()
	var cs []*conn
	for _, csl := range pn.connsByPeer {
		for c := range csl {
			cs = append(cs, c)
		}
	}
	pn.RUnlock()
	return cs
}

// Close calls the ContextCloser func
func (pn *peernet) Close() error {
	return pn.proc.Close()
}

func (pn *peernet) Peerstore() peerstore.Peerstore {
	return pn.ps
}

func (pn *peernet) String() string {
	return fmt.Sprintf("<mock.peernet %s - %d conns>", pn.peer, len(pn.allConns()))
}

// handleNewStream is an internal function to trigger the client's handler
func (pn *peernet) handleNewStream(s network.Stream) {
	pn.RLock()
	handler := pn.streamHandler
	pn.RUnlock()
	if handler != nil {
		go handler(s)
	}
}

// handleNewConn is an internal function to trigger the client's handler
func (pn *peernet) handleNewConn(c network.Conn) {
	pn.RLock()
	handler := pn.connHandler
	pn.RUnlock()
	if handler != nil {
		go handler(c)
	}
}

// DialPeer attempts to establish a connection to a given peer.
// Respects the context.
func (pn *peernet) DialPeer(ctx context.Context, p peer.ID) (network.Conn, error) {
	return pn.connect(p)
}

func (pn *peernet) connect(p peer.ID) (*conn, error) {
	if p == pn.peer {
		return nil, fmt.Errorf("attempted to dial self %s", p)
	}

	// first, check if we already have live connections
	pn.RLock()
	cs, found := pn.connsByPeer[p]
	if found && len(cs) > 0 {
		var chosen *conn
		for c := range cs { // because cs is a map
			chosen = c // select first
			break
		}
		pn.RUnlock()
		return chosen, nil
	}
	pn.RUnlock()

	log.Debugf("%s (newly) dialing %s", pn.peer, p)

	// ok, must create a new connection. we need a link
	links := pn.mocknet.LinksBetweenPeers(pn.peer, p)
	if len(links) < 1 {
		return nil, fmt.Errorf("%s cannot connect to %s", pn.peer, p)
	}

	// if many links found, how do we select? for now, randomly...
	// this would be an interesting place to test logic that can measure
	// links (network interfaces) and select properly
	l := links[rand.Intn(len(links))]

	log.Debugf("%s dialing %s openingConn", pn.peer, p)
	// create a new connection with link
	c := pn.openConn(p, l.(*link))
	return c, nil
}

func (pn *peernet) openConn(r peer.ID, l *link) *conn {
	lc, rc := l.newConnPair(pn)
	log.Debugf("%s opening connection to %s", pn.LocalPeer(), lc.RemotePeer())
	pn.addConn(lc)
	pn.notifyAll(func(n network.Notifiee) {
		n.Connected(pn, lc)
	})
	rc.net.remoteOpenedConn(rc)
	return lc
}

func (pn *peernet) remoteOpenedConn(c *conn) {
	log.Debugf("%s accepting connection from %s", pn.LocalPeer(), c.RemotePeer())
	pn.addConn(c)
	pn.handleNewConn(c)
	pn.notifyAll(func(n network.Notifiee) {
		n.Connected(pn, c)
	})
}

// addConn constructs and adds a connection
// to given remote peer over given link
func (pn *peernet) addConn(c *conn) {
	pn.Lock()
	defer pn.Unlock()

	_, found := pn.connsByPeer[c.RemotePeer()]
	if !found {
		pn.connsByPeer[c.RemotePeer()] = map[*conn]struct{}{}
	}
	pn.connsByPeer[c.RemotePeer()][c] = struct{}{}

	_, found = pn.connsByLink[c.link]
	if !found {
		pn.connsByLink[c.link] = map[*conn]struct{}{}
	}
	pn.connsByLink[c.link][c] = struct{}{}
}

// removeConn removes a given conn
func (pn *peernet) removeConn(c *conn) {
	pn.Lock()
	defer pn.Unlock()

	cs, found := pn.connsByLink[c.link]
	if !found || len(cs) < 1 {
		panic(fmt.Sprintf("attempting to remove a conn that doesnt exist %p", c.link))
	}
	delete(cs, c)

	cs, found = pn.connsByPeer[c.remote]
	if !found {
		panic(fmt.Sprintf("attempting to remove a conn that doesnt exist %v", c.remote))
	}
	delete(cs, c)
}

// Process returns the network's Process
func (pn *peernet) Process() goprocess.Process {
	return pn.proc
}

// LocalPeer the network's LocalPeer
func (pn *peernet) LocalPeer() peer.ID {
	return pn.peer
}

// Peers returns the connected peers
func (pn *peernet) Peers() []peer.ID {
	pn.RLock()
	defer pn.RUnlock()

	peers := make([]peer.ID, 0, len(pn.connsByPeer))
	for _, cs := range pn.connsByPeer {
		for c := range cs {
			peers = append(peers, c.remote)
			break
		}
	}
	return peers
}

// Conns returns all the connections of this peer
func (pn *peernet) Conns() []network.Conn {
	pn.RLock()
	defer pn.RUnlock()

	out := make([]network.Conn, 0, len(pn.connsByPeer))
	for _, cs := range pn.connsByPeer {
		for c := range cs {
			out = append(out, c)
		}
	}
	return out
}

func (pn *peernet) ConnsToPeer(p peer.ID) []network.Conn {
	pn.RLock()
	defer pn.RUnlock()

	cs, found := pn.connsByPeer[p]
	if !found || len(cs) == 0 {
		return nil
	}

	var cs2 []network.Conn
	for c := range cs {
		cs2 = append(cs2, c)
	}
	return cs2
}

// ClosePeer connections to peer
func (pn *peernet) ClosePeer(p peer.ID) error {
	pn.RLock()
	cs, found := pn.connsByPeer[p]
	if !found {
		pn.RUnlock()
		return nil
	}

	var conns []*conn
	for c := range cs {
		conns = append(conns, c)
	}
	pn.RUnlock()
	for _, c := range conns {
		c.Close()
	}
	return nil
}

// BandwidthTotals returns the total amount of bandwidth transferred
func (pn *peernet) BandwidthTotals() (in uint64, out uint64) {
	// need to implement this. probably best to do it in swarm this time.
	// need a "metrics" object
	return 0, 0
}

// Listen tells the network to start listening on given multiaddrs.
func (pn *peernet) Listen(addrs ...ma.Multiaddr) error {
	pn.Peerstore().AddAddrs(pn.LocalPeer(), addrs, peerstore.PermanentAddrTTL)
	return nil
}

// ListenAddresses returns a list of addresses at which this network listens.
func (pn *peernet) ListenAddresses() []ma.Multiaddr {
	return pn.Peerstore().Addrs(pn.LocalPeer())
}

// InterfaceListenAddresses returns a list of addresses at which this network
// listens. It expands "any interface" addresses (/ip4/0.0.0.0, /ip6/::) to
// use the known local interfaces.
func (pn *peernet) InterfaceListenAddresses() ([]ma.Multiaddr, error) {
	return pn.ListenAddresses(), nil
}

// Connectedness returns a state signaling connection capabilities
// For now only returns Connecter || NotConnected. Expand into more later.
func (pn *peernet) Connectedness(p peer.ID) network.Connectedness {
	pn.Lock()
	defer pn.Unlock()

	cs, found := pn.connsByPeer[p]
	if found && len(cs) > 0 {
		return network.Connected
	}
	return network.NotConnected
}

// NewStream returns a new stream to given peer p.
// If there is no connection to p, attempts to create one.
func (pn *peernet) NewStream(ctx context.Context, p peer.ID) (network.Stream, error) {
	c, err := pn.DialPeer(ctx, p)
	if err != nil {
		return nil, err
	}
	return c.NewStream()
}

// SetStreamHandler sets the new stream handler on the Network.
// This operation is threadsafe.
func (pn *peernet) SetStreamHandler(h network.StreamHandler) {
	pn.Lock()
	pn.streamHandler = h
	pn.Unlock()
}

// SetConnHandler sets the new conn handler on the Network.
// This operation is threadsafe.
func (pn *peernet) SetConnHandler(h network.ConnHandler) {
	pn.Lock()
	pn.connHandler = h
	pn.Unlock()
}

// Notify signs up Notifiee to receive signals when events happen
func (pn *peernet) Notify(f network.Notifiee) {
	pn.notifmu.Lock()
	pn.notifs[f] = struct{}{}
	pn.notifmu.Unlock()
}

// StopNotify unregisters Notifiee from receiving signals
func (pn *peernet) StopNotify(f network.Notifiee) {
	pn.notifmu.Lock()
	delete(pn.notifs, f)
	pn.notifmu.Unlock()
}

// notifyAll runs the notification function on all Notifiees
func (pn *peernet) notifyAll(notification func(f network.Notifiee)) {
	pn.notifmu.Lock()
	var wg sync.WaitGroup
	for n := range pn.notifs {
		// make sure we dont block
		// and they dont block each other.
		wg.Add(1)
		go func(n network.Notifiee) {
			defer wg.Done()
			notification(n)
		}(n)
	}
	wg.Wait()
	pn.notifmu.Unlock()
}
<|endoftext|>


<commit_before><commit_msg>loglevel: lock protecting log-parameters.<commit_after><|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"github.com/laher/uggo"
	"io"
	"math"
	"mime"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)
func main() {
	Wget(os.Args)
}

//TODO
// ftp
// no-scheme
// clobber behaviour
// progress
// limit-rate
// timeouts - connect,read,dns?
// wait,waitretry
// proxies/?
// quota/?
// user/password/ask-password
// certificates/no-check-certificate ...
// exit statuses
// recursive downloads
// timestamping
// wgetrc
type WgetOptions struct {
	IsContinue *bool
	Filename *string
	Timeout *int //TODO timeout
	Retries *int //TODO retries
}

const (
	FILEMODE os.FileMode = 0660
)

func Wget(call []string) error {

	options := WgetOptions{}
	flagSet := flag.NewFlagSet("wget", flag.ContinueOnError)
	options.IsContinue = flagSet.Bool("c", false, "continue")
	options.Filename = flagSet.String("o", "", "output filename")
	helpFlag := flagSet.Bool("help", false, "Show this help")

	err := flagSet.Parse(uggo.Gnuify(call[1:]))
	if err != nil {
		return err
	}
	if *helpFlag {
		println("wget [options] URL")
		flagSet.PrintDefaults()
		return nil
	}
	args := flagSet.Args()
	if len(args) < 1 {
		flagSet.PrintDefaults()
		return errors.New("Not enough args")
	}
	if len(args) > 0 {
		links := args
		return wget(links, options)
	} else {
		if uggo.IsPipingStdin() {
			//check STDIN
			return wget([]string{}, options)
		} else {
			//NOT piping.
			return errors.New("Not enough args")
		}
	}
}

func wget(links []string, options WgetOptions) error {
	for _, link := range links {
		err := wgetOne(link, options)
		if err != nil {
			return err
		}
	}
	return nil
}

func tidyFilename(filename string) string {
	//invalid filenames ...
	if filename == "" || filename == "/" ||filename == "\\" || filename == "." {
		filename = "index"
	}
	return filename
}

func wgetOne(link string, options WgetOptions) error {
	if !strings.Contains(link, ":") {
		link = "http://" + link
	}
	startTime := time.Now()
	request, err := http.NewRequest("GET", link, nil)
	//resp, err := http.Get(link)
	if err != nil {
		return err
	}

	filename := ""
	if *options.Filename != "" {
		filename = *options.Filename
	}
	client := &http.Client{}
	//continue from where we left off ...
	if *options.IsContinue {
		if filename == "" {
			filename = filepath.Base(request.URL.Path)
			filename = tidyFilename(filename)
			if !strings.Contains(filename, ".") {
				filename = filename + ".html"
			}
		}
		fi, err := os.Stat(filename)
		if err != nil {
			return err
		}
		from := fi.Size()
		headRequest, err := http.NewRequest("HEAD", link, nil)
		if err != nil {
			return err
		}
		headResp, err := client.Do(headRequest)
		if err != nil {
			return err
		}
		cl := headResp.Header.Get("Content-Length")
		if cl != "" {
		rangeHeader := fmt.Sprintf("bytes %d-%s", from, cl)
		fmt.Printf("Adding range header: %s\n", rangeHeader)
		request.Header.Add("Range", rangeHeader)
		} else {
			fmt.Println("Could not find file length using HEAD request")
		}
	}
	resp, err := client.Do(request)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	fmt.Printf("Http response: %s\n", resp.Status)

	lenS := resp.Header.Get("Content-Length")
	len := int64(-1)
	if lenS != "" {
		len, err = strconv.ParseInt(lenS, 10, 32)
		if err != nil {
			return err
		}
	}
	typ := resp.Header.Get("Content-Type")
	fmt.Printf("Length: %v [%s]\n", len, typ)

	defer resp.Body.Close()
	if filename == "" {
		filename, err = getFilename(resp)
		if err != nil {
			return err
		}
	}
	fmt.Printf("Saving to: '%v'\n\n", filename)
	out, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer out.Close()

	buf := make([]byte, 4068)
	tot := int64(0)
	i := 0

	for {
        // read a chunk
        n, err := resp.Body.Read(buf)
        if err != nil && err != io.EOF {
			return err
		}
        if n == 0 { break }
		tot += int64(n)

        // write a chunk
        if _, err := out.Write(buf[:n]); err != nil {
            return err
        }
		i+=1
		if len > -1 {
			if len < 1 {
				fmt.Printf("\r     [ <=>                                  ] %d\t-.--KB/s eta ?s             ", tot)
			} else {
				//show percentage
				perc := (100 * tot) / len
				prog := progress(perc)
				nowTime := time.Now()
				totTime := nowTime.Sub(startTime)
				spd := float64(tot / 1000) / totTime.Seconds()
				remKb := float64(len - tot) / float64(1000)
				eta :=  remKb / spd
				fmt.Printf("\r%3d%% [%s] %d\t%0.2fKB/s eta %0.1fs             ", perc, prog, tot, spd, eta)
			}
		} else {
			//show dots
			if math.Mod(float64(i), 20) == 0 {
				fmt.Print(".")
			}
		}
    }
	perc := (100 * tot) / len
	prog := progress(perc)
	nowTime := time.Now()
	totTime := nowTime.Sub(startTime)
	spd := float64(tot / 1000) / totTime.Seconds()
	if len < 1 {
		fmt.Printf("\r     [ <=>                                  ] %d\t-.--KB/s in %0.1fs             ", tot, totTime.Seconds())
		fmt.Printf("\n (%0.2fKB/s) - '%v' saved [%v]\n", spd, filename, tot)
	} else {
		fmt.Printf("\r%3d%% [%s] %d\t%0.2fKB/s in %0.1fs             ", perc, prog, tot, spd, totTime.Seconds())
		fmt.Printf("\n '%v' saved [%v/%v]\n", filename, tot, len)
	}
	if err != nil {
		return err
	}
	err = out.Close()
	return err
}

func progress(perc int64) string {
	equalses := perc * 38 / 100
	if equalses < 0 {
		equalses = 0
	}
	spaces := 38 - equalses
	if spaces < 0 {
		spaces = 0
	}
	prog := strings.Repeat("=", int(equalses)) + ">" + strings.Repeat(" ", int(spaces))
	return prog
}

func getFilename(resp *http.Response) (string, error) {
	filename := filepath.Base(resp.Request.URL.Path)
	filename = tidyFilename(filename)

	if !strings.Contains(filename, ".") {
		ct := resp.Header.Get("Content-Type")
		//println(ct)
		ext := "htm"
		mediatype, _, err := mime.ParseMediaType(ct)
		if err != nil {
			fmt.Printf("mime error: %v\n", err)
		} else {
			fmt.Printf("mime type: %v (from Content-Type %v)\n", mediatype, ct)
			slash := strings.Index(mediatype, "/")
			if slash != -1 {
				_, sub := mediatype[:slash], mediatype[slash+1:]
				if sub != "" {
					ext = sub
				}
			}
		}
		filename = filename + "." + ext
	}
	_, err := os.Stat(filename)
	if err != nil {
		if os.IsNotExist(err) {
			return filename, nil
		} else {
			return "", err
		}
	} else {
		num := 1
		//just stop after 100
		for num < 100 {
			filenameNew := filename + "." + strconv.Itoa(num)
			_, err := os.Stat(filenameNew)
			if err != nil {
				if os.IsNotExist(err) {
					return filenameNew, nil
				} else {
					return "", err
				}
			}
			num += 1
		}
		return filename, errors.New("Stopping after trying 100 filename variants")
	}
}
<commit_msg>fixed error reporting<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"github.com/laher/uggo"
	"io"
	"math"
	"mime"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)
func main() {
	err := Wget(os.Args)
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		os.Exit(1)
	}
}

//TODO
// ftp
// no-scheme
// clobber behaviour
// progress
// limit-rate
// timeouts - connect,read,dns?
// wait,waitretry
// proxies/?
// quota/?
// user/password/ask-password
// certificates/no-check-certificate ...
// exit statuses
// recursive downloads
// timestamping
// wgetrc
type WgetOptions struct {
	IsContinue *bool
	Filename *string
	Timeout *int //TODO timeout
	Retries *int //TODO retries
}

const (
	FILEMODE os.FileMode = 0660
)

func Wget(call []string) error {

	options := WgetOptions{}
	flagSet := flag.NewFlagSet("wget", flag.ContinueOnError)
	options.IsContinue = flagSet.Bool("c", false, "continue")
	options.Filename = flagSet.String("o", "", "output filename")
	helpFlag := flagSet.Bool("help", false, "Show this help")

	err := flagSet.Parse(uggo.Gnuify(call[1:]))
	if err != nil {
		return err
	}
	if *helpFlag {
		println("wget [options] URL")
		flagSet.PrintDefaults()
		return nil
	}
	args := flagSet.Args()
	if len(args) < 1 {
		flagSet.PrintDefaults()
		return errors.New("Not enough args")
	}
	if len(args) > 0 {
		links := args
		return wget(links, options)
	} else {
		if uggo.IsPipingStdin() {
			//check STDIN
			return wget([]string{}, options)
		} else {
			//NOT piping.
			return errors.New("Not enough args")
		}
	}
}

func wget(links []string, options WgetOptions) error {
	for _, link := range links {
		err := wgetOne(link, options)
		if err != nil {
			return err
		}
	}
	return nil
}

func tidyFilename(filename string) string {
	//invalid filenames ...
	if filename == "" || filename == "/" ||filename == "\\" || filename == "." {
		filename = "index"
	}
	return filename
}

func wgetOne(link string, options WgetOptions) error {
	if !strings.Contains(link, ":") {
		link = "http://" + link
	}
	startTime := time.Now()
	request, err := http.NewRequest("GET", link, nil)
	//resp, err := http.Get(link)
	if err != nil {
		return err
	}

	filename := ""
	if *options.Filename != "" {
		filename = *options.Filename
	}
	client := &http.Client{}
	//continue from where we left off ...
	if *options.IsContinue {
		if filename == "" {
			filename = filepath.Base(request.URL.Path)
			filename = tidyFilename(filename)
			if !strings.Contains(filename, ".") {
				filename = filename + ".html"
			}
		}
		fi, err := os.Stat(filename)
		if err != nil {
			return err
		}
		from := fi.Size()
		headRequest, err := http.NewRequest("HEAD", link, nil)
		if err != nil {
			return err
		}
		headResp, err := client.Do(headRequest)
		if err != nil {
			return err
		}
		cl := headResp.Header.Get("Content-Length")
		if cl != "" {
		rangeHeader := fmt.Sprintf("bytes %d-%s", from, cl)
		fmt.Printf("Adding range header: %s\n", rangeHeader)
		request.Header.Add("Range", rangeHeader)
		} else {
			fmt.Println("Could not find file length using HEAD request")
		}
	}
	resp, err := client.Do(request)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	fmt.Printf("Http response: %s\n", resp.Status)

	lenS := resp.Header.Get("Content-Length")
	len := int64(-1)
	if lenS != "" {
		len, err = strconv.ParseInt(lenS, 10, 32)
		if err != nil {
			return err
		}
	}
	typ := resp.Header.Get("Content-Type")
	fmt.Printf("Length: %v [%s]\n", len, typ)

	if filename == "" {
		filename, err = getFilename(resp)
		if err != nil {
			return err
		}
	}
	fmt.Printf("Saving to: '%v'\n\n", filename)
	out, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer out.Close()

	buf := make([]byte, 4068)
	tot := int64(0)
	i := 0

	for {
        // read a chunk
        n, err := resp.Body.Read(buf)
        if err != nil && err != io.EOF {
			return err
		}
        if n == 0 { break }
		tot += int64(n)

        // write a chunk
        if _, err := out.Write(buf[:n]); err != nil {
            return err
        }
		i+=1
		if len > -1 {
			if len < 1 {
				fmt.Printf("\r     [ <=>                                  ] %d\t-.--KB/s eta ?s             ", tot)
			} else {
				//show percentage
				perc := (100 * tot) / len
				prog := progress(perc)
				nowTime := time.Now()
				totTime := nowTime.Sub(startTime)
				spd := float64(tot / 1000) / totTime.Seconds()
				remKb := float64(len - tot) / float64(1000)
				eta :=  remKb / spd
				fmt.Printf("\r%3d%% [%s] %d\t%0.2fKB/s eta %0.1fs             ", perc, prog, tot, spd, eta)
			}
		} else {
			//show dots
			if math.Mod(float64(i), 20) == 0 {
				fmt.Print(".")
			}
		}
    }
	perc := (100 * tot) / len
	prog := progress(perc)
	nowTime := time.Now()
	totTime := nowTime.Sub(startTime)
	spd := float64(tot / 1000) / totTime.Seconds()
	if len < 1 {
		fmt.Printf("\r     [ <=>                                  ] %d\t-.--KB/s in %0.1fs             ", tot, totTime.Seconds())
		fmt.Printf("\n (%0.2fKB/s) - '%v' saved [%v]\n", spd, filename, tot)
	} else {
		fmt.Printf("\r%3d%% [%s] %d\t%0.2fKB/s in %0.1fs             ", perc, prog, tot, spd, totTime.Seconds())
		fmt.Printf("\n '%v' saved [%v/%v]\n", filename, tot, len)
	}
	if err != nil {
		return err
	}
	err = out.Close()
	return err
}

func progress(perc int64) string {
	equalses := perc * 38 / 100
	if equalses < 0 {
		equalses = 0
	}
	spaces := 38 - equalses
	if spaces < 0 {
		spaces = 0
	}
	prog := strings.Repeat("=", int(equalses)) + ">" + strings.Repeat(" ", int(spaces))
	return prog
}

func getFilename(resp *http.Response) (string, error) {
	filename := filepath.Base(resp.Request.URL.Path)
	filename = tidyFilename(filename)

	if !strings.Contains(filename, ".") {
		ct := resp.Header.Get("Content-Type")
		//println(ct)
		ext := "htm"
		mediatype, _, err := mime.ParseMediaType(ct)
		if err != nil {
			fmt.Printf("mime error: %v\n", err)
		} else {
			fmt.Printf("mime type: %v (from Content-Type %v)\n", mediatype, ct)
			slash := strings.Index(mediatype, "/")
			if slash != -1 {
				_, sub := mediatype[:slash], mediatype[slash+1:]
				if sub != "" {
					ext = sub
				}
			}
		}
		filename = filename + "." + ext
	}
	_, err := os.Stat(filename)
	if err != nil {
		if os.IsNotExist(err) {
			return filename, nil
		} else {
			return "", err
		}
	} else {
		num := 1
		//just stop after 100
		for num < 100 {
			filenameNew := filename + "." + strconv.Itoa(num)
			_, err := os.Stat(filenameNew)
			if err != nil {
				if os.IsNotExist(err) {
					return filenameNew, nil
				} else {
					return "", err
				}
			}
			num += 1
		}
		return filename, errors.New("Stopping after trying 100 filename variants")
	}
}
<|endoftext|>


<commit_before>package QesyGo

import (
	"github.com/garyburd/redigo/redis"
	"time"
)

type CacheRedis struct {
	Pool     *redis.Pool // redis connection pool
	Conninfo string
	Key      string
}

func (cr *CacheRedis) newPool() {
	cr.Pool = &redis.Pool{
		MaxIdle:     30,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", cr.Conninfo)
			if err != nil {
				return nil, err
			}
			return c, err
		},
	}
}

//var pool = newPool()
func (cr *CacheRedis) Connect() error {
	cr.newPool()
	c := cr.Pool.Get()
	defer c.Close()
	return c.Err()
}

func (cr *CacheRedis) do(commandName string, args ...interface{}) (reply interface{}, err error) {
	c := cr.Pool.Get()
	defer c.Close()
	return c.Do(commandName, args...)
}

func (cr *CacheRedis) Get(key string) (string, error) {
	str, err := redis.String(cr.do("GET", key))
	return str, err
}

func (cr *CacheRedis) Set(key string, value string) error {
	_, err := cr.do("SET", key, value)
	return err
}

func (cr *CacheRedis) Del(key string) error {
	_, err := cr.do("DEL", key)
	return err
}

func (cr *CacheRedis) Exists(key string) (bool, error) {
	return redis.Bool(cr.do("EXISTS", key))
}

func (cr *CacheRedis) Expire(key string, second int) (bool, error) {
	return redis.Bool(cr.do("EXPIRE", key, second))
}

func (cr *CacheRedis) Keys(key string) ([]string, error) {
	return redis.Strings(cr.do("KEYS", key))
}

func (cr *CacheRedis) Ttl(key string) (interface{}, error) {
	return redis.Int(cr.do("TTL", key))
}

func (cr *CacheRedis) HMset(key string, arr interface{}) (interface{}, error) {
	return cr.do("HMSET", redis.Args{}.Add(key).AddFlat(arr)...)
}

func (cr *CacheRedis) HGet(key string, subKey string) (interface{}, error) {
	return cr.do("HGET", key, subKey)
}

func (cr *CacheRedis) HGetAll(key string) (map[string]string, error) {
	rsByte, err := cr.do("HGETALL", key)
	if err != nil {
		return nil, err
	}
	rs, err := redis.StringMap(rsByte, err)
	if err != nil {
		return nil, err
	}
	return rs, err
}
<commit_msg>add redis flushall<commit_after>package QesyGo

import (
	"github.com/garyburd/redigo/redis"
	"time"
)

type CacheRedis struct {
	Pool     *redis.Pool // redis connection pool
	Conninfo string
	Key      string
}

func (cr *CacheRedis) newPool() {
	cr.Pool = &redis.Pool{
		MaxIdle:     30,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", cr.Conninfo)
			if err != nil {
				return nil, err
			}
			return c, err
		},
	}
}

//var pool = newPool()
func (cr *CacheRedis) Connect() error {
	cr.newPool()
	c := cr.Pool.Get()
	defer c.Close()
	return c.Err()
}

func (cr *CacheRedis) do(commandName string, args ...interface{}) (reply interface{}, err error) {
	c := cr.Pool.Get()
	defer c.Close()
	return c.Do(commandName, args...)
}

func (cr *CacheRedis) FlushAll(key string) error {
	c := cr.Pool.Get()
	defer c.Close()
	return c.Flush()
}

func (cr *CacheRedis) Get(key string) (string, error) {
	str, err := redis.String(cr.do("GET", key))
	return str, err
}

func (cr *CacheRedis) Set(key string, value string) error {
	_, err := cr.do("SET", key, value)
	return err
}

func (cr *CacheRedis) Del(key string) error {
	_, err := cr.do("DEL", key)
	return err
}

func (cr *CacheRedis) Exists(key string) (bool, error) {
	return redis.Bool(cr.do("EXISTS", key))
}

func (cr *CacheRedis) Expire(key string, second int) (bool, error) {
	return redis.Bool(cr.do("EXPIRE", key, second))
}

func (cr *CacheRedis) Keys(key string) ([]string, error) {
	return redis.Strings(cr.do("KEYS", key))
}

func (cr *CacheRedis) Ttl(key string) (interface{}, error) {
	return redis.Int(cr.do("TTL", key))
}

func (cr *CacheRedis) HMset(key string, arr interface{}) (interface{}, error) {
	return cr.do("HMSET", redis.Args{}.Add(key).AddFlat(arr)...)
}

func (cr *CacheRedis) HGet(key string, subKey string) (interface{}, error) {
	return cr.do("HGET", key, subKey)
}

func (cr *CacheRedis) HGetAll(key string) (map[string]string, error) {
	rsByte, err := cr.do("HGETALL", key)
	if err != nil {
		return nil, err
	}
	rs, err := redis.StringMap(rsByte, err)
	if err != nil {
		return nil, err
	}
	return rs, err
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 Ludovic Fauvet
// Licensed under the MIT license

package main

import (
	"errors"
	"fmt"
	"github.com/garyburd/redigo/redis"
	"time"
)

const (
	redisConnectionTimeout = 200 * time.Millisecond
	redisReadWriteTimeout  = 5000 * time.Millisecond
)

var (
	errUnreachable = errors.New("endpoint unreachable")
)

type redisobj struct {
	pool *redis.Pool
}

func NewRedis() *redisobj {
	r := &redisobj{}

	r.pool = &redis.Pool{
		MaxIdle:     10,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {
			return r.connect()
		},
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}

	return r
}

func (r *redisobj) connect() (redis.Conn, error) {
	sentinels := GetConfig().RedisSentinels

	if len(sentinels) > 0 {

		if len(GetConfig().RedisSentinelMasterName) == 0 {
			log.Error("Config: RedisSentinelMasterName cannot be empty!")
			goto single
		}

		for _, s := range sentinels {
			log.Debug("Connecting to redis sentinel %s", s.Host)
			var master []string
			var masterhost string
			var cm redis.Conn

			c, err := redis.DialTimeout("tcp", s.Host, redisConnectionTimeout, redisReadWriteTimeout, redisReadWriteTimeout)
			if err != nil {
				log.Error("Sentinel: %s", err.Error())
				continue
			}
			//AUTH?
			role, err := r.askRole(c)
			if err != nil {
				log.Error("Sentinel: %s", err.Error())
				goto closeSentinel
			}
			if role != "sentinel" {
				log.Error("Sentinel: %s is not a sentinel but a %s", s.Host, role)
				goto closeSentinel
			}

			master, err = redis.Strings(c.Do("SENTINEL", "get-master-addr-by-name", GetConfig().RedisSentinelMasterName))
			if err == redis.ErrNil {
				log.Error("Sentinel: %s doesn't know the master-name %s", s.Host, GetConfig().RedisSentinelMasterName)
				goto closeSentinel
			} else if err != nil {
				log.Error("Sentinel: %s", err.Error())
				goto closeSentinel
			}

			masterhost = fmt.Sprintf("%s:%s", master[0], master[1])

			cm, err = redis.DialTimeout("tcp", masterhost, redisConnectionTimeout, redisReadWriteTimeout, redisReadWriteTimeout)
			if err != nil {
				log.Error("Redis master: %s", err.Error())
				goto closeSentinel
			}

			if r.auth(cm) != nil {
				log.Error("Redis master: auth failed")
				goto closeMaster
			}

			role, err = r.askRole(cm)
			if err != nil {
				log.Error("Redis master: %s", err.Error())
				goto closeMaster
			}
			if role != "master" {
				log.Error("Redis master: %s is not a master but a %s", masterhost, role)
				goto closeMaster
			}

			// Close the connection to the sentinel
			c.Close()

			log.Debug("Connected to redis master %s", masterhost)
			return cm, nil

		closeMaster:
			cm.Close()

		closeSentinel:
			c.Close()
		}
	}

single:

	if len(GetConfig().RedisAddress) == 0 {
		if len(sentinels) == 0 {
			log.Error("No redis master available")
		}
		return nil, errUnreachable
	}

	log.Warning("No redis master available, trying using the configured RedisAddress as fallback")

	c, err := redis.DialTimeout("tcp", GetConfig().RedisAddress, redisConnectionTimeout, redisReadWriteTimeout, redisReadWriteTimeout)
	if err != nil {
		return nil, err
	}
	if r.auth(c); err != nil {
		c.Close()
		return nil, err
	}
	log.Debug("Connected to redis master %s", GetConfig().RedisAddress)
	return c, err

}

func (r *redisobj) askRole(c redis.Conn) (string, error) {
	roleReply, err := redis.Values(c.Do("ROLE"))
	role, err := redis.String(roleReply[0], err)
	return role, err
}

func (r *redisobj) auth(c redis.Conn) (err error) {
	if GetConfig().RedisPassword != "" {
		_, err = c.Do("AUTH", GetConfig().RedisPassword)
	}
	return
}
<commit_msg>redis: increase read/write timeout to 5 minutes<commit_after>// Copyright (c) 2014 Ludovic Fauvet
// Licensed under the MIT license

package main

import (
	"errors"
	"fmt"
	"github.com/garyburd/redigo/redis"
	"time"
)

const (
	redisConnectionTimeout = 200 * time.Millisecond
	redisReadWriteTimeout  = 300 * time.Second
)

var (
	errUnreachable = errors.New("endpoint unreachable")
)

type redisobj struct {
	pool *redis.Pool
}

func NewRedis() *redisobj {
	r := &redisobj{}

	r.pool = &redis.Pool{
		MaxIdle:     10,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {
			return r.connect()
		},
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}

	return r
}

func (r *redisobj) connect() (redis.Conn, error) {
	sentinels := GetConfig().RedisSentinels

	if len(sentinels) > 0 {

		if len(GetConfig().RedisSentinelMasterName) == 0 {
			log.Error("Config: RedisSentinelMasterName cannot be empty!")
			goto single
		}

		for _, s := range sentinels {
			log.Debug("Connecting to redis sentinel %s", s.Host)
			var master []string
			var masterhost string
			var cm redis.Conn

			c, err := redis.DialTimeout("tcp", s.Host, redisConnectionTimeout, redisReadWriteTimeout, redisReadWriteTimeout)
			if err != nil {
				log.Error("Sentinel: %s", err.Error())
				continue
			}
			//AUTH?
			role, err := r.askRole(c)
			if err != nil {
				log.Error("Sentinel: %s", err.Error())
				goto closeSentinel
			}
			if role != "sentinel" {
				log.Error("Sentinel: %s is not a sentinel but a %s", s.Host, role)
				goto closeSentinel
			}

			master, err = redis.Strings(c.Do("SENTINEL", "get-master-addr-by-name", GetConfig().RedisSentinelMasterName))
			if err == redis.ErrNil {
				log.Error("Sentinel: %s doesn't know the master-name %s", s.Host, GetConfig().RedisSentinelMasterName)
				goto closeSentinel
			} else if err != nil {
				log.Error("Sentinel: %s", err.Error())
				goto closeSentinel
			}

			masterhost = fmt.Sprintf("%s:%s", master[0], master[1])

			cm, err = redis.DialTimeout("tcp", masterhost, redisConnectionTimeout, redisReadWriteTimeout, redisReadWriteTimeout)
			if err != nil {
				log.Error("Redis master: %s", err.Error())
				goto closeSentinel
			}

			if r.auth(cm) != nil {
				log.Error("Redis master: auth failed")
				goto closeMaster
			}

			role, err = r.askRole(cm)
			if err != nil {
				log.Error("Redis master: %s", err.Error())
				goto closeMaster
			}
			if role != "master" {
				log.Error("Redis master: %s is not a master but a %s", masterhost, role)
				goto closeMaster
			}

			// Close the connection to the sentinel
			c.Close()

			log.Debug("Connected to redis master %s", masterhost)
			return cm, nil

		closeMaster:
			cm.Close()

		closeSentinel:
			c.Close()
		}
	}

single:

	if len(GetConfig().RedisAddress) == 0 {
		if len(sentinels) == 0 {
			log.Error("No redis master available")
		}
		return nil, errUnreachable
	}

	log.Warning("No redis master available, trying using the configured RedisAddress as fallback")

	c, err := redis.DialTimeout("tcp", GetConfig().RedisAddress, redisConnectionTimeout, redisReadWriteTimeout, redisReadWriteTimeout)
	if err != nil {
		return nil, err
	}
	if r.auth(c); err != nil {
		c.Close()
		return nil, err
	}
	log.Debug("Connected to redis master %s", GetConfig().RedisAddress)
	return c, err

}

func (r *redisobj) askRole(c redis.Conn) (string, error) {
	roleReply, err := redis.Values(c.Do("ROLE"))
	role, err := redis.String(roleReply[0], err)
	return role, err
}

func (r *redisobj) auth(c redis.Conn) (err error) {
	if GetConfig().RedisPassword != "" {
		_, err = c.Do("AUTH", GetConfig().RedisPassword)
	}
	return
}
<|endoftext|>


<commit_before>// Copyright 2018 The Go Cloud Authors
//
// 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
//
//     https://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 wire contains directives for Wire code generation.
package wire

// ProviderSet is a marker type that collects a group of providers.
type ProviderSet struct{}

// NewSet creates a new provider set that includes the providers in
// its arguments. Each argument is either an exported function value,
// an exported struct (zero) value, a provider set, a call to Bind, a
// a call to Value, or a call to InterfaceValue.
func NewSet(...interface{}) ProviderSet {
	return ProviderSet{}
}

// Build is placed in the body of an injector function to declare the
// providers to use. Its arguments are the same as NewSet. Its return
// value is an error message that can be sent to panic.
//
// Examples:
//
//	func injector(ctx context.Context) (*sql.DB, error) {
//		wire.Build(otherpkg.FooSet, myProviderFunc)
//		return nil, nil
//	}
//
//	func injector(ctx context.Context) (*sql.DB, error) {
//		panic(wire.Build(otherpkg.FooSet, myProviderFunc))
//	}
func Build(...interface{}) string {
	return "implementation not generated, run wire"
}

// A Binding maps an interface to a concrete type.
type Binding struct{}

// Bind declares that a concrete type should be used to satisfy a
// dependency on the type of iface, which must be a pointer to an
// interface type.
//
// Example:
//
//	type Fooer interface {
//		Foo()
//	}
//
//	type MyFoo struct{}
//
//	func (MyFoo) Foo() {}
//
//	var MySet = wire.NewSet(
//		MyFoo{},
//		wire.Bind(new(Fooer), new(MyFoo)))
func Bind(iface, to interface{}) Binding {
	return Binding{}
}

// A ProvidedValue is an expression that is copied to the generated injector.
type ProvidedValue struct{}

// Value binds an expression to provide the type of the expression.
// The expression may not be an interface value; use InterfaceValue for that.
//
// Example:
//
//	var MySet = wire.NewSet(wire.Value([]string(nil)))
func Value(interface{}) ProvidedValue {
	return ProvidedValue{}
}

// InterfaceValue binds an expression to provide a specific interface type.
//
// Example:
//
//	var MySet = wire.NewSet(wire.InterfaceValue(new(io.Reader), os.Stdin))
func InterfaceValue(typ interface{}, x interface{}) ProvidedValue {
	return ProvidedValue{}
}
<commit_msg>wire: remove duplicated "a" (google/go-cloud#561)<commit_after>// Copyright 2018 The Go Cloud Authors
//
// 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
//
//     https://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 wire contains directives for Wire code generation.
package wire

// ProviderSet is a marker type that collects a group of providers.
type ProviderSet struct{}

// NewSet creates a new provider set that includes the providers in
// its arguments. Each argument is either an exported function value,
// an exported struct (zero) value, a provider set, a call to Bind,
// a call to Value, or a call to InterfaceValue.
func NewSet(...interface{}) ProviderSet {
	return ProviderSet{}
}

// Build is placed in the body of an injector function to declare the
// providers to use. Its arguments are the same as NewSet. Its return
// value is an error message that can be sent to panic.
//
// Examples:
//
//	func injector(ctx context.Context) (*sql.DB, error) {
//		wire.Build(otherpkg.FooSet, myProviderFunc)
//		return nil, nil
//	}
//
//	func injector(ctx context.Context) (*sql.DB, error) {
//		panic(wire.Build(otherpkg.FooSet, myProviderFunc))
//	}
func Build(...interface{}) string {
	return "implementation not generated, run wire"
}

// A Binding maps an interface to a concrete type.
type Binding struct{}

// Bind declares that a concrete type should be used to satisfy a
// dependency on the type of iface, which must be a pointer to an
// interface type.
//
// Example:
//
//	type Fooer interface {
//		Foo()
//	}
//
//	type MyFoo struct{}
//
//	func (MyFoo) Foo() {}
//
//	var MySet = wire.NewSet(
//		MyFoo{},
//		wire.Bind(new(Fooer), new(MyFoo)))
func Bind(iface, to interface{}) Binding {
	return Binding{}
}

// A ProvidedValue is an expression that is copied to the generated injector.
type ProvidedValue struct{}

// Value binds an expression to provide the type of the expression.
// The expression may not be an interface value; use InterfaceValue for that.
//
// Example:
//
//	var MySet = wire.NewSet(wire.Value([]string(nil)))
func Value(interface{}) ProvidedValue {
	return ProvidedValue{}
}

// InterfaceValue binds an expression to provide a specific interface type.
//
// Example:
//
//	var MySet = wire.NewSet(wire.InterfaceValue(new(io.Reader), os.Stdin))
func InterfaceValue(typ interface{}, x interface{}) ProvidedValue {
	return ProvidedValue{}
}
<|endoftext|>


<commit_before>package db

import (
	"github.com/jmcvetta/neoism"
	"os"
)

func Connect() *neoism.Database {
	url := os.Getenv("NEO4J")
	if url == "" {
		url = "http://localhost:7474/data/db"
	}
	db, err := neoism.Connect(url)
	if err != nil {
		panic(err)
	}
	return db
}
<commit_msg>neo4j connector<commit_after>package neo

import (
	"github.com/jmcvetta/neoism"
	"os"
)

func Connect() *neoism.Database {
	url := os.Getenv("NEO4J")
	if url == "" {
		url = "http://localhost:7474/data/db"
	}
	db, err := neoism.Connect(url)
	if err != nil {
		panic(err)
	}
	return db
}
<|endoftext|>