<commit_before>//   Copyright 2016 DigitalOcean
//
//   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 collectors

import (
	"encoding/json"
	"log"

	"github.com/prometheus/client_golang/prometheus"
)

// PoolUsageCollector displays statistics about each pool in the Ceph cluster.
type PoolUsageCollector struct {
	conn Conn

	// UsedBytes tracks the amount of bytes currently allocated for the pool. This
	// does not factor in the overcommitment made for individual images.
	UsedBytes *prometheus.GaugeVec

	// RawUsedBytes tracks the amount of raw bytes currently used for the pool. This
	// factors in the replication factor (size) of the pool.
	RawUsedBytes *prometheus.GaugeVec

	// MaxAvail tracks the amount of bytes currently free for the pool,
	// which depends on the replication settings for the pool in question.
	MaxAvail *prometheus.GaugeVec

	// PercentUsed is the percentage of raw space available to the pool currently in use
	PercentUsed *prometheus.GaugeVec

	// Objects shows the no. of RADOS objects created within the pool.
	Objects *prometheus.GaugeVec

	// DirtyObjects shows the no. of RADOS dirty objects in a cache-tier pool,
	// this doesn't make sense in a regular pool, see:
	// http://lists.ceph.com/pipermail/ceph-users-ceph.com/2015-April/000557.html
	DirtyObjects *prometheus.GaugeVec

	// ReadIO tracks the read IO calls made for the images within each pool.
	ReadIO *prometheus.GaugeVec

	// Readbytes tracks the read throughput made for the images within each pool.
	ReadBytes *prometheus.GaugeVec

	// WriteIO tracks the write IO calls made for the images within each pool.
	WriteIO *prometheus.GaugeVec

	// WriteBytes tracks the write throughput made for the images within each pool.
	WriteBytes *prometheus.GaugeVec
}

// NewPoolUsageCollector creates a new instance of PoolUsageCollector and returns
// its reference.
func NewPoolUsageCollector(conn Conn, cluster string) *PoolUsageCollector {
	var (
		subSystem = "pool"
		poolLabel = []string{"pool"}
	)

	labels := make(prometheus.Labels)
	labels["cluster"] = cluster

	return &PoolUsageCollector{
		conn: conn,

		UsedBytes: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "used_bytes",
				Help:        "Capacity of the pool that is currently under use",
				ConstLabels: labels,
			},
			poolLabel,
		),
		RawUsedBytes: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "raw_used_bytes",
				Help:        "Raw capacity of the pool that is currently under use, this factors in the size",
				ConstLabels: labels,
			},
			poolLabel,
		),
		MaxAvail: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "available_bytes",
				Help:        "Free space for this pool",
				ConstLabels: labels,
			},
			poolLabel,
		),
		PercentUsed: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "percent_used",
				Help:        "Percentage of the capacity available to this pool that is used by this pool",
				ConstLabels: labels,
			},
			poolLabel,
		),
		Objects: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "objects_total",
				Help:        "Total no. of objects allocated within the pool",
				ConstLabels: labels,
			},
			poolLabel,
		),
		DirtyObjects: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "dirty_objects_total",
				Help:        "Total no. of dirty objects in a cache-tier pool",
				ConstLabels: labels,
			},
			poolLabel,
		),
		ReadIO: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "read_total",
				Help:        "Total read i/o calls for the pool",
				ConstLabels: labels,
			},
			poolLabel,
		),
		ReadBytes: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "read_bytes_total",
				Help:        "Total read throughput for the pool",
				ConstLabels: labels,
			},
			poolLabel,
		),
		WriteIO: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "write_total",
				Help:        "Total write i/o calls for the pool",
				ConstLabels: labels,
			},
			poolLabel,
		),
		WriteBytes: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "write_bytes_total",
				Help:        "Total write throughput for the pool",
				ConstLabels: labels,
			},
			poolLabel,
		),
	}
}

func (p *PoolUsageCollector) collectorList() []prometheus.Collector {
	return []prometheus.Collector{
		p.UsedBytes,
		p.RawUsedBytes,
		p.MaxAvail,
		p.PercentUsed,
		p.Objects,
		p.DirtyObjects,
		p.ReadIO,
		p.ReadBytes,
		p.WriteIO,
		p.WriteBytes,
	}
}

type cephPoolStats struct {
	Pools []struct {
		Name  string `json:"name"`
		ID    int    `json:"id"`
		Stats struct {
			BytesUsed    float64 `json:"bytes_used"`
			StoredRaw    float64 `json:"stored_raw"`
			MaxAvail     float64 `json:"max_avail"`
			PercentUsed  float64 `json:"percent_used"`
			Objects      float64 `json:"objects"`
			DirtyObjects float64 `json:"dirty"`
			ReadIO       float64 `json:"rd"`
			ReadBytes    float64 `json:"rd_bytes"`
			WriteIO      float64 `json:"wr"`
			WriteBytes   float64 `json:"wr_bytes"`
		} `json:"stats"`
	} `json:"pools"`
}

func (p *PoolUsageCollector) collect() error {
	cmd := p.cephUsageCommand()
	buf, _, err := p.conn.MonCommand(cmd)
	if err != nil {
		return err
	}

	stats := &cephPoolStats{}
	if err := json.Unmarshal(buf, stats); err != nil {
		return err
	}

	// Reset pool specfic metrics, pools can be removed
	p.UsedBytes.Reset()
	p.RawUsedBytes.Reset()
	p.MaxAvail.Reset()
	p.PercentUsed.Reset()
	p.Objects.Reset()
	p.DirtyObjects.Reset()
	p.ReadIO.Reset()
	p.ReadBytes.Reset()
	p.WriteIO.Reset()
	p.WriteBytes.Reset()

	for _, pool := range stats.Pools {
		p.UsedBytes.WithLabelValues(pool.Name).Set(pool.Stats.BytesUsed)
		p.RawUsedBytes.WithLabelValues(pool.Name).Set(pool.Stats.StoredRaw)
		p.MaxAvail.WithLabelValues(pool.Name).Set(pool.Stats.MaxAvail)
		p.PercentUsed.WithLabelValues(pool.Name).Set(pool.Stats.PercentUsed)
		p.Objects.WithLabelValues(pool.Name).Set(pool.Stats.Objects)
		p.DirtyObjects.WithLabelValues(pool.Name).Set(pool.Stats.DirtyObjects)
		p.ReadIO.WithLabelValues(pool.Name).Set(pool.Stats.ReadIO)
		p.ReadBytes.WithLabelValues(pool.Name).Set(pool.Stats.ReadBytes)
		p.WriteIO.WithLabelValues(pool.Name).Set(pool.Stats.WriteIO)
		p.WriteBytes.WithLabelValues(pool.Name).Set(pool.Stats.WriteBytes)
	}

	return nil
}

func (p *PoolUsageCollector) cephUsageCommand() []byte {
	cmd, err := json.Marshal(map[string]interface{}{
		"prefix": "df",
		"detail": "detail",
		"format": "json",
	})
	if err != nil {
		// panic! because ideally in no world this hard-coded input
		// should fail.
		panic(err)
	}
	return cmd
}

// Describe fulfills the prometheus.Collector's interface and sends the descriptors
// of pool's metrics to the given channel.
func (p *PoolUsageCollector) Describe(ch chan<- *prometheus.Desc) {
	for _, metric := range p.collectorList() {
		metric.Describe(ch)
	}
}

// Collect extracts the current values of all the metrics and sends them to the
// prometheus channel.
func (p *PoolUsageCollector) Collect(ch chan<- prometheus.Metric) {
	if err := p.collect(); err != nil {
		log.Println("[ERROR] failed collecting pool usage metrics:", err)
		return
	}

	for _, metric := range p.collectorList() {
		metric.Collect(ch)
	}
}
<commit_msg>pool_usage: Use the maximum of bytes_used and stored_raw for raw used bytes.<commit_after>//   Copyright 2016 DigitalOcean
//
//   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 collectors

import (
	"encoding/json"
	"log"
	"math"

	"github.com/prometheus/client_golang/prometheus"
)

// PoolUsageCollector displays statistics about each pool in the Ceph cluster.
type PoolUsageCollector struct {
	conn Conn

	// UsedBytes tracks the amount of bytes currently allocated for the pool. This
	// does not factor in the overcommitment made for individual images.
	UsedBytes *prometheus.GaugeVec

	// RawUsedBytes tracks the amount of raw bytes currently used for the pool. This
	// factors in the replication factor (size) of the pool.
	RawUsedBytes *prometheus.GaugeVec

	// MaxAvail tracks the amount of bytes currently free for the pool,
	// which depends on the replication settings for the pool in question.
	MaxAvail *prometheus.GaugeVec

	// PercentUsed is the percentage of raw space available to the pool currently in use
	PercentUsed *prometheus.GaugeVec

	// Objects shows the no. of RADOS objects created within the pool.
	Objects *prometheus.GaugeVec

	// DirtyObjects shows the no. of RADOS dirty objects in a cache-tier pool,
	// this doesn't make sense in a regular pool, see:
	// http://lists.ceph.com/pipermail/ceph-users-ceph.com/2015-April/000557.html
	DirtyObjects *prometheus.GaugeVec

	// ReadIO tracks the read IO calls made for the images within each pool.
	ReadIO *prometheus.GaugeVec

	// Readbytes tracks the read throughput made for the images within each pool.
	ReadBytes *prometheus.GaugeVec

	// WriteIO tracks the write IO calls made for the images within each pool.
	WriteIO *prometheus.GaugeVec

	// WriteBytes tracks the write throughput made for the images within each pool.
	WriteBytes *prometheus.GaugeVec
}

// NewPoolUsageCollector creates a new instance of PoolUsageCollector and returns
// its reference.
func NewPoolUsageCollector(conn Conn, cluster string) *PoolUsageCollector {
	var (
		subSystem = "pool"
		poolLabel = []string{"pool"}
	)

	labels := make(prometheus.Labels)
	labels["cluster"] = cluster

	return &PoolUsageCollector{
		conn: conn,

		UsedBytes: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "used_bytes",
				Help:        "Capacity of the pool that is currently under use",
				ConstLabels: labels,
			},
			poolLabel,
		),
		RawUsedBytes: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "raw_used_bytes",
				Help:        "Raw capacity of the pool that is currently under use, this factors in the size",
				ConstLabels: labels,
			},
			poolLabel,
		),
		MaxAvail: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "available_bytes",
				Help:        "Free space for this pool",
				ConstLabels: labels,
			},
			poolLabel,
		),
		PercentUsed: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "percent_used",
				Help:        "Percentage of the capacity available to this pool that is used by this pool",
				ConstLabels: labels,
			},
			poolLabel,
		),
		Objects: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "objects_total",
				Help:        "Total no. of objects allocated within the pool",
				ConstLabels: labels,
			},
			poolLabel,
		),
		DirtyObjects: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "dirty_objects_total",
				Help:        "Total no. of dirty objects in a cache-tier pool",
				ConstLabels: labels,
			},
			poolLabel,
		),
		ReadIO: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "read_total",
				Help:        "Total read i/o calls for the pool",
				ConstLabels: labels,
			},
			poolLabel,
		),
		ReadBytes: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "read_bytes_total",
				Help:        "Total read throughput for the pool",
				ConstLabels: labels,
			},
			poolLabel,
		),
		WriteIO: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "write_total",
				Help:        "Total write i/o calls for the pool",
				ConstLabels: labels,
			},
			poolLabel,
		),
		WriteBytes: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "write_bytes_total",
				Help:        "Total write throughput for the pool",
				ConstLabels: labels,
			},
			poolLabel,
		),
	}
}

func (p *PoolUsageCollector) collectorList() []prometheus.Collector {
	return []prometheus.Collector{
		p.UsedBytes,
		p.RawUsedBytes,
		p.MaxAvail,
		p.PercentUsed,
		p.Objects,
		p.DirtyObjects,
		p.ReadIO,
		p.ReadBytes,
		p.WriteIO,
		p.WriteBytes,
	}
}

type cephPoolStats struct {
	Pools []struct {
		Name  string `json:"name"`
		ID    int    `json:"id"`
		Stats struct {
			BytesUsed    float64 `json:"bytes_used"`
			StoredRaw    float64 `json:"stored_raw"`
			MaxAvail     float64 `json:"max_avail"`
			PercentUsed  float64 `json:"percent_used"`
			Objects      float64 `json:"objects"`
			DirtyObjects float64 `json:"dirty"`
			ReadIO       float64 `json:"rd"`
			ReadBytes    float64 `json:"rd_bytes"`
			WriteIO      float64 `json:"wr"`
			WriteBytes   float64 `json:"wr_bytes"`
		} `json:"stats"`
	} `json:"pools"`
}

func (p *PoolUsageCollector) collect() error {
	cmd := p.cephUsageCommand()
	buf, _, err := p.conn.MonCommand(cmd)
	if err != nil {
		return err
	}

	stats := &cephPoolStats{}
	if err := json.Unmarshal(buf, stats); err != nil {
		return err
	}

	// Reset pool specfic metrics, pools can be removed
	p.UsedBytes.Reset()
	p.RawUsedBytes.Reset()
	p.MaxAvail.Reset()
	p.PercentUsed.Reset()
	p.Objects.Reset()
	p.DirtyObjects.Reset()
	p.ReadIO.Reset()
	p.ReadBytes.Reset()
	p.WriteIO.Reset()
	p.WriteBytes.Reset()

	for _, pool := range stats.Pools {
		p.UsedBytes.WithLabelValues(pool.Name).Set(pool.Stats.BytesUsed)
		p.RawUsedBytes.WithLabelValues(pool.Name).Set(math.Max(pool.Stats.StoredRaw, pool.Stats.BytesUsed))
		p.MaxAvail.WithLabelValues(pool.Name).Set(pool.Stats.MaxAvail)
		p.PercentUsed.WithLabelValues(pool.Name).Set(pool.Stats.PercentUsed)
		p.Objects.WithLabelValues(pool.Name).Set(pool.Stats.Objects)
		p.DirtyObjects.WithLabelValues(pool.Name).Set(pool.Stats.DirtyObjects)
		p.ReadIO.WithLabelValues(pool.Name).Set(pool.Stats.ReadIO)
		p.ReadBytes.WithLabelValues(pool.Name).Set(pool.Stats.ReadBytes)
		p.WriteIO.WithLabelValues(pool.Name).Set(pool.Stats.WriteIO)
		p.WriteBytes.WithLabelValues(pool.Name).Set(pool.Stats.WriteBytes)
	}

	return nil
}

func (p *PoolUsageCollector) cephUsageCommand() []byte {
	cmd, err := json.Marshal(map[string]interface{}{
		"prefix": "df",
		"detail": "detail",
		"format": "json",
	})
	if err != nil {
		// panic! because ideally in no world this hard-coded input
		// should fail.
		panic(err)
	}
	return cmd
}

// Describe fulfills the prometheus.Collector's interface and sends the descriptors
// of pool's metrics to the given channel.
func (p *PoolUsageCollector) Describe(ch chan<- *prometheus.Desc) {
	for _, metric := range p.collectorList() {
		metric.Describe(ch)
	}
}

// Collect extracts the current values of all the metrics and sends them to the
// prometheus channel.
func (p *PoolUsageCollector) Collect(ch chan<- prometheus.Metric) {
	if err := p.collect(); err != nil {
		log.Println("[ERROR] failed collecting pool usage metrics:", err)
		return
	}

	for _, metric := range p.collectorList() {
		metric.Collect(ch)
	}
}
<|endoftext|>


<commit_before>package service

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

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/filters"
	swarmtypes "github.com/docker/docker/api/types/swarm"
	"github.com/docker/docker/client"
)

// parseSecretString parses the requested secret and returns the secret name
// and target.  Expects format SECRET_NAME:TARGET
func parseSecretString(secretString string) (string, string, error) {
	tokens := strings.Split(secretString, ":")

	secretName := strings.TrimSpace(tokens[0])
	targetName := secretName

	if secretName == "" {
		return "", "", fmt.Errorf("invalid secret name provided")
	}

	if len(tokens) > 1 {
		targetName = strings.TrimSpace(tokens[1])
		if targetName == "" {
			return "", "", fmt.Errorf("invalid presentation name provided")
		}
	}

	// ensure target is a filename only; no paths allowed
	tDir, _ := filepath.Split(targetName)
	if tDir != "" {
		return "", "", fmt.Errorf("target must not have a path")
	}

	return secretName, targetName, nil
}

// parseSecrets retrieves the secrets from the requested names and converts
// them to secret references to use with the spec
func parseSecrets(client client.APIClient, requestedSecrets []string) ([]*swarmtypes.SecretReference, error) {
	secretRefs := make(map[string]*swarmtypes.SecretReference)
	ctx := context.Background()

	for _, secret := range requestedSecrets {
		n, t, err := parseSecretString(secret)
		if err != nil {
			return nil, err
		}

		secretRef := &swarmtypes.SecretReference{
			SecretName: n,
			Mode:       swarmtypes.SecretReferenceFile,
			Target:     t,
		}

		if _, exists := secretRefs[t]; exists {
			return nil, fmt.Errorf("duplicate secret target for %s not allowed", n)
		}
		secretRefs[t] = secretRef
	}

	args := filters.NewArgs()
	for _, s := range secretRefs {
		args.Add("names", s.SecretName)
	}

	secrets, err := client.SecretList(ctx, types.SecretListOptions{
		Filter: args,
	})
	if err != nil {
		return nil, err
	}

	foundSecrets := make(map[string]string)
	for _, secret := range secrets {
		foundSecrets[secret.Spec.Annotations.Name] = secret.ID
	}

	addedSecrets := []*swarmtypes.SecretReference{}

	for _, ref := range secretRefs {
		id, ok := foundSecrets[ref.SecretName]
		if !ok {
			return nil, fmt.Errorf("secret not found: %s", ref.SecretName)
		}

		// set the id for the ref to properly assign in swarm
		// since swarm needs the ID instead of the name
		ref.SecretID = id
		addedSecrets = append(addedSecrets, ref)
	}

	return addedSecrets, nil
}
<commit_msg>update to support new target in swarmkit<commit_after>package service

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

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/filters"
	swarmtypes "github.com/docker/docker/api/types/swarm"
	"github.com/docker/docker/client"
)

// parseSecretString parses the requested secret and returns the secret name
// and target.  Expects format SECRET_NAME:TARGET
func parseSecretString(secretString string) (string, string, error) {
	tokens := strings.Split(secretString, ":")

	secretName := strings.TrimSpace(tokens[0])
	targetName := secretName

	if secretName == "" {
		return "", "", fmt.Errorf("invalid secret name provided")
	}

	if len(tokens) > 1 {
		targetName = strings.TrimSpace(tokens[1])
		if targetName == "" {
			return "", "", fmt.Errorf("invalid presentation name provided")
		}
	}

	// ensure target is a filename only; no paths allowed
	tDir, _ := filepath.Split(targetName)
	if tDir != "" {
		return "", "", fmt.Errorf("target must not have a path")
	}

	return secretName, targetName, nil
}

// parseSecrets retrieves the secrets from the requested names and converts
// them to secret references to use with the spec
func parseSecrets(client client.APIClient, requestedSecrets []string) ([]*swarmtypes.SecretReference, error) {
	secretRefs := make(map[string]*swarmtypes.SecretReference)
	ctx := context.Background()

	for _, secret := range requestedSecrets {
		n, t, err := parseSecretString(secret)
		if err != nil {
			return nil, err
		}

		secretRef := &swarmtypes.SecretReference{
			SecretName: n,
			// TODO (ehazlett): parse these from cli request
			Target: swarmtypes.SecretReferenceFileTarget{
				Name: t,
				UID:  "0",
				GID:  "0",
				Mode: 0444,
			},
		}

		if _, exists := secretRefs[t]; exists {
			return nil, fmt.Errorf("duplicate secret target for %s not allowed", n)
		}
		secretRefs[t] = secretRef
	}

	args := filters.NewArgs()
	for _, s := range secretRefs {
		args.Add("names", s.SecretName)
	}

	secrets, err := client.SecretList(ctx, types.SecretListOptions{
		Filter: args,
	})
	if err != nil {
		return nil, err
	}

	foundSecrets := make(map[string]string)
	for _, secret := range secrets {
		foundSecrets[secret.Spec.Annotations.Name] = secret.ID
	}

	addedSecrets := []*swarmtypes.SecretReference{}

	for _, ref := range secretRefs {
		id, ok := foundSecrets[ref.SecretName]
		if !ok {
			return nil, fmt.Errorf("secret not found: %s", ref.SecretName)
		}

		// set the id for the ref to properly assign in swarm
		// since swarm needs the ID instead of the name
		ref.SecretID = id
		addedSecrets = append(addedSecrets, ref)
	}

	return addedSecrets, nil
}
<|endoftext|>


<commit_before>package gorm

import (
	"errors"
	"fmt"
	"regexp"
	"strings"
	"time"

	"reflect"
)

type Scope struct {
	Search          *search
	Value           interface{}
	Sql             string
	SqlVars         []interface{}
	db              *DB
	indirectValue   *reflect.Value
	instanceId      string
	primaryKeyField *Field
	skipLeft        bool
	fields          map[string]*Field
	selectAttrs     *[]string
}

func (scope *Scope) IndirectValue() reflect.Value {
	if scope.indirectValue == nil {
		value := reflect.Indirect(reflect.ValueOf(scope.Value))
		if value.Kind() == reflect.Ptr {
			value = value.Elem()
		}
		scope.indirectValue = &value
	}
	return *scope.indirectValue
}

func (scope *Scope) NeedPtr() *Scope {
	reflectKind := reflect.ValueOf(scope.Value).Kind()
	if !((reflectKind == reflect.Invalid) || (reflectKind == reflect.Ptr)) {
		err := fmt.Errorf("%v %v\n", fileWithLineNum(), "using unaddressable value")
		scope.Err(err)
		fmt.Printf(err.Error())
	}
	return scope
}

// New create a new Scope without search information
func (scope *Scope) New(value interface{}) *Scope {
	return &Scope{db: scope.NewDB(), Search: &search{}, Value: value}
}

// NewDB create a new DB without search information
func (scope *Scope) NewDB() *DB {
	if scope.db != nil {
		db := scope.db.clone()
		db.search = nil
		db.Value = nil
		return db
	}
	return nil
}

func (scope *Scope) DB() *DB {
	return scope.db
}

// SqlDB return *sql.DB
func (scope *Scope) SqlDB() sqlCommon {
	return scope.db.db
}

// SkipLeft skip remaining callbacks
func (scope *Scope) SkipLeft() {
	scope.skipLeft = true
}

// Quote used to quote database column name according to database dialect
func (scope *Scope) Quote(str string) string {
	if strings.Index(str, ".") != -1 {
		newStrs := []string{}
		for _, str := range strings.Split(str, ".") {
			newStrs = append(newStrs, scope.Dialect().Quote(str))
		}
		return strings.Join(newStrs, ".")
	} else {
		return scope.Dialect().Quote(str)
	}
}

func (scope *Scope) QuoteIfPossible(str string) string {
	if regexp.MustCompile("^[a-zA-Z]+(.[a-zA-Z]+)*$").MatchString(str) {
		return scope.Quote(str)
	}
	return str
}

// Dialect get dialect
func (scope *Scope) Dialect() Dialect {
	return scope.db.parent.dialect
}

// Err write error
func (scope *Scope) Err(err error) error {
	if err != nil {
		scope.db.err(err)
	}
	return err
}

// Log print log message
func (scope *Scope) Log(v ...interface{}) {
	scope.db.log(v...)
}

// HasError check if there are any error
func (scope *Scope) HasError() bool {
	return scope.db.Error != nil
}

func (scope *Scope) PrimaryFields() []*Field {
	var fields = []*Field{}
	for _, field := range scope.GetModelStruct().PrimaryFields {
		fields = append(fields, scope.Fields()[field.DBName])
	}
	return fields
}

func (scope *Scope) PrimaryField() *Field {
	if primaryFields := scope.GetModelStruct().PrimaryFields; len(primaryFields) > 0 {
		if len(primaryFields) > 1 {
			if field, ok := scope.Fields()["id"]; ok {
				return field
			}
		}
		return scope.Fields()[primaryFields[0].DBName]
	}
	return nil
}

// PrimaryKey get the primary key's column name
func (scope *Scope) PrimaryKey() string {
	if field := scope.PrimaryField(); field != nil {
		return field.DBName
	}
	return ""
}

// PrimaryKeyZero check the primary key is blank or not
func (scope *Scope) PrimaryKeyZero() bool {
	field := scope.PrimaryField()
	return field == nil || field.IsBlank
}

// PrimaryKeyValue get the primary key's value
func (scope *Scope) PrimaryKeyValue() interface{} {
	if field := scope.PrimaryField(); field != nil && field.Field.IsValid() {
		return field.Field.Interface()
	}
	return 0
}

// HasColumn to check if has column
func (scope *Scope) HasColumn(column string) bool {
	for _, field := range scope.GetStructFields() {
		if field.IsNormal && (field.Name == column || field.DBName == column) {
			return true
		}
	}
	return false
}

// SetColumn to set the column's value
func (scope *Scope) SetColumn(column interface{}, value interface{}) error {
	if field, ok := column.(*Field); ok {
		return field.Set(value)
	} else if name, ok := column.(string); ok {

		if field, ok := scope.Fields()[name]; ok {
			return field.Set(value)
		}

		dbName := ToDBName(name)
		if field, ok := scope.Fields()[dbName]; ok {
			return field.Set(value)
		}

		if field, ok := scope.FieldByName(name); ok {
			return field.Set(value)
		}
	}
	return errors.New("could not convert column to field")
}

func (scope *Scope) CallMethod(name string, checkError bool) {
	if scope.Value == nil || (checkError && scope.HasError()) {
		return
	}

	call := func(value interface{}) {
		if fm := reflect.ValueOf(value).MethodByName(name); fm.IsValid() {
			switch f := fm.Interface().(type) {
			case func():
				f()
			case func(s *Scope):
				f(scope)
			case func(s *DB):
				newDB := scope.NewDB()
				f(newDB)
				scope.Err(newDB.Error)
			case func() error:
				scope.Err(f())
			case func(s *Scope) error:
				scope.Err(f(scope))
			case func(s *DB) error:
				scope.Err(f(scope.NewDB()))
			default:
				scope.Err(fmt.Errorf("unsupported function %v", name))
			}
		}
	}

	if values := scope.IndirectValue(); values.Kind() == reflect.Slice {
		for i := 0; i < values.Len(); i++ {
			call(values.Index(i).Addr().Interface())
		}
	} else {
		call(scope.Value)
	}
}

func (scope *Scope) CallMethodWithErrorCheck(name string) {
	scope.CallMethod(name, true)
}

// AddToVars add value as sql's vars, gorm will escape them
func (scope *Scope) AddToVars(value interface{}) string {
	if expr, ok := value.(*expr); ok {
		exp := expr.expr
		for _, arg := range expr.args {
			exp = strings.Replace(exp, "?", scope.AddToVars(arg), 1)
		}
		return exp
	} else {
		scope.SqlVars = append(scope.SqlVars, value)
		return scope.Dialect().BinVar(len(scope.SqlVars))
	}
}

type tabler interface {
	TableName() string
}

type dbTabler interface {
	TableName(*DB) string
}

// TableName get table name
func (scope *Scope) TableName() string {
	if scope.Search != nil && len(scope.Search.tableName) > 0 {
		return scope.Search.tableName
	}

	if tabler, ok := scope.Value.(tabler); ok {
		return tabler.TableName()
	}

	if tabler, ok := scope.Value.(dbTabler); ok {
		return tabler.TableName(scope.db)
	}

	return scope.GetModelStruct().TableName(scope.db.Model(scope.Value))
}

func (scope *Scope) QuotedTableName() (name string) {
	if scope.Search != nil && len(scope.Search.tableName) > 0 {
		if strings.Index(scope.Search.tableName, " ") != -1 {
			return scope.Search.tableName
		}
		return scope.Quote(scope.Search.tableName)
	} else {
		return scope.Quote(scope.TableName())
	}
}

// CombinedConditionSql get combined condition sql
func (scope *Scope) CombinedConditionSql() string {
	return scope.joinsSql() + scope.whereSql() + scope.groupSql() +
		scope.havingSql() + scope.orderSql() + scope.limitSql() + scope.offsetSql()
}

func (scope *Scope) FieldByName(name string) (field *Field, ok bool) {
	for _, field := range scope.Fields() {
		if field.Name == name || field.DBName == name {
			return field, true
		}
	}
	return nil, false
}

// Raw set sql
func (scope *Scope) Raw(sql string) *Scope {
	scope.Sql = strings.Replace(sql, "$$", "?", -1)
	return scope
}

// Exec invoke sql
func (scope *Scope) Exec() *Scope {
	defer scope.Trace(NowFunc())

	if !scope.HasError() {
		if result, err := scope.SqlDB().Exec(scope.Sql, scope.SqlVars...); scope.Err(err) == nil {
			if count, err := result.RowsAffected(); scope.Err(err) == nil {
				scope.db.RowsAffected = count
			}
		}
	}
	return scope
}

// Set set value by name
func (scope *Scope) Set(name string, value interface{}) *Scope {
	scope.db.InstantSet(name, value)
	return scope
}

// Get get value by name
func (scope *Scope) Get(name string) (interface{}, bool) {
	return scope.db.Get(name)
}

// InstanceId get InstanceId for scope
func (scope *Scope) InstanceId() string {
	if scope.instanceId == "" {
		scope.instanceId = fmt.Sprintf("%v%v", &scope, &scope.db)
	}
	return scope.instanceId
}

func (scope *Scope) InstanceSet(name string, value interface{}) *Scope {
	return scope.Set(name+scope.InstanceId(), value)
}

func (scope *Scope) InstanceGet(name string) (interface{}, bool) {
	return scope.Get(name + scope.InstanceId())
}

// Trace print sql log
func (scope *Scope) Trace(t time.Time) {
	if len(scope.Sql) > 0 {
		scope.db.slog(scope.Sql, t, scope.SqlVars...)
	}
}

// Begin start a transaction
func (scope *Scope) Begin() *Scope {
	if db, ok := scope.SqlDB().(sqlDb); ok {
		if tx, err := db.Begin(); err == nil {
			scope.db.db = interface{}(tx).(sqlCommon)
			scope.InstanceSet("gorm:started_transaction", true)
		}
	}
	return scope
}

// CommitOrRollback commit current transaction if there is no error, otherwise rollback it
func (scope *Scope) CommitOrRollback() *Scope {
	if _, ok := scope.InstanceGet("gorm:started_transaction"); ok {
		if db, ok := scope.db.db.(sqlTx); ok {
			if scope.HasError() {
				db.Rollback()
			} else {
				db.Commit()
			}
			scope.db.db = scope.db.parent.db
		}
	}
	return scope
}

func (scope *Scope) SelectAttrs() []string {
	if scope.selectAttrs == nil {
		attrs := []string{}
		for _, value := range scope.Search.selects {
			if str, ok := value.(string); ok {
				attrs = append(attrs, str)
			} else if strs, ok := value.([]string); ok {
				attrs = append(attrs, strs...)
			} else if strs, ok := value.([]interface{}); ok {
				for _, str := range strs {
					attrs = append(attrs, fmt.Sprintf("%v", str))
				}
			}
		}
		scope.selectAttrs = &attrs
	}
	return *scope.selectAttrs
}

func (scope *Scope) OmitAttrs() []string {
	return scope.Search.omits
}

func (scope *Scope) changeableDBColumn(column string) bool {
	selectAttrs := scope.SelectAttrs()
	omitAttrs := scope.OmitAttrs()

	if len(selectAttrs) > 0 {
		for _, attr := range selectAttrs {
			if column == ToDBName(attr) {
				return true
			}
		}
		return false
	}

	for _, attr := range omitAttrs {
		if column == ToDBName(attr) {
			return false
		}
	}
	return true
}

func (scope *Scope) changeableField(field *Field) bool {
	selectAttrs := scope.SelectAttrs()
	omitAttrs := scope.OmitAttrs()

	if len(selectAttrs) > 0 {
		for _, attr := range selectAttrs {
			if field.Name == attr || field.DBName == attr {
				return true
			}
		}
		return false
	}

	for _, attr := range omitAttrs {
		if field.Name == attr || field.DBName == attr {
			return false
		}
	}

	return !field.IsIgnored
}

func (scope *Scope) shouldSaveAssociations() bool {
	saveAssociations, ok := scope.Get("gorm:save_associations")
	if ok && !saveAssociations.(bool) {
		return false
	}
	return true
}
<commit_msg>Fix can't call callbacks for embedded pointers<commit_after>package gorm

import (
	"errors"
	"fmt"
	"regexp"
	"strings"
	"time"

	"reflect"
)

type Scope struct {
	Search          *search
	Value           interface{}
	Sql             string
	SqlVars         []interface{}
	db              *DB
	indirectValue   *reflect.Value
	instanceId      string
	primaryKeyField *Field
	skipLeft        bool
	fields          map[string]*Field
	selectAttrs     *[]string
}

func (scope *Scope) IndirectValue() reflect.Value {
	if scope.indirectValue == nil {
		value := reflect.Indirect(reflect.ValueOf(scope.Value))
		if value.Kind() == reflect.Ptr {
			value = value.Elem()
		}
		scope.indirectValue = &value
	}
	return *scope.indirectValue
}

func (scope *Scope) NeedPtr() *Scope {
	reflectKind := reflect.ValueOf(scope.Value).Kind()
	if !((reflectKind == reflect.Invalid) || (reflectKind == reflect.Ptr)) {
		err := fmt.Errorf("%v %v\n", fileWithLineNum(), "using unaddressable value")
		scope.Err(err)
		fmt.Printf(err.Error())
	}
	return scope
}

// New create a new Scope without search information
func (scope *Scope) New(value interface{}) *Scope {
	return &Scope{db: scope.NewDB(), Search: &search{}, Value: value}
}

// NewDB create a new DB without search information
func (scope *Scope) NewDB() *DB {
	if scope.db != nil {
		db := scope.db.clone()
		db.search = nil
		db.Value = nil
		return db
	}
	return nil
}

func (scope *Scope) DB() *DB {
	return scope.db
}

// SqlDB return *sql.DB
func (scope *Scope) SqlDB() sqlCommon {
	return scope.db.db
}

// SkipLeft skip remaining callbacks
func (scope *Scope) SkipLeft() {
	scope.skipLeft = true
}

// Quote used to quote database column name according to database dialect
func (scope *Scope) Quote(str string) string {
	if strings.Index(str, ".") != -1 {
		newStrs := []string{}
		for _, str := range strings.Split(str, ".") {
			newStrs = append(newStrs, scope.Dialect().Quote(str))
		}
		return strings.Join(newStrs, ".")
	} else {
		return scope.Dialect().Quote(str)
	}
}

func (scope *Scope) QuoteIfPossible(str string) string {
	if regexp.MustCompile("^[a-zA-Z]+(.[a-zA-Z]+)*$").MatchString(str) {
		return scope.Quote(str)
	}
	return str
}

// Dialect get dialect
func (scope *Scope) Dialect() Dialect {
	return scope.db.parent.dialect
}

// Err write error
func (scope *Scope) Err(err error) error {
	if err != nil {
		scope.db.err(err)
	}
	return err
}

// Log print log message
func (scope *Scope) Log(v ...interface{}) {
	scope.db.log(v...)
}

// HasError check if there are any error
func (scope *Scope) HasError() bool {
	return scope.db.Error != nil
}

func (scope *Scope) PrimaryFields() []*Field {
	var fields = []*Field{}
	for _, field := range scope.GetModelStruct().PrimaryFields {
		fields = append(fields, scope.Fields()[field.DBName])
	}
	return fields
}

func (scope *Scope) PrimaryField() *Field {
	if primaryFields := scope.GetModelStruct().PrimaryFields; len(primaryFields) > 0 {
		if len(primaryFields) > 1 {
			if field, ok := scope.Fields()["id"]; ok {
				return field
			}
		}
		return scope.Fields()[primaryFields[0].DBName]
	}
	return nil
}

// PrimaryKey get the primary key's column name
func (scope *Scope) PrimaryKey() string {
	if field := scope.PrimaryField(); field != nil {
		return field.DBName
	}
	return ""
}

// PrimaryKeyZero check the primary key is blank or not
func (scope *Scope) PrimaryKeyZero() bool {
	field := scope.PrimaryField()
	return field == nil || field.IsBlank
}

// PrimaryKeyValue get the primary key's value
func (scope *Scope) PrimaryKeyValue() interface{} {
	if field := scope.PrimaryField(); field != nil && field.Field.IsValid() {
		return field.Field.Interface()
	}
	return 0
}

// HasColumn to check if has column
func (scope *Scope) HasColumn(column string) bool {
	for _, field := range scope.GetStructFields() {
		if field.IsNormal && (field.Name == column || field.DBName == column) {
			return true
		}
	}
	return false
}

// SetColumn to set the column's value
func (scope *Scope) SetColumn(column interface{}, value interface{}) error {
	if field, ok := column.(*Field); ok {
		return field.Set(value)
	} else if name, ok := column.(string); ok {

		if field, ok := scope.Fields()[name]; ok {
			return field.Set(value)
		}

		dbName := ToDBName(name)
		if field, ok := scope.Fields()[dbName]; ok {
			return field.Set(value)
		}

		if field, ok := scope.FieldByName(name); ok {
			return field.Set(value)
		}
	}
	return errors.New("could not convert column to field")
}

func (scope *Scope) CallMethod(name string, checkError bool) {
	if scope.Value == nil || (checkError && scope.HasError()) {
		return
	}

	call := func(value interface{}) {
		if fm := reflect.ValueOf(value).MethodByName(name); fm.IsValid() {
			switch f := fm.Interface().(type) {
			case func():
				f()
			case func(s *Scope):
				f(scope)
			case func(s *DB):
				newDB := scope.NewDB()
				f(newDB)
				scope.Err(newDB.Error)
			case func() error:
				scope.Err(f())
			case func(s *Scope) error:
				scope.Err(f(scope))
			case func(s *DB) error:
				scope.Err(f(scope.NewDB()))
			default:
				scope.Err(fmt.Errorf("unsupported function %v", name))
			}
		}
	}

	if values := scope.IndirectValue(); values.Kind() == reflect.Slice {
		for i := 0; i < values.Len(); i++ {
			value := values.Index(i).Addr().Interface()
			if values.Index(i).Kind() == reflect.Ptr {
				value = values.Index(i).Interface()
			}
			call(value)
		}
	} else {
		if scope.IndirectValue().CanAddr() {
			call(scope.IndirectValue().Addr().Interface())
		} else {
			call(scope.IndirectValue().Interface())
		}
	}
}

func (scope *Scope) CallMethodWithErrorCheck(name string) {
	scope.CallMethod(name, true)
}

// AddToVars add value as sql's vars, gorm will escape them
func (scope *Scope) AddToVars(value interface{}) string {
	if expr, ok := value.(*expr); ok {
		exp := expr.expr
		for _, arg := range expr.args {
			exp = strings.Replace(exp, "?", scope.AddToVars(arg), 1)
		}
		return exp
	} else {
		scope.SqlVars = append(scope.SqlVars, value)
		return scope.Dialect().BinVar(len(scope.SqlVars))
	}
}

type tabler interface {
	TableName() string
}

type dbTabler interface {
	TableName(*DB) string
}

// TableName get table name
func (scope *Scope) TableName() string {
	if scope.Search != nil && len(scope.Search.tableName) > 0 {
		return scope.Search.tableName
	}

	if tabler, ok := scope.Value.(tabler); ok {
		return tabler.TableName()
	}

	if tabler, ok := scope.Value.(dbTabler); ok {
		return tabler.TableName(scope.db)
	}

	return scope.GetModelStruct().TableName(scope.db.Model(scope.Value))
}

func (scope *Scope) QuotedTableName() (name string) {
	if scope.Search != nil && len(scope.Search.tableName) > 0 {
		if strings.Index(scope.Search.tableName, " ") != -1 {
			return scope.Search.tableName
		}
		return scope.Quote(scope.Search.tableName)
	} else {
		return scope.Quote(scope.TableName())
	}
}

// CombinedConditionSql get combined condition sql
func (scope *Scope) CombinedConditionSql() string {
	return scope.joinsSql() + scope.whereSql() + scope.groupSql() +
		scope.havingSql() + scope.orderSql() + scope.limitSql() + scope.offsetSql()
}

func (scope *Scope) FieldByName(name string) (field *Field, ok bool) {
	for _, field := range scope.Fields() {
		if field.Name == name || field.DBName == name {
			return field, true
		}
	}
	return nil, false
}

// Raw set sql
func (scope *Scope) Raw(sql string) *Scope {
	scope.Sql = strings.Replace(sql, "$$", "?", -1)
	return scope
}

// Exec invoke sql
func (scope *Scope) Exec() *Scope {
	defer scope.Trace(NowFunc())

	if !scope.HasError() {
		if result, err := scope.SqlDB().Exec(scope.Sql, scope.SqlVars...); scope.Err(err) == nil {
			if count, err := result.RowsAffected(); scope.Err(err) == nil {
				scope.db.RowsAffected = count
			}
		}
	}
	return scope
}

// Set set value by name
func (scope *Scope) Set(name string, value interface{}) *Scope {
	scope.db.InstantSet(name, value)
	return scope
}

// Get get value by name
func (scope *Scope) Get(name string) (interface{}, bool) {
	return scope.db.Get(name)
}

// InstanceId get InstanceId for scope
func (scope *Scope) InstanceId() string {
	if scope.instanceId == "" {
		scope.instanceId = fmt.Sprintf("%v%v", &scope, &scope.db)
	}
	return scope.instanceId
}

func (scope *Scope) InstanceSet(name string, value interface{}) *Scope {
	return scope.Set(name+scope.InstanceId(), value)
}

func (scope *Scope) InstanceGet(name string) (interface{}, bool) {
	return scope.Get(name + scope.InstanceId())
}

// Trace print sql log
func (scope *Scope) Trace(t time.Time) {
	if len(scope.Sql) > 0 {
		scope.db.slog(scope.Sql, t, scope.SqlVars...)
	}
}

// Begin start a transaction
func (scope *Scope) Begin() *Scope {
	if db, ok := scope.SqlDB().(sqlDb); ok {
		if tx, err := db.Begin(); err == nil {
			scope.db.db = interface{}(tx).(sqlCommon)
			scope.InstanceSet("gorm:started_transaction", true)
		}
	}
	return scope
}

// CommitOrRollback commit current transaction if there is no error, otherwise rollback it
func (scope *Scope) CommitOrRollback() *Scope {
	if _, ok := scope.InstanceGet("gorm:started_transaction"); ok {
		if db, ok := scope.db.db.(sqlTx); ok {
			if scope.HasError() {
				db.Rollback()
			} else {
				db.Commit()
			}
			scope.db.db = scope.db.parent.db
		}
	}
	return scope
}

func (scope *Scope) SelectAttrs() []string {
	if scope.selectAttrs == nil {
		attrs := []string{}
		for _, value := range scope.Search.selects {
			if str, ok := value.(string); ok {
				attrs = append(attrs, str)
			} else if strs, ok := value.([]string); ok {
				attrs = append(attrs, strs...)
			} else if strs, ok := value.([]interface{}); ok {
				for _, str := range strs {
					attrs = append(attrs, fmt.Sprintf("%v", str))
				}
			}
		}
		scope.selectAttrs = &attrs
	}
	return *scope.selectAttrs
}

func (scope *Scope) OmitAttrs() []string {
	return scope.Search.omits
}

func (scope *Scope) changeableDBColumn(column string) bool {
	selectAttrs := scope.SelectAttrs()
	omitAttrs := scope.OmitAttrs()

	if len(selectAttrs) > 0 {
		for _, attr := range selectAttrs {
			if column == ToDBName(attr) {
				return true
			}
		}
		return false
	}

	for _, attr := range omitAttrs {
		if column == ToDBName(attr) {
			return false
		}
	}
	return true
}

func (scope *Scope) changeableField(field *Field) bool {
	selectAttrs := scope.SelectAttrs()
	omitAttrs := scope.OmitAttrs()

	if len(selectAttrs) > 0 {
		for _, attr := range selectAttrs {
			if field.Name == attr || field.DBName == attr {
				return true
			}
		}
		return false
	}

	for _, attr := range omitAttrs {
		if field.Name == attr || field.DBName == attr {
			return false
		}
	}

	return !field.IsIgnored
}

func (scope *Scope) shouldSaveAssociations() bool {
	saveAssociations, ok := scope.Get("gorm:save_associations")
	if ok && !saveAssociations.(bool) {
		return false
	}
	return true
}
<|endoftext|>


<commit_before>// Copyright 2015 The Chromium 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 logging

import (
	"flag"

	"golang.org/x/net/context"
)

// Config is a logging configuration structure.
type Config struct {
	Level  Level
	Filter Filter
}

// AddFlags adds common flags to a supplied FlagSet.
func (c *Config) AddFlags(fs *flag.FlagSet) {
	fs.Var(&c.Level, "log_level",
		"The logging level. Valid options are: debug, info, warning, error.")
	fs.Var(&c.Filter, "log_filter",
		"Log filter keywords. Can be specified multiple times.")
}

// Set installs a filter-aware logger that wraps the currently-installed Logger
// and selectively discards messages based on the logging configuration.
func (c *Config) Set(ctx context.Context) context.Context {
	filterFunc := c.Filter.Get()
	baseFactory := GetFactory(ctx)

	ctx = SetLevel(ctx, c.Level)
	return SetFactory(ctx, func(ctx context.Context) Logger {
		if value, ok := GetFields(ctx)[FilterOnKey]; ok {
			if !filterFunc(value) {
				return nil
			}
		}
		return baseFactory(ctx)
	})
}
<commit_msg>logging: fix panic on filter set<commit_after>// Copyright 2015 The Chromium 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 logging

import (
	"flag"

	"golang.org/x/net/context"
)

// Config is a logging configuration structure.
type Config struct {
	Level  Level
	Filter Filter
}

// AddFlags adds common flags to a supplied FlagSet.
func (c *Config) AddFlags(fs *flag.FlagSet) {
	fs.Var(&c.Level, "log_level",
		"The logging level. Valid options are: debug, info, warning, error.")
	fs.Var(&c.Filter, "log_filter",
		"Log filter keywords. Can be specified multiple times.")
}

// Set installs a filter-aware logger that wraps the currently-installed Logger
// and selectively discards messages based on the logging configuration.
func (c *Config) Set(ctx context.Context) context.Context {
	filterFunc := c.Filter.Get()
	baseFactory := GetFactory(ctx)

	ctx = SetLevel(ctx, c.Level)
	return SetFactory(ctx, func(ctx context.Context) Logger {
		if value, ok := GetFields(ctx)[FilterOnKey]; ok {
			if !filterFunc(value) {
				return Null()
			}
		}
		return baseFactory(ctx)
	})
}
<|endoftext|>


<commit_before>package humanlog

import (
	"bytes"
	"encoding/json"
	"fmt"
	"math"
	"sort"
	"strings"
	"text/tabwriter"
	"time"

	"github.com/fatih/color"
)

// JSONHandler can handle logs emmited by logrus.TextFormatter loggers.
type JSONHandler struct {
	buf     *bytes.Buffer
	out     *tabwriter.Writer
	truncKV int

	Opts *HandlerOptions

	Level   string
	Time    time.Time
	Message string
	Fields  map[string]string

	last map[string]string
}

func (h *JSONHandler) clear() {
	h.Level = ""
	h.Time = time.Time{}
	h.Message = ""
	h.last = h.Fields
	h.Fields = make(map[string]string)
	if h.buf != nil {
		h.buf.Reset()
	}
}

// TryHandle tells if this line was handled by this handler.
func (h *JSONHandler) TryHandle(d []byte) bool {
	if !bytes.Contains(d, []byte(`"time":`)) && !bytes.Contains(d, []byte(`"ts":`)) {
		return false
	}
	err := h.UnmarshalJSON(d)
	if err != nil {
		h.clear()
		return false
	}
	return true
}

// UnmarshalJSON sets the fields of the handler.
func (h *JSONHandler) UnmarshalJSON(data []byte) error {
	raw := make(map[string]interface{})
	err := json.Unmarshal(data, &raw)
	if err != nil {
		return err
	}

	time, ok := raw["time"]
	if ok {
		delete(raw, "time")
	} else {
		time, ok = raw["ts"]
		if ok {
			delete(raw, "ts")
		}
	}
	if ok {
		h.Time, ok = tryParseTime(time)
		if !ok {
			return fmt.Errorf("field time is not a known timestamp: %v", time)
		}
	}
	if h.Message, ok = raw["msg"].(string); ok {
		delete(raw, "msg")
	} else if h.Message, ok = raw["message"].(string); ok {
		delete(raw, "message")
	}

	h.Level, ok = raw["level"].(string)
	if !ok {
		h.Level, ok = raw["lvl"].(string)
		delete(raw, "lvl")
		if !ok {
			h.Level = "???"
		}
	} else {
		delete(raw, "level")
	}

	if h.Fields == nil {
		h.Fields = make(map[string]string)
	}

	for key, val := range raw {
		switch v := val.(type) {
		case float64:
			if v-math.Floor(v) < 0.000001 && v < 1e9 {
				// looks like an integer that's not too large
				h.Fields[key] = fmt.Sprintf("%d", int(v))
			} else {
				h.Fields[key] = fmt.Sprintf("%g", v)
			}
		case string:
			h.Fields[key] = fmt.Sprintf("%q", v)
		default:
			h.Fields[key] = fmt.Sprintf("%v", v)
		}
	}

	return nil
}

// Prettify the output in a logrus like fashion.
func (h *JSONHandler) Prettify(skipUnchanged bool) []byte {
	defer h.clear()
	if h.out == nil {
		if h.Opts == nil {
			h.Opts = DefaultOptions
		}
		h.buf = bytes.NewBuffer(nil)
		h.out = tabwriter.NewWriter(h.buf, 0, 1, 0, '\t', 0)
	}

	var (
		msgColor       *color.Color
		msgAbsentColor *color.Color
	)
	if h.Opts.LightBg {
		msgColor = h.Opts.MsgLightBgColor
		msgAbsentColor = h.Opts.MsgAbsentLightBgColor
	} else {
		msgColor = h.Opts.MsgDarkBgColor
		msgAbsentColor = h.Opts.MsgAbsentDarkBgColor
	}
	msgColor = color.New(color.FgHiWhite)
	msgAbsentColor = color.New(color.FgHiWhite)

	var msg string
	if h.Message == "" {
		msg = msgAbsentColor.Sprint("<no msg>")
	} else {
		msg = msgColor.Sprint(h.Message)
	}

	lvl := strings.ToUpper(h.Level)[:imin(4, len(h.Level))]
	var level string
	switch h.Level {
	case "debug":
		level = h.Opts.DebugLevelColor.Sprint(lvl)
	case "info":
		level = h.Opts.InfoLevelColor.Sprint(lvl)
	case "warn", "warning":
		level = h.Opts.WarnLevelColor.Sprint(lvl)
	case "error":
		level = h.Opts.ErrorLevelColor.Sprint(lvl)
	case "fatal", "panic":
		level = h.Opts.FatalLevelColor.Sprint(lvl)
	default:
		level = h.Opts.UnknownLevelColor.Sprint(lvl)
	}

	var timeColor *color.Color
	if h.Opts.LightBg {
		timeColor = h.Opts.TimeLightBgColor
	} else {
		timeColor = h.Opts.TimeDarkBgColor
	}
	_, _ = fmt.Fprintf(h.out, "%s |%s| %s\t %s",
		timeColor.Sprint(h.Time.Format(h.Opts.TimeFormat)),
		level,
		msg,
		strings.Join(h.joinKVs(skipUnchanged, "="), "\t "),
	)

	_ = h.out.Flush()

	return h.buf.Bytes()
}

func (h *JSONHandler) joinKVs(skipUnchanged bool, sep string) []string {

	kv := make([]string, 0, len(h.Fields))
	for k, v := range h.Fields {
		if !h.Opts.shouldShowKey(k) {
			continue
		}

		if skipUnchanged {
			if lastV, ok := h.last[k]; ok && lastV == v && !h.Opts.shouldShowUnchanged(k) {
				continue
			}
		}
		kstr := h.Opts.KeyColor.Sprint(k)

		var vstr string
		if h.Opts.Truncates && len(v) > h.Opts.TruncateLength {
			vstr = v[:h.Opts.TruncateLength] + "..."
		} else {
			vstr = v
		}
		vstr = h.Opts.ValColor.Sprint(vstr)
		kv = append(kv, kstr+sep+vstr)
	}

	sort.Strings(kv)

	if h.Opts.SortLongest {
		sort.Stable(byLongest(kv))
	}

	return kv
}
<commit_msg>add support for bunyan and logstash JSON formats<commit_after>package humanlog

import (
	"bytes"
	"encoding/json"
	"fmt"
	"math"
	"sort"
	"strings"
	"text/tabwriter"
	"time"

	"github.com/fatih/color"
)

// JSONHandler can handle logs emmited by logrus.TextFormatter loggers.
type JSONHandler struct {
	buf     *bytes.Buffer
	out     *tabwriter.Writer
	truncKV int

	Opts *HandlerOptions

	Level   string
	Time    time.Time
	Message string
	Fields  map[string]string

	last map[string]string
}

// supportedTimeFields enumerates supported timestamp field names
var supportedTimeFields = []string{"time", "ts", "@timestamp"}

func (h *JSONHandler) clear() {
	h.Level = ""
	h.Time = time.Time{}
	h.Message = ""
	h.last = h.Fields
	h.Fields = make(map[string]string)
	if h.buf != nil {
		h.buf.Reset()
	}
}

// TryHandle tells if this line was handled by this handler.
func (h *JSONHandler) TryHandle(d []byte) bool {
	var ok bool

	for _, field := range supportedTimeFields {
		ok = bytes.Contains(d, []byte(`"`+field+`":`))
		if ok {
			break
		}
	}

	if !ok {
		return false
	}

	err := h.UnmarshalJSON(d)
	if err != nil {
		h.clear()
		return false
	}
	return true
}

// UnmarshalJSON sets the fields of the handler.
func (h *JSONHandler) UnmarshalJSON(data []byte) error {
	raw := make(map[string]interface{})
	err := json.Unmarshal(data, &raw)
	if err != nil {
		return err
	}

	var time interface{}
	var ok bool

	for _, field := range supportedTimeFields {
		time, ok = raw[field]
		if ok {
			delete(raw, field)
			break
		}
	}

	if ok {
		h.Time, ok = tryParseTime(time)
		if !ok {
			return fmt.Errorf("field time is not a known timestamp: %v", time)
		}
	}

	if h.Message, ok = raw["msg"].(string); ok {
		delete(raw, "msg")
	} else if h.Message, ok = raw["message"].(string); ok {
		delete(raw, "message")
	}

	h.Level, ok = raw["level"].(string)
	if !ok {
		h.Level, ok = raw["lvl"].(string)
		delete(raw, "lvl")
		if !ok {
			// bunyan uses numerical log levels
			level, ok := raw["level"].(float64)
			if ok {
				h.Level = convertBunyanLogLevel(level)
				delete(raw, "level")
			} else {
				h.Level = "???"
			}
		}
	}

	if h.Fields == nil {
		h.Fields = make(map[string]string)
	}

	for key, val := range raw {
		switch v := val.(type) {
		case float64:
			if v-math.Floor(v) < 0.000001 && v < 1e9 {
				// looks like an integer that's not too large
				h.Fields[key] = fmt.Sprintf("%d", int(v))
			} else {
				h.Fields[key] = fmt.Sprintf("%g", v)
			}
		case string:
			h.Fields[key] = fmt.Sprintf("%q", v)
		default:
			h.Fields[key] = fmt.Sprintf("%v", v)
		}
	}

	return nil
}

// Prettify the output in a logrus like fashion.
func (h *JSONHandler) Prettify(skipUnchanged bool) []byte {
	defer h.clear()
	if h.out == nil {
		if h.Opts == nil {
			h.Opts = DefaultOptions
		}
		h.buf = bytes.NewBuffer(nil)
		h.out = tabwriter.NewWriter(h.buf, 0, 1, 0, '\t', 0)
	}

	var (
		msgColor       *color.Color
		msgAbsentColor *color.Color
	)
	if h.Opts.LightBg {
		msgColor = h.Opts.MsgLightBgColor
		msgAbsentColor = h.Opts.MsgAbsentLightBgColor
	} else {
		msgColor = h.Opts.MsgDarkBgColor
		msgAbsentColor = h.Opts.MsgAbsentDarkBgColor
	}
	msgColor = color.New(color.FgHiWhite)
	msgAbsentColor = color.New(color.FgHiWhite)

	var msg string
	if h.Message == "" {
		msg = msgAbsentColor.Sprint("<no msg>")
	} else {
		msg = msgColor.Sprint(h.Message)
	}

	lvl := strings.ToUpper(h.Level)[:imin(4, len(h.Level))]
	var level string
	switch h.Level {
	case "debug":
		level = h.Opts.DebugLevelColor.Sprint(lvl)
	case "info":
		level = h.Opts.InfoLevelColor.Sprint(lvl)
	case "warn", "warning":
		level = h.Opts.WarnLevelColor.Sprint(lvl)
	case "error":
		level = h.Opts.ErrorLevelColor.Sprint(lvl)
	case "fatal", "panic":
		level = h.Opts.FatalLevelColor.Sprint(lvl)
	default:
		level = h.Opts.UnknownLevelColor.Sprint(lvl)
	}

	var timeColor *color.Color
	if h.Opts.LightBg {
		timeColor = h.Opts.TimeLightBgColor
	} else {
		timeColor = h.Opts.TimeDarkBgColor
	}
	_, _ = fmt.Fprintf(h.out, "%s |%s| %s\t %s",
		timeColor.Sprint(h.Time.Format(h.Opts.TimeFormat)),
		level,
		msg,
		strings.Join(h.joinKVs(skipUnchanged, "="), "\t "),
	)

	_ = h.out.Flush()

	return h.buf.Bytes()
}

func (h *JSONHandler) joinKVs(skipUnchanged bool, sep string) []string {

	kv := make([]string, 0, len(h.Fields))
	for k, v := range h.Fields {
		if !h.Opts.shouldShowKey(k) {
			continue
		}

		if skipUnchanged {
			if lastV, ok := h.last[k]; ok && lastV == v && !h.Opts.shouldShowUnchanged(k) {
				continue
			}
		}
		kstr := h.Opts.KeyColor.Sprint(k)

		var vstr string
		if h.Opts.Truncates && len(v) > h.Opts.TruncateLength {
			vstr = v[:h.Opts.TruncateLength] + "..."
		} else {
			vstr = v
		}
		vstr = h.Opts.ValColor.Sprint(vstr)
		kv = append(kv, kstr+sep+vstr)
	}

	sort.Strings(kv)

	if h.Opts.SortLongest {
		sort.Stable(byLongest(kv))
	}

	return kv
}

// convertBunyanLogLevel returns a human readable log level given a numerical bunyan level
// https://github.com/trentm/node-bunyan#levels
func convertBunyanLogLevel(level float64) string {
	switch level {
	case 10:
		return "trace"
	case 20:
		return "debug"
	case 30:
		return "info"
	case 40:
		return "warn"
	case 50:
		return "error"
	case 60:
		return "fatal"
	default:
		return "???"
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"sync"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"
	keybase1 "github.com/keybase/client/protocol/go"
	"github.com/keybase/kbfs/libkbfs"
	"golang.org/x/net/context"
)

type Folder struct {
	fs *FS
	id libkbfs.DirId
	dh *libkbfs.DirHandle

	// Protects all Dir.pathNode and File.pathNode instances.
	mu sync.RWMutex
}

type Dir struct {
	fs.NodeRef

	folder   *Folder
	parent   *Dir
	pathNode libkbfs.PathNode
}

var _ fs.Node = (*Dir)(nil)

func (d *Dir) Attr(a *fuse.Attr) {
	a.Mode = os.ModeDir | 0700
	if d.folder.id.IsPublic() || d.folder.dh.IsPublic() {
		a.Mode |= 0055
	}
}

// getPath returns the Path for the current directory.
//
// Caller is responsible for locking.
func (d *Dir) getPathLocked() libkbfs.Path {
	p := libkbfs.Path{
		TopDir: d.folder.id,
	}
	for cur := d; cur != nil; cur = cur.parent {
		p.Path = append(p.Path, cur.pathNode)
	}
	// reverse
	for i := len(p.Path)/2 - 1; i >= 0; i-- {
		opp := len(p.Path) - 1 - i
		p.Path[i], p.Path[opp] = p.Path[opp], p.Path[i]
	}
	return p
}

// Update the PathNode stored here, and in parents.
//
// Caller is responsible for locking.
func (d *Dir) updatePathLocked(p libkbfs.Path) {
	for dir, path := d, p.Path; dir != nil; dir, path = dir.parent, path[:len(path)-1] {
		pNode := path[len(path)-1]
		if dir.pathNode.Name != pNode.Name {
			break
		}
		dir.pathNode = pNode
	}
}

var _ fs.NodeRequestLookuper = (*Dir)(nil)

func (d *Dir) Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.LookupResponse) (fs.Node, error) {
	d.folder.mu.RLock()
	defer d.folder.mu.RUnlock()

	p := d.getPathLocked()

	if req.Name == libkbfs.PublicName &&
		p.HasPublic() &&
		d.folder.dh.HasPublic() {
		dhPub := &libkbfs.DirHandle{
			Writers: d.folder.dh.Writers,
			Readers: []keybase1.UID{keybase1.PublicUID},
		}
		md, err := d.folder.fs.config.KBFSOps().GetRootMDForHandle(dhPub)
		if err != nil {
			return nil, err
		}
		pubFolder := &Folder{
			id: md.Id,
			dh: dhPub,
		}
		child := &Dir{
			folder: pubFolder,
			pathNode: libkbfs.PathNode{
				BlockPointer: md.Data().Dir.BlockPointer,
				Name:         req.Name,
			},
		}
		return child, nil
	}

	dirBlock, err := d.folder.fs.config.KBFSOps().GetDir(p)
	if err != nil {
		return nil, err
	}
	de, ok := dirBlock.Children[req.Name]
	if !ok {
		return nil, fuse.ENOENT
	}

	switch de.Type {
	default:
		return nil, fmt.Errorf("unhandled entry type: %v", de.Type)

	case libkbfs.File, libkbfs.Exec:
		child := &File{
			parent: d,
			de:     de,
			pathNode: libkbfs.PathNode{
				BlockPointer: de.BlockPointer,
				Name:         req.Name,
			},
			exec: de.Type == libkbfs.Exec,
		}
		return child, nil

	case libkbfs.Dir:
		child := &Dir{
			folder: d.folder,
			parent: d,
			pathNode: libkbfs.PathNode{
				BlockPointer: de.BlockPointer,
				Name:         req.Name,
			},
		}
		return child, nil

	case libkbfs.Sym:
		child := &Symlink{
			parent: d,
			de:     de,
			pathNode: libkbfs.PathNode{
				// use a null block pointer for symlinks
				Name: req.Name,
			},
		}
		return child, nil
	}
}

var _ fs.NodeCreater = (*Dir)(nil)

func (d *Dir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) {
	d.folder.mu.Lock()
	defer d.folder.mu.Unlock()

	isExec := (req.Mode.Perm() & 0100) != 0
	p, de, err := d.folder.fs.config.KBFSOps().CreateFile(d.getPathLocked(), req.Name, isExec)
	if err != nil {
		return nil, nil, err
	}
	d.updatePathLocked(p)
	// TODO update mtime, ctime, size?

	child := &File{
		parent: d,
		de:     de,
		pathNode: libkbfs.PathNode{
			BlockPointer: de.BlockPointer,
			Name:         req.Name,
		},
		exec: isExec,
	}
	return child, child, nil
}

var _ fs.NodeMkdirer = (*Dir)(nil)

func (d *Dir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) {
	d.folder.mu.Lock()
	defer d.folder.mu.Unlock()

	p, de, err := d.folder.fs.config.KBFSOps().CreateDir(d.getPathLocked(), req.Name)
	if err != nil {
		return nil, err
	}
	d.updatePathLocked(p)
	// TODO update mtime, ctime, size?

	child := &Dir{
		folder: d.folder,
		parent: d,
		pathNode: libkbfs.PathNode{
			BlockPointer: de.BlockPointer,
			Name:         req.Name,
		},
	}
	return child, nil
}

var _ fs.NodeSymlinker = (*Dir)(nil)

func (d *Dir) Symlink(ctx context.Context, req *fuse.SymlinkRequest) (fs.Node, error) {
	d.folder.mu.Lock()
	defer d.folder.mu.Unlock()

	p, de, err := d.folder.fs.config.KBFSOps().CreateLink(d.getPathLocked(), req.NewName, req.Target)
	if err != nil {
		return nil, err
	}
	d.updatePathLocked(p)
	// TODO update mtime, ctime, size?

	child := &Symlink{
		parent: d,
		de:     de,
		pathNode: libkbfs.PathNode{
			// use a null block pointer for symlinks
			Name: req.NewName,
		},
	}
	return child, nil
}

var _ fs.Handle = (*Dir)(nil)

var _ fs.HandleReadDirAller = (*Dir)(nil)

func (d *Dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
	dirBlock, err := d.folder.fs.config.KBFSOps().GetDir(d.getPathLocked())
	if err != nil {
		return nil, err
	}

	var res []fuse.Dirent
	for name, de := range dirBlock.Children {
		fde := fuse.Dirent{
			Name: name,
		}
		switch de.Type {
		case libkbfs.File, libkbfs.Exec:
			fde.Type = fuse.DT_File
		case libkbfs.Dir:
			fde.Type = fuse.DT_Dir
		case libkbfs.Sym:
			fde.Type = fuse.DT_Link
		}
		res = append(res, fde)
	}
	return res, nil
}
<commit_msg>FUSE: Fix misunderstanding of KBFSOps.CreateFile/CreateDir return value<commit_after>package main

import (
	"fmt"
	"os"
	"sync"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"
	keybase1 "github.com/keybase/client/protocol/go"
	"github.com/keybase/kbfs/libkbfs"
	"golang.org/x/net/context"
)

type Folder struct {
	fs *FS
	id libkbfs.DirId
	dh *libkbfs.DirHandle

	// Protects all Dir.pathNode and File.pathNode instances.
	mu sync.RWMutex
}

type Dir struct {
	fs.NodeRef

	folder   *Folder
	parent   *Dir
	pathNode libkbfs.PathNode
}

var _ fs.Node = (*Dir)(nil)

func (d *Dir) Attr(a *fuse.Attr) {
	a.Mode = os.ModeDir | 0700
	if d.folder.id.IsPublic() || d.folder.dh.IsPublic() {
		a.Mode |= 0055
	}
}

// getPath returns the Path for the current directory.
//
// Caller is responsible for locking.
func (d *Dir) getPathLocked() libkbfs.Path {
	p := libkbfs.Path{
		TopDir: d.folder.id,
	}
	for cur := d; cur != nil; cur = cur.parent {
		p.Path = append(p.Path, cur.pathNode)
	}
	// reverse
	for i := len(p.Path)/2 - 1; i >= 0; i-- {
		opp := len(p.Path) - 1 - i
		p.Path[i], p.Path[opp] = p.Path[opp], p.Path[i]
	}
	return p
}

// Update the PathNode stored here, and in parents.
//
// Caller is responsible for locking.
func (d *Dir) updatePathLocked(p libkbfs.Path) {
	for dir, path := d, p.Path; dir != nil; dir, path = dir.parent, path[:len(path)-1] {
		pNode := path[len(path)-1]
		if dir.pathNode.Name != pNode.Name {
			break
		}
		dir.pathNode = pNode
	}
}

var _ fs.NodeRequestLookuper = (*Dir)(nil)

func (d *Dir) Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.LookupResponse) (fs.Node, error) {
	d.folder.mu.RLock()
	defer d.folder.mu.RUnlock()

	p := d.getPathLocked()

	if req.Name == libkbfs.PublicName &&
		p.HasPublic() &&
		d.folder.dh.HasPublic() {
		dhPub := &libkbfs.DirHandle{
			Writers: d.folder.dh.Writers,
			Readers: []keybase1.UID{keybase1.PublicUID},
		}
		md, err := d.folder.fs.config.KBFSOps().GetRootMDForHandle(dhPub)
		if err != nil {
			return nil, err
		}
		pubFolder := &Folder{
			id: md.Id,
			dh: dhPub,
		}
		child := &Dir{
			folder: pubFolder,
			pathNode: libkbfs.PathNode{
				BlockPointer: md.Data().Dir.BlockPointer,
				Name:         req.Name,
			},
		}
		return child, nil
	}

	dirBlock, err := d.folder.fs.config.KBFSOps().GetDir(p)
	if err != nil {
		return nil, err
	}
	de, ok := dirBlock.Children[req.Name]
	if !ok {
		return nil, fuse.ENOENT
	}

	switch de.Type {
	default:
		return nil, fmt.Errorf("unhandled entry type: %v", de.Type)

	case libkbfs.File, libkbfs.Exec:
		child := &File{
			parent: d,
			de:     de,
			pathNode: libkbfs.PathNode{
				BlockPointer: de.BlockPointer,
				Name:         req.Name,
			},
			exec: de.Type == libkbfs.Exec,
		}
		return child, nil

	case libkbfs.Dir:
		child := &Dir{
			folder: d.folder,
			parent: d,
			pathNode: libkbfs.PathNode{
				BlockPointer: de.BlockPointer,
				Name:         req.Name,
			},
		}
		return child, nil

	case libkbfs.Sym:
		child := &Symlink{
			parent: d,
			de:     de,
			pathNode: libkbfs.PathNode{
				// use a null block pointer for symlinks
				Name: req.Name,
			},
		}
		return child, nil
	}
}

var _ fs.NodeCreater = (*Dir)(nil)

func (d *Dir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) {
	d.folder.mu.Lock()
	defer d.folder.mu.Unlock()

	isExec := (req.Mode.Perm() & 0100) != 0
	pChild, de, err := d.folder.fs.config.KBFSOps().CreateFile(d.getPathLocked(), req.Name, isExec)
	if err != nil {
		return nil, nil, err
	}
	d.updatePathLocked(*pChild.ParentPath())
	// TODO update mtime, ctime, size?

	child := &File{
		parent: d,
		de:     de,
		pathNode: libkbfs.PathNode{
			BlockPointer: de.BlockPointer,
			Name:         req.Name,
		},
		exec: isExec,
	}
	return child, child, nil
}

var _ fs.NodeMkdirer = (*Dir)(nil)

func (d *Dir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) {
	d.folder.mu.Lock()
	defer d.folder.mu.Unlock()

	pChild, de, err := d.folder.fs.config.KBFSOps().CreateDir(d.getPathLocked(), req.Name)
	if err != nil {
		return nil, err
	}
	d.updatePathLocked(*pChild.ParentPath())
	// TODO update mtime, ctime, size?

	child := &Dir{
		folder: d.folder,
		parent: d,
		pathNode: libkbfs.PathNode{
			BlockPointer: de.BlockPointer,
			Name:         req.Name,
		},
	}
	return child, nil
}

var _ fs.NodeSymlinker = (*Dir)(nil)

func (d *Dir) Symlink(ctx context.Context, req *fuse.SymlinkRequest) (fs.Node, error) {
	d.folder.mu.Lock()
	defer d.folder.mu.Unlock()

	p, de, err := d.folder.fs.config.KBFSOps().CreateLink(d.getPathLocked(), req.NewName, req.Target)
	if err != nil {
		return nil, err
	}
	d.updatePathLocked(p)
	// TODO update mtime, ctime, size?

	child := &Symlink{
		parent: d,
		de:     de,
		pathNode: libkbfs.PathNode{
			// use a null block pointer for symlinks
			Name: req.NewName,
		},
	}
	return child, nil
}

var _ fs.Handle = (*Dir)(nil)

var _ fs.HandleReadDirAller = (*Dir)(nil)

func (d *Dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
	dirBlock, err := d.folder.fs.config.KBFSOps().GetDir(d.getPathLocked())
	if err != nil {
		return nil, err
	}

	var res []fuse.Dirent
	for name, de := range dirBlock.Children {
		fde := fuse.Dirent{
			Name: name,
		}
		switch de.Type {
		case libkbfs.File, libkbfs.Exec:
			fde.Type = fuse.DT_File
		case libkbfs.Dir:
			fde.Type = fuse.DT_Dir
		case libkbfs.Sym:
			fde.Type = fuse.DT_Link
		}
		res = append(res, fde)
	}
	return res, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"

	"github.com/jung-kurt/gofpdf"
)

const version = "0.1.0-dev"

type KeyInformation struct {
	x      float64
	y      float64
	width  float64
	height float64

	use bool
}

type Scan struct {
	line        int
	lineHead    int
	inKeymaps   bool
	layerNumber int
	keys        [3][]string
	m           map[string]string
}

func (self *Scan) Init() {
	self.line = 1
	self.lineHead = 0
	self.inKeymaps = false
	self.layerNumber = 0
	self.m = map[string]string{"KC_EQL": "=",
		"KC_DELT": "Del", "KC_BSPC": "BkSp",
		"KC_TRNS": "", "KC_ENT": "Enter", "KC_1": "1",
		"KC_2": "2", "KC_3": "3", "KC_4": "4", "KC_5": "5", "KC_6": "7",
		"KC_7": "7", "KC_8": "8", "KC_9": "9", "KC_0": "0",
		"KC_A": "A", "KC_B": "B", "KC_C": "C", "KC_D": "D",
		"KC_E": "E", "KC_F": "F", "KC_G": "G", "KC_H": "H",
		"KC_I": "I", "KC_J": "J", "KC_K": "K", "KC_L": "L",
		"KC_M": "M", "KC_N": "N", "KC_O": "O", "KC_P": "P",
		"KC_Q": "Q", "KC_R": "R", "KC_S": "S", "KC_T": "T",
		"KC_U": "U", "KC_V": "V", "KC_W": "W", "KC_X": "X",
		"KC_Y": "Y", "KC_Z": "Z",
		"KC_EXLM": "!", "KC_AT": "@", "KC_LCBR": "{", "KC_RCBR": "}", "KC_PIPE": "|",
		"KC_HASH": "#", "KC_DLR": "$", "KC_LPRN": "(", "KC_RPRN": ")", "KC_GRV": "`",
		"KC_PERC": "%", "KC_CIRC": "^", "KC_LBRC": "[", "KC_RBRC": "]", "KC_TILD": "~",
		"KC_PLUS": "+", "KC_ASTR": "*", "KC_DOT": ".", "KC_AMPR": "&",
		"KC_MINS": "-", "KC_BSLS": "\\", "KC_RSFT": "RShift",
		"KC_MUTE": "Mute", "RGB_HUD": "Hue-", "RGB_HUI": "Hue+",
		"KC_F1": "F1", "KC_F2": "F2", "KC_F3": "F3", "KC_F4": "F4",
		"KC_F5": "F5", "KC_F6": "F6", "KC_F7": "F7", "KC_F8": "F8",
		"KC_F9": "F9", "KC_F10": "F10", "KC_F11": "F11", "KC_F12": "F12",
		"KC_UP": "UP", "KC_DOWN": "DOWN", "KC_LEFT": "LEFT", "KC_RGHT": "RIGHT",
		"KC_MS_U": "MsUp", "KC_MS_D": "MsDown", "KC_MS_L": "MsLeft", "KC_MS_R": "MsRght",
		"KC_BTN1": "Lclk", "KC_BTN2": "Rclk",
		"RGB_TOG": "Toggle", "RGB_SLD": "Solid",
		"RGB_VAD": "Brightness-", "RGB_VAI": "Brightness+", "RGB_MOD": "Animat",
		"KC_LSFT": "LShift", "KC_SPC": "SPC",
		"KC_VOLU": "VolUp", "KC_VOLD": "VolDn", "KC_MPRV": "Prev", "KC_MNXT": "Next",
		"KC_HOME": "Home", "KC_END": "End", "KC_PGUP": "PgUp", "KC_PGDN": "PgDn",
		"KC_MPLY": "Play", "KC_TAB": "Tab",
		"KC_WBAK": "BrowserBack"}
}

func (self *Scan) Err(s int) {
	fmt.Printf("\n!!Error!!%d\n", s)
}

func (self *Scan) GetDisplayName(key string) string {
	_, ok := self.m[key]
	if ok {
		return self.m[key]
	} else {
		return key
	}
}
func (self *Scan) Output() {
	pdf := gofpdf.New("P", "mm", "A4", "")
	pdf.SetFont("Arial", "", 10)
	pdf.AddPage()

	curx, cury := pdf.GetXY()
	x := curx
	y := cury
	_, lineHt := pdf.GetFontSize()

	//
	cols := [14]float64{0, 0, -0.25, -0.375, -0.25, 0, 0,
		0, 0, -0.25, -0.375, -0.25, 0, 0}
	var lkil []KeyInformation
	var rkil []KeyInformation
	for j := 0; j < 8; j++ {
		for i := 0; i < 7; i++ {
			var ltmp = KeyInformation{x: float64(i * 10), y: float64(j * 10), width: float64(10), height: float64(10), use: true}
			var rtmp = KeyInformation{x: float64((i + 13) * 10), y: float64(j * 10), width: float64(10), height: float64(10), use: true}
			if j < 6 {
				ltmp.y = ltmp.y + cols[i]*10
				rtmp.y = rtmp.y + cols[i+7]*10
			}
			if i == 0 {
				ltmp.x = ltmp.x - 5
				ltmp.width = 15
			}
			if i == 6 {
				rtmp.width = 15
			}
			lkil = append(lkil, ltmp)
			rkil = append(rkil, rtmp)
		}
	}
	//
	lkil[20].use = false
	rkil[14].use = false
	lkil[33].use = false
	rkil[29].use = false
	lkil[34].use = false
	rkil[28].use = false
	//
	for j := 5; j < 8; j++ {
		for i := 0; i < 4; i++ {
			lkil[j*7+i].use = false
			rkil[j*7+(6-i)].use = false
		}
	}
	//
	lkil[39].use = false
	rkil[37].use = false
	lkil[46].use = false
	rkil[44].use = false
	lkil[47].use = false
	rkil[43].use = false
	//
	lkil[53].height = float64(20)
	lkil[53].y = lkil[53].y - 10
	rkil[51].height = float64(20)
	rkil[51].y = lkil[51].y - 10
	lkil[54].height = float64(20)
	lkil[54].y = lkil[54].y - 10
	rkil[50].height = float64(20)
	rkil[50].y = lkil[50].y - 10
	//
	lkil[13].height = float64(15)
	rkil[7].height = float64(15)
	lkil[27].height = float64(15)
	rkil[21].height = float64(15)
	lkil[27].y = lkil[27].y - 5
	rkil[21].y = rkil[21].y - 5
	//
	lkil[28].x = lkil[28].x + 5
	lkil[28].width = 10
	rkil[34].width = 10
	// right

	for k := 0; k < 3; k++ {
		var keyindex int = 0
		for j := 0; j < 8; j++ {
			for i := 0; i < 7; i++ {
				var ki = lkil[j*7+i]
				if ki.use {
					if j > 4 {
						pdf.TransformBegin()
						pdf.TransformRotate(-30, 97, 97+90*float64(k))
					}
					pdf.Rect(curx+ki.x, cury+float64(k*90)+ki.y, ki.width, ki.height, "")
					pdf.SetXY(curx+ki.x, cury+float64(k*90)+ki.y)
					pdf.Cell(0, 0+lineHt, self.GetDisplayName(self.keys[k][keyindex]))
					keyindex = keyindex + 1
					if j > 4 {
						pdf.TransformEnd()
					}
				}
			}
		}
		for j := 0; j < 8; j++ {
			for i := 0; i < 7; i++ {
				var ki = rkil[j*7+i]
				if ki.use {
					if j > 4 {
						pdf.TransformBegin()
						pdf.TransformRotate(30, 113, 97+90*float64(k))
					}
					pdf.Rect(ki.x, cury+float64(k*90)+ki.y, ki.width, ki.height, "")
					pdf.SetXY(ki.x, cury+float64(k*90)+ki.y)
					pdf.Cell(0, 0+lineHt, self.GetDisplayName(self.keys[k][keyindex]))
					keyindex = keyindex + 1
					if j > 4 {
						pdf.TransformEnd()
					}
					x += 10
				}
			}
			y = y + 10
			x = curx
		}
		y = y + 20
	}
	pdf.Output(os.Stdout)
}

func main() {
	if len(os.Args) < 2 {
		fmt.Printf("%v FILE\n", os.Args[0])
		os.Exit(1)
	}
	file, err := os.Open(os.Args[1])
	if err != nil {
		log.Fatal(err)
	}

	buffer, err := ioutil.ReadAll(file)
	if err != nil {
		log.Fatal(err)
	}

	file.Close()

	parser := &Parser{Buffer: string(buffer)}
	parser.Init()
	parser.s.Init()
	err2 := parser.Parse()

	if err2 != nil {
		fmt.Println(err2)
	} else {
		parser.Execute()
		parser.s.Output()
	}
}
<commit_msg>prepare next release<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"

	"github.com/jung-kurt/gofpdf"
)

const version = "0.2.0-dev"

type KeyInformation struct {
	x      float64
	y      float64
	width  float64
	height float64

	use bool
}

type Scan struct {
	line        int
	lineHead    int
	inKeymaps   bool
	layerNumber int
	keys        [3][]string
	m           map[string]string
}

func (self *Scan) Init() {
	self.line = 1
	self.lineHead = 0
	self.inKeymaps = false
	self.layerNumber = 0
	self.m = map[string]string{"KC_EQL": "=",
		"KC_DELT": "Del", "KC_BSPC": "BkSp",
		"KC_TRNS": "", "KC_ENT": "Enter", "KC_1": "1",
		"KC_2": "2", "KC_3": "3", "KC_4": "4", "KC_5": "5", "KC_6": "7",
		"KC_7": "7", "KC_8": "8", "KC_9": "9", "KC_0": "0",
		"KC_A": "A", "KC_B": "B", "KC_C": "C", "KC_D": "D",
		"KC_E": "E", "KC_F": "F", "KC_G": "G", "KC_H": "H",
		"KC_I": "I", "KC_J": "J", "KC_K": "K", "KC_L": "L",
		"KC_M": "M", "KC_N": "N", "KC_O": "O", "KC_P": "P",
		"KC_Q": "Q", "KC_R": "R", "KC_S": "S", "KC_T": "T",
		"KC_U": "U", "KC_V": "V", "KC_W": "W", "KC_X": "X",
		"KC_Y": "Y", "KC_Z": "Z",
		"KC_EXLM": "!", "KC_AT": "@", "KC_LCBR": "{", "KC_RCBR": "}", "KC_PIPE": "|",
		"KC_HASH": "#", "KC_DLR": "$", "KC_LPRN": "(", "KC_RPRN": ")", "KC_GRV": "`",
		"KC_PERC": "%", "KC_CIRC": "^", "KC_LBRC": "[", "KC_RBRC": "]", "KC_TILD": "~",
		"KC_PLUS": "+", "KC_ASTR": "*", "KC_DOT": ".", "KC_AMPR": "&",
		"KC_MINS": "-", "KC_BSLS": "\\", "KC_RSFT": "RShift",
		"KC_MUTE": "Mute", "RGB_HUD": "Hue-", "RGB_HUI": "Hue+",
		"KC_F1": "F1", "KC_F2": "F2", "KC_F3": "F3", "KC_F4": "F4",
		"KC_F5": "F5", "KC_F6": "F6", "KC_F7": "F7", "KC_F8": "F8",
		"KC_F9": "F9", "KC_F10": "F10", "KC_F11": "F11", "KC_F12": "F12",
		"KC_UP": "UP", "KC_DOWN": "DOWN", "KC_LEFT": "LEFT", "KC_RGHT": "RIGHT",
		"KC_MS_U": "MsUp", "KC_MS_D": "MsDown", "KC_MS_L": "MsLeft", "KC_MS_R": "MsRght",
		"KC_BTN1": "Lclk", "KC_BTN2": "Rclk",
		"RGB_TOG": "Toggle", "RGB_SLD": "Solid",
		"RGB_VAD": "Brightness-", "RGB_VAI": "Brightness+", "RGB_MOD": "Animat",
		"KC_LSFT": "LShift", "KC_SPC": "SPC",
		"KC_VOLU": "VolUp", "KC_VOLD": "VolDn", "KC_MPRV": "Prev", "KC_MNXT": "Next",
		"KC_HOME": "Home", "KC_END": "End", "KC_PGUP": "PgUp", "KC_PGDN": "PgDn",
		"KC_MPLY": "Play", "KC_TAB": "Tab",
		"KC_WBAK": "BrowserBack"}
}

func (self *Scan) Err(s int) {
	fmt.Printf("\n!!Error!!%d\n", s)
}

func (self *Scan) GetDisplayName(key string) string {
	_, ok := self.m[key]
	if ok {
		return self.m[key]
	} else {
		return key
	}
}
func (self *Scan) Output() {
	pdf := gofpdf.New("P", "mm", "A4", "")
	pdf.SetFont("Arial", "", 10)
	pdf.AddPage()

	curx, cury := pdf.GetXY()
	x := curx
	y := cury
	_, lineHt := pdf.GetFontSize()

	//
	cols := [14]float64{0, 0, -0.25, -0.375, -0.25, 0, 0,
		0, 0, -0.25, -0.375, -0.25, 0, 0}
	var lkil []KeyInformation
	var rkil []KeyInformation
	for j := 0; j < 8; j++ {
		for i := 0; i < 7; i++ {
			var ltmp = KeyInformation{x: float64(i * 10), y: float64(j * 10), width: float64(10), height: float64(10), use: true}
			var rtmp = KeyInformation{x: float64((i + 13) * 10), y: float64(j * 10), width: float64(10), height: float64(10), use: true}
			if j < 6 {
				ltmp.y = ltmp.y + cols[i]*10
				rtmp.y = rtmp.y + cols[i+7]*10
			}
			if i == 0 {
				ltmp.x = ltmp.x - 5
				ltmp.width = 15
			}
			if i == 6 {
				rtmp.width = 15
			}
			lkil = append(lkil, ltmp)
			rkil = append(rkil, rtmp)
		}
	}
	//
	lkil[20].use = false
	rkil[14].use = false
	lkil[33].use = false
	rkil[29].use = false
	lkil[34].use = false
	rkil[28].use = false
	//
	for j := 5; j < 8; j++ {
		for i := 0; i < 4; i++ {
			lkil[j*7+i].use = false
			rkil[j*7+(6-i)].use = false
		}
	}
	//
	lkil[39].use = false
	rkil[37].use = false
	lkil[46].use = false
	rkil[44].use = false
	lkil[47].use = false
	rkil[43].use = false
	//
	lkil[53].height = float64(20)
	lkil[53].y = lkil[53].y - 10
	rkil[51].height = float64(20)
	rkil[51].y = lkil[51].y - 10
	lkil[54].height = float64(20)
	lkil[54].y = lkil[54].y - 10
	rkil[50].height = float64(20)
	rkil[50].y = lkil[50].y - 10
	//
	lkil[13].height = float64(15)
	rkil[7].height = float64(15)
	lkil[27].height = float64(15)
	rkil[21].height = float64(15)
	lkil[27].y = lkil[27].y - 5
	rkil[21].y = rkil[21].y - 5
	//
	lkil[28].x = lkil[28].x + 5
	lkil[28].width = 10
	rkil[34].width = 10
	// right

	for k := 0; k < 3; k++ {
		var keyindex int = 0
		for j := 0; j < 8; j++ {
			for i := 0; i < 7; i++ {
				var ki = lkil[j*7+i]
				if ki.use {
					if j > 4 {
						pdf.TransformBegin()
						pdf.TransformRotate(-30, 97, 97+90*float64(k))
					}
					pdf.Rect(curx+ki.x, cury+float64(k*90)+ki.y, ki.width, ki.height, "")
					pdf.SetXY(curx+ki.x, cury+float64(k*90)+ki.y)
					pdf.Cell(0, 0+lineHt, self.GetDisplayName(self.keys[k][keyindex]))
					keyindex = keyindex + 1
					if j > 4 {
						pdf.TransformEnd()
					}
				}
			}
		}
		for j := 0; j < 8; j++ {
			for i := 0; i < 7; i++ {
				var ki = rkil[j*7+i]
				if ki.use {
					if j > 4 {
						pdf.TransformBegin()
						pdf.TransformRotate(30, 113, 97+90*float64(k))
					}
					pdf.Rect(ki.x, cury+float64(k*90)+ki.y, ki.width, ki.height, "")
					pdf.SetXY(ki.x, cury+float64(k*90)+ki.y)
					pdf.Cell(0, 0+lineHt, self.GetDisplayName(self.keys[k][keyindex]))
					keyindex = keyindex + 1
					if j > 4 {
						pdf.TransformEnd()
					}
					x += 10
				}
			}
			y = y + 10
			x = curx
		}
		y = y + 20
	}
	pdf.Output(os.Stdout)
}

func main() {
	if len(os.Args) < 2 {
		fmt.Printf("%v FILE\n", os.Args[0])
		os.Exit(1)
	}
	file, err := os.Open(os.Args[1])
	if err != nil {
		log.Fatal(err)
	}

	buffer, err := ioutil.ReadAll(file)
	if err != nil {
		log.Fatal(err)
	}

	file.Close()

	parser := &Parser{Buffer: string(buffer)}
	parser.Init()
	parser.s.Init()
	err2 := parser.Parse()

	if err2 != nil {
		fmt.Println(err2)
	} else {
		parser.Execute()
		parser.s.Output()
	}
}
<|endoftext|>


<commit_before>package kontrol

import (
	"encoding/json"
	"errors"
	"fmt"
	"strings"
	"time"

	"github.com/coreos/go-etcd/etcd"
	"github.com/hashicorp/go-version"
	"github.com/koding/kite"
	kontrolprotocol "github.com/koding/kite/kontrol/protocol"
	"github.com/koding/kite/protocol"
)

// keyOrder defines the order of the query parameters.
var keyOrder = []string{
	"username",
	"environment",
	"name",
	"version",
	"region",
	"hostname",
	"id",
}

// Etcd implements the Storage interface
type Etcd struct {
	client *etcd.Client
	log    kite.Logger
}

func NewEtcd(machines []string, log kite.Logger) *Etcd {
	if machines == nil || len(machines) == 0 {
		machines = []string{"127.0.0.1:4001"}
	}

	client := etcd.NewClient(machines)
	ok := client.SetCluster(machines)
	if !ok {
		panic("cannot connect to etcd cluster: " + strings.Join(machines, ","))
	}

	return &Etcd{
		client: client,
		log:    log,
	}
}

func (e *Etcd) Delete(k *protocol.Kite) error {
	etcdKey := KitesPrefix + k.String()
	etcdIDKey := KitesPrefix + "/" + k.ID

	_, err := e.client.Delete(etcdKey, true)
	_, err = e.client.Delete(etcdIDKey, true)
	return err
}

func (e *Etcd) Clear() error {
	_, err := e.client.Delete(KitesPrefix, true)
	return err
}

func (e *Etcd) Upsert(k *protocol.Kite, value *kontrolprotocol.RegisterValue) error {
	return e.Add(k, value)
}

func (e *Etcd) Add(k *protocol.Kite, value *kontrolprotocol.RegisterValue) error {
	etcdKey := KitesPrefix + k.String()
	etcdIDKey := KitesPrefix + "/" + k.ID

	valueBytes, err := json.Marshal(value)
	if err != nil {
		return err
	}

	valueString := string(valueBytes)

	// Set the kite key.
	// Example "/koding/production/os/0.0.1/sj/kontainer1.sj.koding.com/1234asdf..."
	_, err = e.client.Set(etcdKey, valueString, uint64(KeyTTL/time.Second))
	if err != nil {
		return err
	}

	// Also store the the kite.Key Id for easy lookup
	_, err = e.client.Set(etcdIDKey, valueString, uint64(KeyTTL/time.Second))
	if err != nil {
		return err
	}

	return nil
}

func (e *Etcd) Update(k *protocol.Kite, value *kontrolprotocol.RegisterValue) error {
	etcdKey := KitesPrefix + k.String()
	etcdIDKey := KitesPrefix + "/" + k.ID

	valueBytes, err := json.Marshal(value)
	if err != nil {
		return err
	}

	valueString := string(valueBytes)

	// update the kite key.
	// Example "/koding/production/os/0.0.1/sj/kontainer1.sj.koding.com/1234asdf..."
	_, err = e.client.Update(etcdKey, valueString, uint64(KeyTTL/time.Second))
	if err != nil {
		err = e.Add(k, value)
		if err != nil {
			return err
		}
		return nil
	}

	// Also update the the kite.Key Id for easy lookup
	_, err = e.client.Update(etcdIDKey, valueString, uint64(KeyTTL/time.Second))
	if err != nil {
		return err
	}

	// Set the TTL for the username. Otherwise, empty dirs remain in etcd.
	_, err = e.client.Update(KitesPrefix+"/"+k.Username,
		"", uint64(KeyTTL/time.Second))
	if err != nil {
		return err
	}

	return nil
}

func (e *Etcd) Get(query *protocol.KontrolQuery) (Kites, error) {
	// We will make a get request to etcd store with this key. So get a "etcd"
	// key from the given query so that we can use it to query from Etcd.
	etcdKey, err := e.etcdKey(query)
	if err != nil {
		return nil, err
	}

	// If version field contains a constraint we need no make a new query up to
	// "name" field and filter the results after getting all versions.
	// NewVersion returns an error if it's a constraint, like: ">= 1.0, < 1.4"
	// Because NewConstraint doesn't return an error for version's like "0.0.1"
	// we check it with the NewVersion function.
	var hasVersionConstraint bool // does query contains a constraint on version?
	var keyRest string            // query key after the version field
	var versionConstraint version.Constraints
	_, err = version.NewVersion(query.Version)
	if err != nil && query.Version != "" {
		// now parse our constraint
		versionConstraint, err = version.NewConstraint(query.Version)
		if err != nil {
			// version is a malformed, just return the error
			return nil, err
		}

		hasVersionConstraint = true
		nameQuery := &protocol.KontrolQuery{
			Username:    query.Username,
			Environment: query.Environment,
			Name:        query.Name,
		}
		// We will make a get request to all nodes under this name
		// and filter the result later.
		etcdKey, _ = GetQueryKey(nameQuery)

		// Rest of the key after version field
		keyRest = "/" + strings.TrimRight(
			query.Region+"/"+query.Hostname+"/"+query.ID, "/")
	}

	resp, err := e.client.Get(KitesPrefix+etcdKey, false, true)
	if err != nil {
		// if it's something else just return
		return nil, err
	}

	kites := make(Kites, 0)

	node := NewNode(resp.Node)

	// means a query with all fields were made or a query with an ID was made,
	// in which case also returns a full path. This path has a value that
	// contains the final kite URL. Therefore this is a single kite result,
	// create it and pass it back.
	if node.HasValue() {
		oneKite, err := node.Kite()
		if err != nil {
			return nil, err
		}

		kites = append(kites, oneKite)
	} else {
		kites, err = node.Kites()
		if err != nil {
			return nil, err
		}

		// Filter kites by version constraint
		if hasVersionConstraint {
			kites.Filter(versionConstraint, keyRest)
		}
	}

	// Shuffle the list
	kites.Shuffle()

	return kites, nil
}

func (e *Etcd) etcdKey(query *protocol.KontrolQuery) (string, error) {
	if onlyIDQuery(query) {
		resp, err := e.client.Get(KitesPrefix+"/"+query.ID, false, true)
		if err != nil {
			return "", err
		}

		return resp.Node.Value, nil
	}

	return GetQueryKey(query)
}

// RegisterValue is the type of the value that is saved to etcd.
type RegisterValue struct {
	URL string `json:"url"`
}

// validateKiteKey returns a string representing the kite uniquely
// that is suitable to use as a key for etcd.
func validateKiteKey(k *protocol.Kite) error {
	fields := k.Query().Fields()

	// Validate fields.
	for k, v := range fields {
		if v == "" {
			return fmt.Errorf("Empty Kite field: %s", k)
		}
		if strings.ContainsRune(v, '/') {
			return fmt.Errorf("Field \"%s\" must not contain '/'", k)
		}
	}

	return nil
}

// onlyIDQuery returns true if the query contains only a non-empty ID and all
// others keys are empty
func onlyIDQuery(q *protocol.KontrolQuery) bool {
	fields := q.Fields()

	// check if any other key exist, if yes return a false
	for _, k := range keyOrder {
		v := fields[k]
		if k != "id" && v != "" {
			return false
		}
	}

	// now all other keys are empty, check finally for our ID
	if fields["id"] != "" {
		return true
	}

	// ID is empty too!
	return false
}

// getQueryKey returns the etcd key for the query.
func GetQueryKey(q *protocol.KontrolQuery) (string, error) {
	fields := q.Fields()

	if q.Username == "" {
		return "", errors.New("Empty username field")
	}

	// Validate query and build key.
	path := "/"

	empty := false   // encountered with empty field?
	empytField := "" // for error log

	// http://golang.org/doc/go1.3#map, order is important and we can't rely on
	// maps because the keys are not ordered :)
	for _, key := range keyOrder {
		v := fields[key]
		if v == "" {
			empty = true
			empytField = key
			continue
		}

		if empty && v != "" {
			return "", fmt.Errorf("Invalid query. Query option is not set: %s", empytField)
		}

		path = path + v + "/"
	}

	path = strings.TrimSuffix(path, "/")

	return path, nil
}

func getAudience(q *protocol.KontrolQuery) string {
	if q.Name != "" {
		return "/" + q.Username + "/" + q.Environment + "/" + q.Name
	} else if q.Environment != "" {
		return "/" + q.Username + "/" + q.Environment
	} else {
		return "/" + q.Username
	}
}
<commit_msg>Fixes breaking change done in net/url<commit_after>package kontrol

import (
	"encoding/json"
	"errors"
	"fmt"
	"strings"
	"time"

	"github.com/coreos/go-etcd/etcd"
	"github.com/hashicorp/go-version"
	"github.com/koding/kite"
	kontrolprotocol "github.com/koding/kite/kontrol/protocol"
	"github.com/koding/kite/protocol"
)

// keyOrder defines the order of the query parameters.
var keyOrder = []string{
	"username",
	"environment",
	"name",
	"version",
	"region",
	"hostname",
	"id",
}

// Etcd implements the Storage interface
type Etcd struct {
	client *etcd.Client
	log    kite.Logger
}

func NewEtcd(machines []string, log kite.Logger) *Etcd {
	if machines == nil || len(machines) == 0 {
		machines = []string{"//127.0.0.1:4001"}
	}

	client := etcd.NewClient(machines)
	ok := client.SetCluster(machines)
	if !ok {
		panic("cannot connect to etcd cluster: " + strings.Join(machines, ","))
	}

	return &Etcd{
		client: client,
		log:    log,
	}
}

func (e *Etcd) Delete(k *protocol.Kite) error {
	etcdKey := KitesPrefix + k.String()
	etcdIDKey := KitesPrefix + "/" + k.ID

	_, err := e.client.Delete(etcdKey, true)
	_, err = e.client.Delete(etcdIDKey, true)
	return err
}

func (e *Etcd) Clear() error {
	_, err := e.client.Delete(KitesPrefix, true)
	return err
}

func (e *Etcd) Upsert(k *protocol.Kite, value *kontrolprotocol.RegisterValue) error {
	return e.Add(k, value)
}

func (e *Etcd) Add(k *protocol.Kite, value *kontrolprotocol.RegisterValue) error {
	etcdKey := KitesPrefix + k.String()
	etcdIDKey := KitesPrefix + "/" + k.ID

	valueBytes, err := json.Marshal(value)
	if err != nil {
		return err
	}

	valueString := string(valueBytes)

	// Set the kite key.
	// Example "/koding/production/os/0.0.1/sj/kontainer1.sj.koding.com/1234asdf..."
	_, err = e.client.Set(etcdKey, valueString, uint64(KeyTTL/time.Second))
	if err != nil {
		return err
	}

	// Also store the the kite.Key Id for easy lookup
	_, err = e.client.Set(etcdIDKey, valueString, uint64(KeyTTL/time.Second))
	if err != nil {
		return err
	}

	return nil
}

func (e *Etcd) Update(k *protocol.Kite, value *kontrolprotocol.RegisterValue) error {
	etcdKey := KitesPrefix + k.String()
	etcdIDKey := KitesPrefix + "/" + k.ID

	valueBytes, err := json.Marshal(value)
	if err != nil {
		return err
	}

	valueString := string(valueBytes)

	// update the kite key.
	// Example "/koding/production/os/0.0.1/sj/kontainer1.sj.koding.com/1234asdf..."
	_, err = e.client.Update(etcdKey, valueString, uint64(KeyTTL/time.Second))
	if err != nil {
		err = e.Add(k, value)
		if err != nil {
			return err
		}
		return nil
	}

	// Also update the the kite.Key Id for easy lookup
	_, err = e.client.Update(etcdIDKey, valueString, uint64(KeyTTL/time.Second))
	if err != nil {
		return err
	}

	// Set the TTL for the username. Otherwise, empty dirs remain in etcd.
	_, err = e.client.Update(KitesPrefix+"/"+k.Username,
		"", uint64(KeyTTL/time.Second))
	if err != nil {
		return err
	}

	return nil
}

func (e *Etcd) Get(query *protocol.KontrolQuery) (Kites, error) {
	// We will make a get request to etcd store with this key. So get a "etcd"
	// key from the given query so that we can use it to query from Etcd.
	etcdKey, err := e.etcdKey(query)
	if err != nil {
		return nil, err
	}

	// If version field contains a constraint we need no make a new query up to
	// "name" field and filter the results after getting all versions.
	// NewVersion returns an error if it's a constraint, like: ">= 1.0, < 1.4"
	// Because NewConstraint doesn't return an error for version's like "0.0.1"
	// we check it with the NewVersion function.
	var hasVersionConstraint bool // does query contains a constraint on version?
	var keyRest string            // query key after the version field
	var versionConstraint version.Constraints
	_, err = version.NewVersion(query.Version)
	if err != nil && query.Version != "" {
		// now parse our constraint
		versionConstraint, err = version.NewConstraint(query.Version)
		if err != nil {
			// version is a malformed, just return the error
			return nil, err
		}

		hasVersionConstraint = true
		nameQuery := &protocol.KontrolQuery{
			Username:    query.Username,
			Environment: query.Environment,
			Name:        query.Name,
		}
		// We will make a get request to all nodes under this name
		// and filter the result later.
		etcdKey, _ = GetQueryKey(nameQuery)

		// Rest of the key after version field
		keyRest = "/" + strings.TrimRight(
			query.Region+"/"+query.Hostname+"/"+query.ID, "/")
	}

	resp, err := e.client.Get(KitesPrefix+etcdKey, false, true)
	if err != nil {
		// if it's something else just return
		return nil, err
	}

	kites := make(Kites, 0)

	node := NewNode(resp.Node)

	// means a query with all fields were made or a query with an ID was made,
	// in which case also returns a full path. This path has a value that
	// contains the final kite URL. Therefore this is a single kite result,
	// create it and pass it back.
	if node.HasValue() {
		oneKite, err := node.Kite()
		if err != nil {
			return nil, err
		}

		kites = append(kites, oneKite)
	} else {
		kites, err = node.Kites()
		if err != nil {
			return nil, err
		}

		// Filter kites by version constraint
		if hasVersionConstraint {
			kites.Filter(versionConstraint, keyRest)
		}
	}

	// Shuffle the list
	kites.Shuffle()

	return kites, nil
}

func (e *Etcd) etcdKey(query *protocol.KontrolQuery) (string, error) {
	if onlyIDQuery(query) {
		resp, err := e.client.Get(KitesPrefix+"/"+query.ID, false, true)
		if err != nil {
			return "", err
		}

		return resp.Node.Value, nil
	}

	return GetQueryKey(query)
}

// RegisterValue is the type of the value that is saved to etcd.
type RegisterValue struct {
	URL string `json:"url"`
}

// validateKiteKey returns a string representing the kite uniquely
// that is suitable to use as a key for etcd.
func validateKiteKey(k *protocol.Kite) error {
	fields := k.Query().Fields()

	// Validate fields.
	for k, v := range fields {
		if v == "" {
			return fmt.Errorf("Empty Kite field: %s", k)
		}
		if strings.ContainsRune(v, '/') {
			return fmt.Errorf("Field \"%s\" must not contain '/'", k)
		}
	}

	return nil
}

// onlyIDQuery returns true if the query contains only a non-empty ID and all
// others keys are empty
func onlyIDQuery(q *protocol.KontrolQuery) bool {
	fields := q.Fields()

	// check if any other key exist, if yes return a false
	for _, k := range keyOrder {
		v := fields[k]
		if k != "id" && v != "" {
			return false
		}
	}

	// now all other keys are empty, check finally for our ID
	if fields["id"] != "" {
		return true
	}

	// ID is empty too!
	return false
}

// getQueryKey returns the etcd key for the query.
func GetQueryKey(q *protocol.KontrolQuery) (string, error) {
	fields := q.Fields()

	if q.Username == "" {
		return "", errors.New("Empty username field")
	}

	// Validate query and build key.
	path := "/"

	empty := false   // encountered with empty field?
	empytField := "" // for error log

	// http://golang.org/doc/go1.3#map, order is important and we can't rely on
	// maps because the keys are not ordered :)
	for _, key := range keyOrder {
		v := fields[key]
		if v == "" {
			empty = true
			empytField = key
			continue
		}

		if empty && v != "" {
			return "", fmt.Errorf("Invalid query. Query option is not set: %s", empytField)
		}

		path = path + v + "/"
	}

	path = strings.TrimSuffix(path, "/")

	return path, nil
}

func getAudience(q *protocol.KontrolQuery) string {
	if q.Name != "" {
		return "/" + q.Username + "/" + q.Environment + "/" + q.Name
	} else if q.Environment != "" {
		return "/" + q.Username + "/" + q.Environment
	} else {
		return "/" + q.Username
	}
}
<|endoftext|>