<commit_before>package runtime

import (
	"context"
	"encoding/base64"
	"fmt"
	"net"
	"net/http"
	"net/textproto"
	"strconv"
	"strings"
	"time"

	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/metadata"
	"google.golang.org/grpc/status"
)

// MetadataHeaderPrefix is the http prefix that represents custom metadata
// parameters to or from a gRPC call.
const MetadataHeaderPrefix = "Grpc-Metadata-"

// MetadataPrefix is prepended to permanent HTTP header keys (as specified
// by the IANA) when added to the gRPC context.
const MetadataPrefix = "grpcgateway-"

// MetadataTrailerPrefix is prepended to gRPC metadata as it is converted to
// HTTP headers in a response handled by grpc-gateway
const MetadataTrailerPrefix = "Grpc-Trailer-"

const metadataGrpcTimeout = "Grpc-Timeout"
const metadataHeaderBinarySuffix = "-Bin"

const xForwardedFor = "X-Forwarded-For"
const xForwardedHost = "X-Forwarded-Host"

var (
	// DefaultContextTimeout is used for gRPC call context.WithTimeout whenever a Grpc-Timeout inbound
	// header isn't present. If the value is 0 the sent `context` will not have a timeout.
	DefaultContextTimeout = 0 * time.Second
)

type rpcMethodKey struct{}

func decodeBinHeader(v string) ([]byte, error) {
	if len(v)%4 == 0 {
		// Input was padded, or padding was not necessary.
		return base64.StdEncoding.DecodeString(v)
	}
	return base64.RawStdEncoding.DecodeString(v)
}

/*
AnnotateContext adds context information such as metadata from the request.

At a minimum, the RemoteAddr is included in the fashion of "X-Forwarded-For",
except that the forwarded destination is not another HTTP service but rather
a gRPC service.
*/
func AnnotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcMethodName string) (context.Context, error) {
	ctx, md, err := annotateContext(ctx, mux, req, rpcMethodName)
	if err != nil {
		return nil, err
	}
	if md == nil {
		return ctx, nil
	}

	return metadata.NewOutgoingContext(ctx, md), nil
}

// AnnotateIncomingContext adds context information such as metadata from the request.
// Attach metadata as incoming context.
func AnnotateIncomingContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcMethodName string) (context.Context, error) {
	ctx, md, err := annotateContext(ctx, mux, req, rpcMethodName)
	if err != nil {
		return nil, err
	}
	if md == nil {
		return ctx, nil
	}

	return metadata.NewIncomingContext(ctx, md), nil
}

func annotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcMethodName string) (context.Context, metadata.MD, error) {
	ctx = withRPCMethod(ctx, rpcMethodName)
	var pairs []string
	timeout := DefaultContextTimeout
	if tm := req.Header.Get(metadataGrpcTimeout); tm != "" {
		var err error
		timeout, err = timeoutDecode(tm)
		if err != nil {
			return nil, nil, status.Errorf(codes.InvalidArgument, "invalid grpc-timeout: %s", tm)
		}
	}

	for key, vals := range req.Header {
		for _, val := range vals {
			key = textproto.CanonicalMIMEHeaderKey(key)
			// For backwards-compatibility, pass through 'authorization' header with no prefix.
			if key == "Authorization" {
				pairs = append(pairs, "authorization", val)
			}
			if h, ok := mux.incomingHeaderMatcher(key); ok {
				// Handles "-bin" metadata in grpc, since grpc will do another base64
				// encode before sending to server, we need to decode it first.
				if strings.HasSuffix(key, metadataHeaderBinarySuffix) {
					b, err := decodeBinHeader(val)
					if err != nil {
						return nil, nil, status.Errorf(codes.InvalidArgument, "invalid binary header %s: %s", key, err)
					}

					val = string(b)
				}
				pairs = append(pairs, h, val)
			}
		}
	}
	if host := req.Header.Get(xForwardedHost); host != "" {
		pairs = append(pairs, strings.ToLower(xForwardedHost), host)
	} else if req.Host != "" {
		pairs = append(pairs, strings.ToLower(xForwardedHost), req.Host)
	}

	if addr := req.RemoteAddr; addr != "" {
		if remoteIP, _, err := net.SplitHostPort(addr); err == nil {
			if fwd := req.Header.Get(xForwardedFor); fwd == "" {
				pairs = append(pairs, strings.ToLower(xForwardedFor), remoteIP)
			} else {
				pairs = append(pairs, strings.ToLower(xForwardedFor), fmt.Sprintf("%s, %s", fwd, remoteIP))
			}
		}
	}

	if timeout != 0 {
		ctx, _ = context.WithTimeout(ctx, timeout)
	}
	if len(pairs) == 0 {
		return ctx, nil, nil
	}
	md := metadata.Pairs(pairs...)
	for _, mda := range mux.metadataAnnotators {
		md = metadata.Join(md, mda(ctx, req))
	}
	return ctx, md, nil
}

// ServerMetadata consists of metadata sent from gRPC server.
type ServerMetadata struct {
	HeaderMD  metadata.MD
	TrailerMD metadata.MD
}

type serverMetadataKey struct{}

// NewServerMetadataContext creates a new context with ServerMetadata
func NewServerMetadataContext(ctx context.Context, md ServerMetadata) context.Context {
	return context.WithValue(ctx, serverMetadataKey{}, md)
}

// ServerMetadataFromContext returns the ServerMetadata in ctx
func ServerMetadataFromContext(ctx context.Context) (md ServerMetadata, ok bool) {
	md, ok = ctx.Value(serverMetadataKey{}).(ServerMetadata)
	return
}

func timeoutDecode(s string) (time.Duration, error) {
	size := len(s)
	if size < 2 {
		return 0, fmt.Errorf("timeout string is too short: %q", s)
	}
	d, ok := timeoutUnitToDuration(s[size-1])
	if !ok {
		return 0, fmt.Errorf("timeout unit is not recognized: %q", s)
	}
	t, err := strconv.ParseInt(s[:size-1], 10, 64)
	if err != nil {
		return 0, err
	}
	return d * time.Duration(t), nil
}

func timeoutUnitToDuration(u uint8) (d time.Duration, ok bool) {
	switch u {
	case 'H':
		return time.Hour, true
	case 'M':
		return time.Minute, true
	case 'S':
		return time.Second, true
	case 'm':
		return time.Millisecond, true
	case 'u':
		return time.Microsecond, true
	case 'n':
		return time.Nanosecond, true
	default:
	}
	return
}

// isPermanentHTTPHeader checks whether hdr belongs to the list of
// permanent request headers maintained by IANA.
// http://www.iana.org/assignments/message-headers/message-headers.xml
func isPermanentHTTPHeader(hdr string) bool {
	switch hdr {
	case
		"Accept",
		"Accept-Charset",
		"Accept-Language",
		"Accept-Ranges",
		"Authorization",
		"Cache-Control",
		"Content-Type",
		"Cookie",
		"Date",
		"Expect",
		"From",
		"Host",
		"If-Match",
		"If-Modified-Since",
		"If-None-Match",
		"If-Schedule-Tag-Match",
		"If-Unmodified-Since",
		"Max-Forwards",
		"Origin",
		"Pragma",
		"Referer",
		"User-Agent",
		"Via",
		"Warning":
		return true
	}
	return false
}

// RPCMethod returns the method string for the server context. The returned
// string is in the format of "/package.service/method".
func RPCMethod(ctx context.Context) (string, bool) {
	m := ctx.Value(rpcMethodKey{})
	if m == nil {
		return "", false
	}
	ms, ok := m.(string)
	if !ok {
		return "", false
	}
	return ms, true
}

func withRPCMethod(ctx context.Context, rpcMethodName string) context.Context {
	return context.WithValue(ctx, rpcMethodKey{}, rpcMethodName)
}
<commit_msg>Only canonicalize header key once in each iteration (#1565)<commit_after>package runtime

import (
	"context"
	"encoding/base64"
	"fmt"
	"net"
	"net/http"
	"net/textproto"
	"strconv"
	"strings"
	"time"

	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/metadata"
	"google.golang.org/grpc/status"
)

// MetadataHeaderPrefix is the http prefix that represents custom metadata
// parameters to or from a gRPC call.
const MetadataHeaderPrefix = "Grpc-Metadata-"

// MetadataPrefix is prepended to permanent HTTP header keys (as specified
// by the IANA) when added to the gRPC context.
const MetadataPrefix = "grpcgateway-"

// MetadataTrailerPrefix is prepended to gRPC metadata as it is converted to
// HTTP headers in a response handled by grpc-gateway
const MetadataTrailerPrefix = "Grpc-Trailer-"

const metadataGrpcTimeout = "Grpc-Timeout"
const metadataHeaderBinarySuffix = "-Bin"

const xForwardedFor = "X-Forwarded-For"
const xForwardedHost = "X-Forwarded-Host"

var (
	// DefaultContextTimeout is used for gRPC call context.WithTimeout whenever a Grpc-Timeout inbound
	// header isn't present. If the value is 0 the sent `context` will not have a timeout.
	DefaultContextTimeout = 0 * time.Second
)

type rpcMethodKey struct{}

func decodeBinHeader(v string) ([]byte, error) {
	if len(v)%4 == 0 {
		// Input was padded, or padding was not necessary.
		return base64.StdEncoding.DecodeString(v)
	}
	return base64.RawStdEncoding.DecodeString(v)
}

/*
AnnotateContext adds context information such as metadata from the request.

At a minimum, the RemoteAddr is included in the fashion of "X-Forwarded-For",
except that the forwarded destination is not another HTTP service but rather
a gRPC service.
*/
func AnnotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcMethodName string) (context.Context, error) {
	ctx, md, err := annotateContext(ctx, mux, req, rpcMethodName)
	if err != nil {
		return nil, err
	}
	if md == nil {
		return ctx, nil
	}

	return metadata.NewOutgoingContext(ctx, md), nil
}

// AnnotateIncomingContext adds context information such as metadata from the request.
// Attach metadata as incoming context.
func AnnotateIncomingContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcMethodName string) (context.Context, error) {
	ctx, md, err := annotateContext(ctx, mux, req, rpcMethodName)
	if err != nil {
		return nil, err
	}
	if md == nil {
		return ctx, nil
	}

	return metadata.NewIncomingContext(ctx, md), nil
}

func annotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcMethodName string) (context.Context, metadata.MD, error) {
	ctx = withRPCMethod(ctx, rpcMethodName)
	var pairs []string
	timeout := DefaultContextTimeout
	if tm := req.Header.Get(metadataGrpcTimeout); tm != "" {
		var err error
		timeout, err = timeoutDecode(tm)
		if err != nil {
			return nil, nil, status.Errorf(codes.InvalidArgument, "invalid grpc-timeout: %s", tm)
		}
	}

	for key, vals := range req.Header {
		key = textproto.CanonicalMIMEHeaderKey(key)
		for _, val := range vals {
			// For backwards-compatibility, pass through 'authorization' header with no prefix.
			if key == "Authorization" {
				pairs = append(pairs, "authorization", val)
			}
			if h, ok := mux.incomingHeaderMatcher(key); ok {
				// Handles "-bin" metadata in grpc, since grpc will do another base64
				// encode before sending to server, we need to decode it first.
				if strings.HasSuffix(key, metadataHeaderBinarySuffix) {
					b, err := decodeBinHeader(val)
					if err != nil {
						return nil, nil, status.Errorf(codes.InvalidArgument, "invalid binary header %s: %s", key, err)
					}

					val = string(b)
				}
				pairs = append(pairs, h, val)
			}
		}
	}
	if host := req.Header.Get(xForwardedHost); host != "" {
		pairs = append(pairs, strings.ToLower(xForwardedHost), host)
	} else if req.Host != "" {
		pairs = append(pairs, strings.ToLower(xForwardedHost), req.Host)
	}

	if addr := req.RemoteAddr; addr != "" {
		if remoteIP, _, err := net.SplitHostPort(addr); err == nil {
			if fwd := req.Header.Get(xForwardedFor); fwd == "" {
				pairs = append(pairs, strings.ToLower(xForwardedFor), remoteIP)
			} else {
				pairs = append(pairs, strings.ToLower(xForwardedFor), fmt.Sprintf("%s, %s", fwd, remoteIP))
			}
		}
	}

	if timeout != 0 {
		ctx, _ = context.WithTimeout(ctx, timeout)
	}
	if len(pairs) == 0 {
		return ctx, nil, nil
	}
	md := metadata.Pairs(pairs...)
	for _, mda := range mux.metadataAnnotators {
		md = metadata.Join(md, mda(ctx, req))
	}
	return ctx, md, nil
}

// ServerMetadata consists of metadata sent from gRPC server.
type ServerMetadata struct {
	HeaderMD  metadata.MD
	TrailerMD metadata.MD
}

type serverMetadataKey struct{}

// NewServerMetadataContext creates a new context with ServerMetadata
func NewServerMetadataContext(ctx context.Context, md ServerMetadata) context.Context {
	return context.WithValue(ctx, serverMetadataKey{}, md)
}

// ServerMetadataFromContext returns the ServerMetadata in ctx
func ServerMetadataFromContext(ctx context.Context) (md ServerMetadata, ok bool) {
	md, ok = ctx.Value(serverMetadataKey{}).(ServerMetadata)
	return
}

func timeoutDecode(s string) (time.Duration, error) {
	size := len(s)
	if size < 2 {
		return 0, fmt.Errorf("timeout string is too short: %q", s)
	}
	d, ok := timeoutUnitToDuration(s[size-1])
	if !ok {
		return 0, fmt.Errorf("timeout unit is not recognized: %q", s)
	}
	t, err := strconv.ParseInt(s[:size-1], 10, 64)
	if err != nil {
		return 0, err
	}
	return d * time.Duration(t), nil
}

func timeoutUnitToDuration(u uint8) (d time.Duration, ok bool) {
	switch u {
	case 'H':
		return time.Hour, true
	case 'M':
		return time.Minute, true
	case 'S':
		return time.Second, true
	case 'm':
		return time.Millisecond, true
	case 'u':
		return time.Microsecond, true
	case 'n':
		return time.Nanosecond, true
	default:
	}
	return
}

// isPermanentHTTPHeader checks whether hdr belongs to the list of
// permanent request headers maintained by IANA.
// http://www.iana.org/assignments/message-headers/message-headers.xml
func isPermanentHTTPHeader(hdr string) bool {
	switch hdr {
	case
		"Accept",
		"Accept-Charset",
		"Accept-Language",
		"Accept-Ranges",
		"Authorization",
		"Cache-Control",
		"Content-Type",
		"Cookie",
		"Date",
		"Expect",
		"From",
		"Host",
		"If-Match",
		"If-Modified-Since",
		"If-None-Match",
		"If-Schedule-Tag-Match",
		"If-Unmodified-Since",
		"Max-Forwards",
		"Origin",
		"Pragma",
		"Referer",
		"User-Agent",
		"Via",
		"Warning":
		return true
	}
	return false
}

// RPCMethod returns the method string for the server context. The returned
// string is in the format of "/package.service/method".
func RPCMethod(ctx context.Context) (string, bool) {
	m := ctx.Value(rpcMethodKey{})
	if m == nil {
		return "", false
	}
	ms, ok := m.(string)
	if !ok {
		return "", false
	}
	return ms, true
}

func withRPCMethod(ctx context.Context, rpcMethodName string) context.Context {
	return context.WithValue(ctx, rpcMethodKey{}, rpcMethodName)
}
<|endoftext|>


<commit_before>package runtime

import (
    "fmt"
    "reflect"
    "strings"
    "github.com/cloudson/gitql/parser"
    "github.com/libgit2/git2go"
)

var repo *git.Repository
var builder *GitBuilder
var boolRegister bool

type GitBuilder struct {
    tables map[string]string
    possibleTables map[string][]string
    walk *git.RevWalk
}

type RuntimeError struct {
    code uint8
    message string
}

type RuntimeVisitor struct {

}

// =========================== Runtime
func Run(n *parser.NodeProgram) {
    builder = GetGitBuilder(n.Path)
    visitor := new(RuntimeVisitor)
    err := visitor.Visit(n)
    if err != nil {
        panic(err)
    }

    s := n.Child.(*parser.NodeSelect)
    where := s.Where
    // valuesTable := make([]string, len(s.Fields))
    counter := 1
    fmt.Println()
    fn := func (object *git.Commit) bool {
        lvalue := where.LeftValue().(*parser.NodeId).Value()
        rvalue := where.RightValue().(*parser.NodeLiteral).Value()
        result := where.Assertion(discoverLvalue(lvalue, s.Tables[0], object), rvalue)
        if result {
            fields := s.Fields
            if s.WildCard {
                fields = builder.possibleTables[s.Tables[0]]
            }
            for _, f := range fields {
                fmt.Printf("%s | ", discoverLvalue(f, s.Tables[0], object))
            }
            fmt.Println()

            counter = counter + 1
        }
        if counter > s.Limit {
            return false
        }
        return true
    }

    err = builder.walk.Iterate(fn)
    if err != nil {
        fmt.Printf(err.Error())
    }

}

func discoverLvalue(identifier string, table string, object *git.Commit) string {
    err := builder.UseFieldFromTable(identifier, table)
    if err != nil {
        panic(err)
    }
    switch identifier {
        case "hash" :
            return object.Id().String()
        case "author":
            return object.Author().Name
        case "author_email":
            return object.Author().Email
        case "committer":
            return object.Committer().Name
        case "committer_email":
            return object.Committer().Email
        case "full_message":
            return object.Message()
        case "message":
            message := object.Message()
            r := []rune("\n")
            idx := strings.IndexRune(message, r[0])
            if idx != -1 {
                message = message[0:idx]
            }
            return message

    }

    panic(fmt.Sprintf("Trying select field %s ", identifier))
}

// =========================== Error

func (e *RuntimeError) Error() string{
    return e.message
}

func throwRuntimeError(message string, code uint8) (*RuntimeError) {
    e := new(RuntimeError)
    e.message = message
    e.code = code

    return e
}

// ========================== RuntimeVisitor

func (v *RuntimeVisitor) Visit(n *parser.NodeProgram) (error) {
    return v.VisitSelect(n.Child.(*parser.NodeSelect))
}

func (v *RuntimeVisitor) VisitSelect(n *parser.NodeSelect) (error) {
    table := n.Tables[0]
    fields := n.Fields
    var err error
    for _, f := range fields {
        err = builder.UseFieldFromTable(f, table)
        if err != nil {
            return err
        }
    }
    err = v.VisitExpr(n.Where)
    if err != nil {
        return err
    }
    return nil
}

func (v *RuntimeVisitor) VisitExpr(n parser.NodeExpr) (error) {
    switch reflect.TypeOf(n) {
        case reflect.TypeOf(new(parser.NodeEqual)) :
            g:= n.(*parser.NodeEqual)
            return v.VisitEqual(g)
        case reflect.TypeOf(new(parser.NodeGreater)) :
            g:= n.(*parser.NodeGreater)
            return v.VisitGreater(g)
        case reflect.TypeOf(new(parser.NodeSmaller)) :
            g:= n.(*parser.NodeSmaller)
            return v.VisitSmaller(g)
    }

    return nil
}

func (v *RuntimeVisitor) VisitEqual(n *parser.NodeEqual) (error) {

    // left, isId := n.LeftValue().(*parser.NodeId)
    // if !isId {

    // }

    return nil
}

func (v *RuntimeVisitor) VisitGreater(n *parser.NodeGreater) (error) {

    return nil
}

func (v *RuntimeVisitor) VisitSmaller(n *parser.NodeSmaller) (error) {

    return nil
}

func (v *RuntimeVisitor) Builder() (*GitBuilder){
    return nil
}

// =================== GitBuilder

func GetGitBuilder(path *string) (*GitBuilder) {

    gb := new(GitBuilder)
    gb.tables = make(map[string]string)
    possibleTables := map[string][]string {
        "commits": {
            "hash",
            // "date",
            "author",
            "author_email",
            "committer",
            "committer_email",
            "message",
            "full_message",
        },
        "author": {
            "name",
            "email",
        },
        "files": {
            "hash",
            "path",
        },
    }
    gb.possibleTables = possibleTables

    openRepository(path)

    gb.walk, _ = repo.Walk()
    gb.walk.PushHead()
    gb.walk.Sorting(git.SortTime)

    return gb
}

func openRepository(path *string) {
    _repo, err := git.OpenRepository(*path)
    if err != nil {
        panic(err)
    }
    repo = _repo
}

func (g *GitBuilder) WithTable(tableName string, alias string) error {
    err := g.isValidTable(tableName)
    if err != nil {
        return err
    }

    if g.possibleTables[tableName] == nil {
        return throwRuntimeError(fmt.Sprintf("Table '%s' not found", tableName), 0)
    }

    if alias == "" {
        alias = tableName
    }

    g.tables[alias] = tableName

    return nil
}

func (g *GitBuilder) isValidTable(tableName string) error {
    if g.possibleTables[tableName] == nil {
        return throwRuntimeError(fmt.Sprintf("Table '%s' not found", tableName), 0)
    }

    return nil
}

func (g *GitBuilder) UseFieldFromTable(field string, tableName string) error {
    if field == "*" {
        return nil
    }

    err := g.isValidTable(tableName)
    if err != nil {
        return err
    }

    table := g.possibleTables[tableName]
    for _, t := range table {
        if t == field {
            return nil
        }
    }

    return throwRuntimeError(fmt.Sprintf("Table '%s' has not field '%s'", tableName, field), 0)
}

// Criar varias funcoes de asserção, a closure usará elas para saber se um certo objeto
// pode ser mostrado ou não.<commit_msg>supports for date<commit_after>package runtime

import (
    "fmt"
    "reflect"
    "strings"
    "github.com/cloudson/gitql/parser"
    "github.com/libgit2/git2go"
)

var repo *git.Repository
var builder *GitBuilder
var boolRegister bool

type GitBuilder struct {
    tables map[string]string
    possibleTables map[string][]string
    walk *git.RevWalk
}

type RuntimeError struct {
    code uint8
    message string
}

type RuntimeVisitor struct {

}

// =========================== Runtime
func Run(n *parser.NodeProgram) {
    builder = GetGitBuilder(n.Path)
    visitor := new(RuntimeVisitor)
    err := visitor.Visit(n)
    if err != nil {
        panic(err)
    }

    s := n.Child.(*parser.NodeSelect)
    where := s.Where
    // valuesTable := make([]string, len(s.Fields))
    counter := 1
    fmt.Println()
    fn := func (object *git.Commit) bool {
        lvalue := where.LeftValue().(*parser.NodeId).Value()
        rvalue := where.RightValue().(*parser.NodeLiteral).Value()
        result := where.Assertion(discoverLvalue(lvalue, s.Tables[0], object), rvalue)
        if result {
            fields := s.Fields
            if s.WildCard {
                fields = builder.possibleTables[s.Tables[0]]
            }
            for _, f := range fields {
                fmt.Printf("%s | ", discoverLvalue(f, s.Tables[0], object))
            }
            fmt.Println()

            counter = counter + 1
        }
        if counter > s.Limit {
            return false
        }
        return true
    }

    err = builder.walk.Iterate(fn)
    if err != nil {
        fmt.Printf(err.Error())
    }

}

func discoverLvalue(identifier string, table string, object *git.Commit) string {
    err := builder.UseFieldFromTable(identifier, table)
    if err != nil {
        panic(err)
    }
    switch identifier {
        case "hash" :
            return object.Id().String()
        case "author":
            return object.Author().Name
        case "author_email":
            return object.Author().Email
        case "committer":
            return object.Committer().Name
        case "committer_email":
            return object.Committer().Email
        case "date":
            return object.Committer().When.String()
        case "full_message":
            return object.Message()
        case "message":
            message := object.Message()
            r := []rune("\n")
            idx := strings.IndexRune(message, r[0])
            if idx != -1 {
                message = message[0:idx]
            }
            return message

    }

    panic(fmt.Sprintf("Trying select field %s ", identifier))
}

// =========================== Error

func (e *RuntimeError) Error() string{
    return e.message
}

func throwRuntimeError(message string, code uint8) (*RuntimeError) {
    e := new(RuntimeError)
    e.message = message
    e.code = code

    return e
}

// ========================== RuntimeVisitor

func (v *RuntimeVisitor) Visit(n *parser.NodeProgram) (error) {
    return v.VisitSelect(n.Child.(*parser.NodeSelect))
}

func (v *RuntimeVisitor) VisitSelect(n *parser.NodeSelect) (error) {
    table := n.Tables[0]
    fields := n.Fields
    var err error
    for _, f := range fields {
        err = builder.UseFieldFromTable(f, table)
        if err != nil {
            return err
        }
    }
    err = v.VisitExpr(n.Where)
    if err != nil {
        return err
    }
    return nil
}

func (v *RuntimeVisitor) VisitExpr(n parser.NodeExpr) (error) {
    switch reflect.TypeOf(n) {
        case reflect.TypeOf(new(parser.NodeEqual)) :
            g:= n.(*parser.NodeEqual)
            return v.VisitEqual(g)
        case reflect.TypeOf(new(parser.NodeGreater)) :
            g:= n.(*parser.NodeGreater)
            return v.VisitGreater(g)
        case reflect.TypeOf(new(parser.NodeSmaller)) :
            g:= n.(*parser.NodeSmaller)
            return v.VisitSmaller(g)
    }

    return nil
}

func (v *RuntimeVisitor) VisitEqual(n *parser.NodeEqual) (error) {

    // left, isId := n.LeftValue().(*parser.NodeId)
    // if !isId {

    // }

    return nil
}

func (v *RuntimeVisitor) VisitGreater(n *parser.NodeGreater) (error) {

    return nil
}

func (v *RuntimeVisitor) VisitSmaller(n *parser.NodeSmaller) (error) {

    return nil
}

func (v *RuntimeVisitor) Builder() (*GitBuilder){
    return nil
}

// =================== GitBuilder

func GetGitBuilder(path *string) (*GitBuilder) {

    gb := new(GitBuilder)
    gb.tables = make(map[string]string)
    possibleTables := map[string][]string {
        "commits": {
            "hash",
            "date",
            "author",
            "author_email",
            "committer",
            "committer_email",
            "message",
            "full_message",
        },
        "author": {
            "name",
            "email",
        },
        "files": {
            "hash",
            "path",
        },
    }
    gb.possibleTables = possibleTables

    openRepository(path)

    gb.walk, _ = repo.Walk()
    gb.walk.PushHead()
    gb.walk.Sorting(git.SortTime)

    return gb
}

func openRepository(path *string) {
    _repo, err := git.OpenRepository(*path)
    if err != nil {
        panic(err)
    }
    repo = _repo
}

func (g *GitBuilder) WithTable(tableName string, alias string) error {
    err := g.isValidTable(tableName)
    if err != nil {
        return err
    }

    if g.possibleTables[tableName] == nil {
        return throwRuntimeError(fmt.Sprintf("Table '%s' not found", tableName), 0)
    }

    if alias == "" {
        alias = tableName
    }

    g.tables[alias] = tableName

    return nil
}

func (g *GitBuilder) isValidTable(tableName string) error {
    if g.possibleTables[tableName] == nil {
        return throwRuntimeError(fmt.Sprintf("Table '%s' not found", tableName), 0)
    }

    return nil
}

func (g *GitBuilder) UseFieldFromTable(field string, tableName string) error {
    if field == "*" {
        return nil
    }

    err := g.isValidTable(tableName)
    if err != nil {
        return err
    }

    table := g.possibleTables[tableName]
    for _, t := range table {
        if t == field {
            return nil
        }
    }

    return throwRuntimeError(fmt.Sprintf("Table '%s' has not field '%s'", tableName, field), 0)
}

// Criar varias funcoes de asserção, a closure usará elas para saber se um certo objeto
// pode ser mostrado ou não.<|endoftext|>


<commit_before>package core

// Arguments represents a structured set of arguments passed to a predicate.
// It allows destructive operations to internal properties because it is
// guaranteed by Thunks that arguments objects are never reused as a function
// call creates a Thunk.
type Arguments struct {
	positionals   []*Thunk
	expandedList  *Thunk
	keywords      []KeywordArgument
	expandedDicts []*Thunk
}

// NewArguments creates a new Arguments.
func NewArguments(
	ps []PositionalArgument,
	ks []KeywordArgument,
	ds []*Thunk) Arguments {
	ts := make([]*Thunk, 0, len(ps))
	l := (*Thunk)(nil)

	for i, p := range ps {
		if p.expanded {
			l = mergePositionalArguments(ps[i:])
			break
		}

		ts = append(ts, p.value)
	}

	return Arguments{ts, l, ks, ds}
}

// NewPositionalArguments creates an Arguments which consists of unexpanded
// positional arguments.
func NewPositionalArguments(ts ...*Thunk) Arguments {
	return Arguments{ts, nil, nil, nil}
}

func mergePositionalArguments(ps []PositionalArgument) *Thunk {
	t := EmptyList

	// Optimization for a common pattern of (func a b c ... ..xs).
	// Note that Merge is O(n) but Prepend is O(1).
	if last := len(ps) - 1; ps[last].expanded {
		t = ps[last].value
		ps = ps[:last]
	}

	for i := len(ps) - 1; i >= 0; i-- {
		p := ps[i]

		if p.expanded {
			t = PApp(Merge, p.value, t)
		} else {
			t = PApp(Prepend, p.value, t)
		}
	}

	return t
}

func (args *Arguments) nextPositional() *Thunk {
	if len(args.positionals) != 0 {
		t := args.positionals[0]
		args.positionals = args.positionals[1:]
		return t
	}

	if args.expandedList == nil {
		return nil
	}

	l := args.expandedList
	args.expandedList = PApp(Rest, l)
	return PApp(First, l)
}

func (args *Arguments) restPositionals() *Thunk {
	ts := args.positionals
	l := args.expandedList
	args.positionals = nil
	args.expandedList = nil

	if l == nil {
		return NewList(ts...)
	} else if len(ts) == 0 {
		return l
	}

	return PApp(Prepend, append(ts, l)...)
}

func (args *Arguments) searchKeyword(s string) *Thunk {
	for i, k := range args.keywords {
		if s == k.name {
			args.keywords = append(args.keywords[:i], args.keywords[i+1:]...)
			return k.value
		}
	}

	for i, t := range args.expandedDicts {
		v := t.Eval()
		d, ok := v.(DictionaryType)

		if !ok {
			return NotDictionaryError(v)
		}

		k := StringType(s)

		if v, ok := d.Search(k); ok {
			ds := make([]*Thunk, len(args.expandedDicts))
			copy(ds, args.expandedDicts)
			ds[i] = Normal(d.Remove(k))
			args.expandedDicts = ds
			return v
		}
	}

	return nil
}

func (args *Arguments) restKeywords() *Thunk {
	ks := args.keywords
	ds := args.expandedDicts
	args.keywords = nil
	args.expandedDicts = nil

	d := emptyDictionary

	for _, k := range ks {
		v := d.insert(StringType(k.name), k.value)
		var ok bool
		d, ok = v.(DictionaryType)

		if !ok {
			return NotDictionaryError(v)
		}
	}

	return PApp(Merge, append([]*Thunk{Normal(d)}, ds...)...)
}

// Merge merges 2 sets of arguments into one.
func (args Arguments) Merge(old Arguments) Arguments {
	ks := append(args.keywords, old.keywords...)
	ds := append(args.expandedDicts, old.expandedDicts...)

	if args.expandedList == nil {
		return Arguments{append(args.positionals, old.positionals...), old.expandedList, ks, ds}
	}

	l := EmptyList

	if old.expandedList != nil {
		l = old.expandedList
	}

	return Arguments{
		args.positionals,
		PApp(Merge, args.expandedList, PApp(Prepend, append(old.positionals, l)...)),
		ks,
		ds,
	}
}

func (args Arguments) empty() *Thunk {
	if len(args.positionals) > 0 {
		return argumentError("%d positional arguments are left", len(args.positionals))
	}

	// Testing args.expandedList is impossible because we cannot know its length
	// without evaluating it.

	n := 0

	for _, t := range args.expandedDicts {
		v := t.Eval()
		d, ok := v.(DictionaryType)

		if !ok {
			return NotDictionaryError(v)
		}

		n += d.Size()
	}

	if n != 0 || args.keywords != nil && len(args.keywords) > 0 {
		return argumentError("%d keyword arguments are left", len(args.keywords)+n)
	}

	return nil
}
<commit_msg>Refactor binding of expanded dictionaries<commit_after>package core

// Arguments represents a structured set of arguments passed to a predicate.
// It allows destructive operations to internal properties because it is
// guaranteed by Thunks that arguments objects are never reused as a function
// call creates a Thunk.
type Arguments struct {
	positionals   []*Thunk
	expandedList  *Thunk
	keywords      []KeywordArgument
	expandedDicts []*Thunk
}

// NewArguments creates a new Arguments.
func NewArguments(
	ps []PositionalArgument,
	ks []KeywordArgument,
	ds []*Thunk) Arguments {
	ts := make([]*Thunk, 0, len(ps))
	l := (*Thunk)(nil)

	for i, p := range ps {
		if p.expanded {
			l = mergePositionalArguments(ps[i:])
			break
		}

		ts = append(ts, p.value)
	}

	return Arguments{ts, l, ks, ds}
}

// NewPositionalArguments creates an Arguments which consists of unexpanded
// positional arguments.
func NewPositionalArguments(ts ...*Thunk) Arguments {
	return Arguments{ts, nil, nil, nil}
}

func mergePositionalArguments(ps []PositionalArgument) *Thunk {
	t := EmptyList

	// Optimization for a common pattern of (func a b c ... ..xs).
	// Note that Merge is O(n) but Prepend is O(1).
	if last := len(ps) - 1; ps[last].expanded {
		t = ps[last].value
		ps = ps[:last]
	}

	for i := len(ps) - 1; i >= 0; i-- {
		p := ps[i]

		if p.expanded {
			t = PApp(Merge, p.value, t)
		} else {
			t = PApp(Prepend, p.value, t)
		}
	}

	return t
}

func (args *Arguments) nextPositional() *Thunk {
	if len(args.positionals) != 0 {
		t := args.positionals[0]
		args.positionals = args.positionals[1:]
		return t
	}

	if args.expandedList == nil {
		return nil
	}

	l := args.expandedList
	args.expandedList = PApp(Rest, l)
	return PApp(First, l)
}

func (args *Arguments) restPositionals() *Thunk {
	ts := args.positionals
	l := args.expandedList
	args.positionals = nil
	args.expandedList = nil

	if l == nil {
		return NewList(ts...)
	} else if len(ts) == 0 {
		return l
	}

	return PApp(Prepend, append(ts, l)...)
}

func (args *Arguments) searchKeyword(s string) *Thunk {
	for i, k := range args.keywords {
		if s == k.name {
			args.keywords = append(args.keywords[:i], args.keywords[i+1:]...)
			return k.value
		}
	}

	for i, t := range args.expandedDicts {
		v := t.Eval()
		d, ok := v.(DictionaryType)

		if !ok {
			return NotDictionaryError(v)
		}

		k := StringType(s)

		// Using DictionaryType.{Search,Remove} methods is safe here
		// because the key is always StringType.
		if v, ok := d.Search(k); ok {
			args.expandedDicts = append([]*Thunk{}, args.expandedDicts...)
			args.expandedDicts[i] = Normal(d.Remove(k))
			return v
		}
	}

	return nil
}

func (args *Arguments) restKeywords() *Thunk {
	ks := args.keywords
	ds := args.expandedDicts
	args.keywords = nil
	args.expandedDicts = nil

	d := emptyDictionary

	for _, k := range ks {
		v := d.insert(StringType(k.name), k.value)
		var ok bool
		d, ok = v.(DictionaryType)

		if !ok {
			return NotDictionaryError(v)
		}
	}

	return PApp(Merge, append([]*Thunk{Normal(d)}, ds...)...)
}

// Merge merges 2 sets of arguments into one.
func (args Arguments) Merge(old Arguments) Arguments {
	ks := append(args.keywords, old.keywords...)
	ds := append(args.expandedDicts, old.expandedDicts...)

	if args.expandedList == nil {
		return Arguments{append(args.positionals, old.positionals...), old.expandedList, ks, ds}
	}

	l := EmptyList

	if old.expandedList != nil {
		l = old.expandedList
	}

	return Arguments{
		args.positionals,
		PApp(Merge, args.expandedList, PApp(Prepend, append(old.positionals, l)...)),
		ks,
		ds,
	}
}

func (args Arguments) empty() *Thunk {
	if len(args.positionals) > 0 {
		return argumentError("%d positional arguments are left", len(args.positionals))
	}

	// Testing args.expandedList is impossible because we cannot know its length
	// without evaluating it.

	n := 0

	for _, t := range args.expandedDicts {
		v := t.Eval()
		d, ok := v.(DictionaryType)

		if !ok {
			return NotDictionaryError(v)
		}

		n += d.Size()
	}

	if n != 0 || args.keywords != nil && len(args.keywords) > 0 {
		return argumentError("%d keyword arguments are left", len(args.keywords)+n)
	}

	return nil
}
<|endoftext|>


<commit_before>package core

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestDumpFail(t *testing.T) {
	for _, th := range []*Thunk{
		OutOfRangeError(),
	} {
		v := PApp(Dump, th).Eval()
		t.Log(v)

		if _, ok := v.(ErrorType); !ok {
			t.Fail()
		}
	}
}

func TestInternalStrictDumpPanic(t *testing.T) {
	defer func() {
		assert.NotEqual(t, nil, recover())
	}()

	strictDump(nil)
}

func TestInternalStrictDumpFail(t *testing.T) {
	for _, th := range []*Thunk{
		NewList(OutOfRangeError()),
		NewDictionary([]Value{Nil.Eval()}, []*Thunk{OutOfRangeError()})} {
		if _, err := strictDump(th.Eval()); err == nil {
			t.Fail()
		}
	}
}

func TestStrictDump(t *testing.T) {
	for _, th := range []*Thunk{
		Nil,
		True,
		False,
		EmptyList,
		EmptyDictionary,
		NewNumber(42),
		NewString("foo"),
		NewOutput(Nil),
	} {
		s, err := StrictDump(th.Eval())
		assert.NotEqual(t, "", s)
		assert.Equal(t, (*Thunk)(nil), err)
	}
}

func TestEqualFail(t *testing.T) {
	for _, ts := range [][]*Thunk{
		{OutOfRangeError(), Nil},
		{True, True, OutOfRangeError()},
	} {
		_, ok := PApp(Equal, ts...).Eval().(ErrorType)
		assert.True(t, ok)
	}
}

func TestIdentity(t *testing.T) {
	for _, th := range []*Thunk{Nil, NewNumber(42), True, False, NewString("foo")} {
		assert.True(t, testEqual(PApp(identity, th), th))
	}
}

func TestTypeOf(t *testing.T) {
	for _, test := range []struct {
		typ   string
		thunk *Thunk
	}{
		{"nil", Nil},
		{"list", NewList()},
		{"list", EmptyList},
		{"bool", True},
		{"number", NewNumber(123)},
		{"string", NewString("foo")},
		{"dict", NewDictionary(nil, nil)},
		{"error", NewError("MyError", "This is error.")},
		{"function", identity},
		{"function", PApp(Partial, identity)},
	} {
		v := PApp(TypeOf, test.thunk).Eval()
		t.Log(v)
		assert.Equal(t, test.typ, string(v.(StringType)))
	}
}

func TestTypeOfFail(t *testing.T) {
	defer func() {
		r := recover()
		assert.NotEqual(t, nil, r)
		_, ok := r.(error)
		assert.True(t, ok)
	}()

	PApp(TypeOf, Normal("foo")).Eval()
}
<commit_msg>Test typeOf function with output<commit_after>package core

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestDumpFail(t *testing.T) {
	for _, th := range []*Thunk{
		OutOfRangeError(),
	} {
		v := PApp(Dump, th).Eval()
		t.Log(v)

		if _, ok := v.(ErrorType); !ok {
			t.Fail()
		}
	}
}

func TestInternalStrictDumpPanic(t *testing.T) {
	defer func() {
		assert.NotEqual(t, nil, recover())
	}()

	strictDump(nil)
}

func TestInternalStrictDumpFail(t *testing.T) {
	for _, th := range []*Thunk{
		NewList(OutOfRangeError()),
		NewDictionary([]Value{Nil.Eval()}, []*Thunk{OutOfRangeError()})} {
		if _, err := strictDump(th.Eval()); err == nil {
			t.Fail()
		}
	}
}

func TestStrictDump(t *testing.T) {
	for _, th := range []*Thunk{
		Nil,
		True,
		False,
		EmptyList,
		EmptyDictionary,
		NewNumber(42),
		NewString("foo"),
		NewOutput(Nil),
	} {
		s, err := StrictDump(th.Eval())
		assert.NotEqual(t, "", s)
		assert.Equal(t, (*Thunk)(nil), err)
	}
}

func TestEqualFail(t *testing.T) {
	for _, ts := range [][]*Thunk{
		{OutOfRangeError(), Nil},
		{True, True, OutOfRangeError()},
	} {
		_, ok := PApp(Equal, ts...).Eval().(ErrorType)
		assert.True(t, ok)
	}
}

func TestIdentity(t *testing.T) {
	for _, th := range []*Thunk{Nil, NewNumber(42), True, False, NewString("foo")} {
		assert.True(t, testEqual(PApp(identity, th), th))
	}
}

func TestTypeOf(t *testing.T) {
	for _, test := range []struct {
		typ   string
		thunk *Thunk
	}{
		{"nil", Nil},
		{"list", NewList()},
		{"list", EmptyList},
		{"bool", True},
		{"number", NewNumber(123)},
		{"string", NewString("foo")},
		{"dict", NewDictionary(nil, nil)},
		{"error", NewError("MyError", "This is error.")},
		{"function", identity},
		{"function", PApp(Partial, identity)},
	} {
		v := PApp(TypeOf, test.thunk).Eval()
		t.Log(v)
		assert.Equal(t, test.typ, string(v.(StringType)))
	}
}

func TestTypeOfError(t *testing.T) {
	v := PApp(impureFunction, NewNumber(42)).Eval()
	_, ok := v.(ErrorType)
	t.Log(v)
	assert.True(t, ok)
}

func TestTypeOfFail(t *testing.T) {
	defer func() {
		r := recover()
		assert.NotEqual(t, nil, r)
		_, ok := r.(error)
		assert.True(t, ok)
	}()

	PApp(TypeOf, Normal("foo")).Eval()
}
<|endoftext|>


<commit_before>package std

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/tisp-lang/tisp/src/lib/core"
)

func TestEqualTrue(t *testing.T) {
	for _, ts := range [][]*core.Thunk{
		{},
		{core.True},
		{core.True, core.True},
		{core.Nil, core.Nil},
		{core.NewNumber(42), core.NewNumber(42)},
		{core.NewNumber(42), core.NewNumber(42), core.NewNumber(42)},
	} {
		assert.True(t, bool(core.PApp(Equal, ts...).Eval().(core.BoolType)))
	}
}

func TestEqualFalse(t *testing.T) {
	for _, ts := range [][]*core.Thunk{
		{core.True, core.False},
		{core.NewNumber(0), core.NewNumber(42)},
		{core.NewNumber(0), core.NewNumber(0), core.NewNumber(42)},
		{core.NewNumber(0), core.NewNumber(42), core.NewNumber(42)},
	} {
		assert.True(t, !bool(core.PApp(Equal, ts...).Eval().(core.BoolType)))
	}
}
<commit_msg>Test error cases of equal function<commit_after>package std

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/tisp-lang/tisp/src/lib/core"
)

func TestEqualTrue(t *testing.T) {
	for _, ts := range [][]*core.Thunk{
		{},
		{core.True},
		{core.True, core.True},
		{core.Nil, core.Nil},
		{core.NewNumber(42), core.NewNumber(42)},
		{core.NewNumber(42), core.NewNumber(42), core.NewNumber(42)},
	} {
		assert.True(t, bool(core.PApp(Equal, ts...).Eval().(core.BoolType)))
	}
}

func TestEqualFalse(t *testing.T) {
	for _, ts := range [][]*core.Thunk{
		{core.True, core.False},
		{core.NewNumber(0), core.NewNumber(42)},
		{core.NewNumber(0), core.NewNumber(0), core.NewNumber(42)},
		{core.NewNumber(0), core.NewNumber(42), core.NewNumber(42)},
	} {
		assert.True(t, !bool(core.PApp(Equal, ts...).Eval().(core.BoolType)))
	}
}

func TestEqualFail(t *testing.T) {
	for _, th := range []*core.Thunk{
		core.App(
			Equal,
			core.NewArguments(
				[]core.PositionalArgument{core.NewPositionalArgument(core.OutOfRangeError(), true)},
				nil,
				nil)),
		core.App(
			Equal,
			core.NewArguments(
				[]core.PositionalArgument{
					core.NewPositionalArgument(core.Nil, false),
					core.NewPositionalArgument(core.OutOfRangeError(), true),
				},
				nil,
				nil)),
		core.App(
			Equal,
			core.NewArguments(
				[]core.PositionalArgument{
					core.NewPositionalArgument(core.Nil, false),
					core.NewPositionalArgument(core.NewList(core.OutOfRangeError()), true),
				},
				nil,
				nil)),
	} {
		_, ok := th.Eval().(core.ErrorType)
		assert.True(t, ok)
	}
}
<|endoftext|>


<commit_before>package autostart

import (
	"os"
	"os/exec"
	"path/filepath"
	"text/template"
)

const jobTemplate = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>{{.Name}}</string>
    <key>ProgramArguments</key>
      <array>
        {{range .Exec -}}
        <string>{{.}}</string>
        {{end}}
      </array>
    <key>RunAtLoad</key>
    <true/>
  </dict>
</plist>`

var launchDir string

func init() {
	launchDir = filepath.Join(os.Getenv("HOME"), "Library", "LaunchAgents")
}

func (a *App) path() string {
	return filepath.Join(launchDir, a.Name+".plist")
}

// IsEnabled Check is app enabled startup.
func (a *App) IsEnabled() bool {
	_, err := os.Stat(a.path())
	return !os.IsNotExist(err)
}

// Enable this app on startup.
func (a *App) Enable() error {
	t := template.Must(template.New("job").Parse(jobTemplate))

	f, err := os.Create(a.path())
	if err != nil {
		return err
	}
	defer f.Close()

	if err := t.Execute(f, a); err != nil {
		return err
	}

	cmd := exec.Command("launchctl", "load", a.path())
	if err := cmd.Run(); err != nil {
		return err
	}

	return nil
}

// Disable this app on startup.
func (a *App) Disable() error {
	cmd := exec.Command("launchctl", "unload", a.path())
	if err := cmd.Run(); err != nil {
		return err
	}

	return os.Remove(a.path())
}
<commit_msg>remove unnecessary command<commit_after>package autostart

import (
	"os"
	"path/filepath"
	"text/template"
)

const jobTemplate = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>{{.Name}}</string>
    <key>ProgramArguments</key>
      <array>
        {{range .Exec -}}
        <string>{{.}}</string>
        {{end}}
      </array>
    <key>RunAtLoad</key>
    <true/>
  </dict>
</plist>`

var launchDir string

func init() {
	launchDir = filepath.Join(os.Getenv("HOME"), "Library", "LaunchAgents")
}

func (a *App) path() string {
	return filepath.Join(launchDir, a.Name+".plist")
}

// IsEnabled Check is app enabled startup.
func (a *App) IsEnabled() bool {
	_, err := os.Stat(a.path())
	return !os.IsNotExist(err)
}

// Enable this app on startup.
func (a *App) Enable() error {
	t := template.Must(template.New("job").Parse(jobTemplate))

	f, err := os.Create(a.path())
	if err != nil {
		return err
	}
	defer f.Close()

	if err := t.Execute(f, a); err != nil {
		return err
	}

	return nil
}

// Disable this app on startup.
func (a *App) Disable() error {

	return os.Remove(a.path())
}
<|endoftext|>


<commit_before>package azurerm

import (
	"crypto/sha1"
	"encoding/base64"
	"encoding/hex"
	"fmt"
	"log"
	"reflect"
	"strings"
	"sync"

	"github.com/Azure/azure-sdk-for-go/arm/resources/resources"
	"github.com/hashicorp/go-multierror"
	"github.com/hashicorp/terraform/helper/mutexkv"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/terraform"
	riviera "github.com/jen20/riviera/azure"
)

// Provider returns a terraform.ResourceProvider.
func Provider() terraform.ResourceProvider {
	var p *schema.Provider
	p = &schema.Provider{
		Schema: map[string]*schema.Schema{
			"subscription_id": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_SUBSCRIPTION_ID", ""),
			},

			"client_id": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_CLIENT_ID", ""),
			},

			"client_secret": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_CLIENT_SECRET", ""),
			},

			"tenant_id": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_TENANT_ID", ""),
			},

			"environment": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_ENVIRONMENT", "public"),
			},

			"skip_provider_registration": {
				Type:        schema.TypeBool,
				Optional:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_SKIP_PROVIDER_REGISTRATION", false),
			},
		},

		DataSourcesMap: map[string]*schema.Resource{
			"azurerm_client_config":  dataSourceArmClientConfig(),
			"azurerm_resource_group": dataSourceArmResourceGroup(),
			"azurerm_public_ip":      dataSourceArmPublicIP(),
			"azurerm_managed_disk":   dataSourceArmManagedDisk(),
		},

		ResourcesMap: map[string]*schema.Resource{
			// These resources use the Azure ARM SDK
			"azurerm_application_insights": resourceArmApplicationInsights(),
			"azurerm_availability_set":     resourceArmAvailabilitySet(),
			"azurerm_cdn_endpoint":         resourceArmCdnEndpoint(),
			"azurerm_cdn_profile":          resourceArmCdnProfile(),
			"azurerm_container_registry":   resourceArmContainerRegistry(),
			"azurerm_container_service":    resourceArmContainerService(),
			"azurerm_cosmosdb_account":     resourceArmCosmosDBAccount(),

			"azurerm_dns_a_record":     resourceArmDnsARecord(),
			"azurerm_dns_aaaa_record":  resourceArmDnsAAAARecord(),
			"azurerm_dns_cname_record": resourceArmDnsCNameRecord(),
			"azurerm_dns_mx_record":    resourceArmDnsMxRecord(),
			"azurerm_dns_ns_record":    resourceArmDnsNsRecord(),
			"azurerm_dns_ptr_record":   resourceArmDnsPtrRecord(),
			"azurerm_dns_srv_record":   resourceArmDnsSrvRecord(),
			"azurerm_dns_txt_record":   resourceArmDnsTxtRecord(),
			"azurerm_dns_zone":         resourceArmDnsZone(),

			"azurerm_eventgrid_topic":             resourceArmEventGridTopic(),
			"azurerm_eventhub":                    resourceArmEventHub(),
			"azurerm_eventhub_authorization_rule": resourceArmEventHubAuthorizationRule(),
			"azurerm_eventhub_consumer_group":     resourceArmEventHubConsumerGroup(),
			"azurerm_eventhub_namespace":          resourceArmEventHubNamespace(),
			"azurerm_express_route_circuit":       resourceArmExpressRouteCircuit(),

			"azurerm_image":            resourceArmImage(),
			"azurerm_key_vault":        resourceArmKeyVault(),
			"azurerm_key_vault_secret": resourceArmKeyVaultSecret(),

			"azurerm_lb":                      resourceArmLoadBalancer(),
			"azurerm_lb_backend_address_pool": resourceArmLoadBalancerBackendAddressPool(),
			"azurerm_lb_nat_rule":             resourceArmLoadBalancerNatRule(),
			"azurerm_lb_nat_pool":             resourceArmLoadBalancerNatPool(),
			"azurerm_lb_probe":                resourceArmLoadBalancerProbe(),
			"azurerm_lb_rule":                 resourceArmLoadBalancerRule(),
			"azurerm_local_network_gateway":   resourceArmLocalNetworkGateway(),

			"azurerm_managed_disk":           resourceArmManagedDisk(),
			"azurerm_network_interface":      resourceArmNetworkInterface(),
			"azurerm_network_security_group": resourceArmNetworkSecurityGroup(),
			"azurerm_network_security_rule":  resourceArmNetworkSecurityRule(),
			"azurerm_public_ip":              resourceArmPublicIp(),

			"azurerm_redis_cache": resourceArmRedisCache(),
			"azurerm_route":       resourceArmRoute(),
			"azurerm_route_table": resourceArmRouteTable(),

			"azurerm_servicebus_namespace":    resourceArmServiceBusNamespace(),
			"azurerm_servicebus_queue":        resourceArmServiceBusQueue(),
			"azurerm_servicebus_subscription": resourceArmServiceBusSubscription(),
			"azurerm_servicebus_topic":        resourceArmServiceBusTopic(),
			"azurerm_sql_elasticpool":         resourceArmSqlElasticPool(),
			"azurerm_storage_account":         resourceArmStorageAccount(),
			"azurerm_storage_blob":            resourceArmStorageBlob(),
			"azurerm_storage_container":       resourceArmStorageContainer(),
			"azurerm_storage_share":           resourceArmStorageShare(),
			"azurerm_storage_queue":           resourceArmStorageQueue(),
			"azurerm_storage_table":           resourceArmStorageTable(),
			"azurerm_subnet":                  resourceArmSubnet(),

			"azurerm_template_deployment":       resourceArmTemplateDeployment(),
			"azurerm_traffic_manager_endpoint":  resourceArmTrafficManagerEndpoint(),
			"azurerm_traffic_manager_profile":   resourceArmTrafficManagerProfile(),
			"azurerm_virtual_machine_extension": resourceArmVirtualMachineExtensions(),
			"azurerm_virtual_machine":           resourceArmVirtualMachine(),
			"azurerm_virtual_machine_scale_set": resourceArmVirtualMachineScaleSet(),
			"azurerm_virtual_network":           resourceArmVirtualNetwork(),
			"azurerm_virtual_network_peering":   resourceArmVirtualNetworkPeering(),

			"azurerm_app_service_plan": resourceArmAppServicePlan(),

			// These resources use the Riviera SDK
			"azurerm_resource_group":    resourceArmResourceGroup(),
			"azurerm_search_service":    resourceArmSearchService(),
			"azurerm_sql_database":      resourceArmSqlDatabase(),
			"azurerm_sql_firewall_rule": resourceArmSqlFirewallRule(),
			"azurerm_sql_server":        resourceArmSqlServer(),
		},
	}

	p.ConfigureFunc = providerConfigure(p)

	return p
}

// Config is the configuration structure used to instantiate a
// new Azure management client.
type Config struct {
	ManagementURL string

	SubscriptionID           string
	ClientID                 string
	ClientSecret             string
	TenantID                 string
	Environment              string
	SkipProviderRegistration bool

	validateCredentialsOnce sync.Once
}

func (c *Config) validate() error {
	var err *multierror.Error

	if c.SubscriptionID == "" {
		err = multierror.Append(err, fmt.Errorf("Subscription ID must be configured for the AzureRM provider"))
	}
	if c.ClientID == "" {
		err = multierror.Append(err, fmt.Errorf("Client ID must be configured for the AzureRM provider"))
	}
	if c.ClientSecret == "" {
		err = multierror.Append(err, fmt.Errorf("Client Secret must be configured for the AzureRM provider"))
	}
	if c.TenantID == "" {
		err = multierror.Append(err, fmt.Errorf("Tenant ID must be configured for the AzureRM provider"))
	}
	if c.Environment == "" {
		err = multierror.Append(err, fmt.Errorf("Environment must be configured for the AzureRM provider"))
	}

	return err.ErrorOrNil()
}

func providerConfigure(p *schema.Provider) schema.ConfigureFunc {
	return func(d *schema.ResourceData) (interface{}, error) {
		config := &Config{
			SubscriptionID:           d.Get("subscription_id").(string),
			ClientID:                 d.Get("client_id").(string),
			ClientSecret:             d.Get("client_secret").(string),
			TenantID:                 d.Get("tenant_id").(string),
			Environment:              d.Get("environment").(string),
			SkipProviderRegistration: d.Get("skip_provider_registration").(bool),
		}

		if err := config.validate(); err != nil {
			return nil, err
		}

		client, err := config.getArmClient()
		if err != nil {
			return nil, err
		}

		client.StopContext = p.StopContext()

		// replaces the context between tests
		p.MetaReset = func() error {
			client.StopContext = p.StopContext()
			return nil
		}

		// List all the available providers and their registration state to avoid unnecessary
		// requests. This also lets us check if the provider credentials are correct.
		providerList, err := client.providers.List(nil, "")
		if err != nil {
			return nil, fmt.Errorf("Unable to list provider registration status, it is possible that this is due to invalid "+
				"credentials or the service principal does not have permission to use the Resource Manager API, Azure "+
				"error: %s", err)
		}

		if !config.SkipProviderRegistration {
			err = registerAzureResourceProvidersWithSubscription(*providerList.Value, client.providers)
			if err != nil {
				return nil, err
			}
		}

		return client, nil
	}
}

func registerProviderWithSubscription(providerName string, client resources.ProvidersClient) error {
	_, err := client.Register(providerName)
	if err != nil {
		return fmt.Errorf("Cannot register provider %s with Azure Resource Manager: %s.", providerName, err)
	}

	return nil
}

var providerRegistrationOnce sync.Once

// registerAzureResourceProvidersWithSubscription uses the providers client to register
// all Azure resource providers which the Terraform provider may require (regardless of
// whether they are actually used by the configuration or not). It was confirmed by Microsoft
// that this is the approach their own internal tools also take.
func registerAzureResourceProvidersWithSubscription(providerList []resources.Provider, client resources.ProvidersClient) error {
	var err error
	providerRegistrationOnce.Do(func() {
		providers := map[string]struct{}{
			"Microsoft.Cache":             struct{}{},
			"Microsoft.Cdn":               struct{}{},
			"Microsoft.Compute":           struct{}{},
			"Microsoft.ContainerRegistry": struct{}{},
			"Microsoft.ContainerService":  struct{}{},
			"Microsoft.DocumentDB":        struct{}{},
			"Microsoft.EventGrid":         struct{}{},
			"Microsoft.EventHub":          struct{}{},
			"Microsoft.KeyVault":          struct{}{},
			"Microsoft.Insights":          struct{}{},
			"Microsoft.Network":           struct{}{},
			"Microsoft.Resources":         struct{}{},
			"Microsoft.Search":            struct{}{},
			"Microsoft.ServiceBus":        struct{}{},
			"Microsoft.Sql":               struct{}{},
			"Microsoft.Storage":           struct{}{},
		}

		// filter out any providers already registered
		for _, p := range providerList {
			if _, ok := providers[*p.Namespace]; !ok {
				continue
			}

			if strings.ToLower(*p.RegistrationState) == "registered" {
				log.Printf("[DEBUG] Skipping provider registration for namespace %s\n", *p.Namespace)
				delete(providers, *p.Namespace)
			}
		}

		var wg sync.WaitGroup
		wg.Add(len(providers))
		for providerName := range providers {
			go func(p string) {
				defer wg.Done()
				log.Printf("[DEBUG] Registering provider with namespace %s\n", p)
				if innerErr := registerProviderWithSubscription(p, client); err != nil {
					err = innerErr
				}
			}(providerName)
		}
		wg.Wait()
	})

	return err
}

// armMutexKV is the instance of MutexKV for ARM resources
var armMutexKV = mutexkv.NewMutexKV()

func azureStateRefreshFunc(resourceURI string, client *ArmClient, command riviera.APICall) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		req := client.rivieraClient.NewRequestForURI(resourceURI)
		req.Command = command

		res, err := req.Execute()
		if err != nil {
			return nil, "", fmt.Errorf("Error executing %T command in azureStateRefreshFunc", req.Command)
		}

		var value reflect.Value
		if reflect.ValueOf(res.Parsed).Kind() == reflect.Ptr {
			value = reflect.ValueOf(res.Parsed).Elem()
		} else {
			value = reflect.ValueOf(res.Parsed)
		}

		for i := 0; i < value.NumField(); i++ { // iterates through every struct type field
			tag := value.Type().Field(i).Tag // returns the tag string
			tagValue := tag.Get("mapstructure")
			if tagValue == "provisioningState" {
				return res.Parsed, value.Field(i).Elem().String(), nil
			}
		}

		panic(fmt.Errorf("azureStateRefreshFunc called on structure %T with no mapstructure:provisioningState tag. This is a bug", res.Parsed))
	}
}

// Resource group names can be capitalised, but we store them in lowercase.
// Use a custom diff function to avoid creation of new resources.
func resourceAzurermResourceGroupNameDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
	return strings.ToLower(old) == strings.ToLower(new)
}

// ignoreCaseDiffSuppressFunc is a DiffSuppressFunc from helper/schema that is
// used to ignore any case-changes in a return value.
func ignoreCaseDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool {
	return strings.ToLower(old) == strings.ToLower(new)
}

// ignoreCaseStateFunc is a StateFunc from helper/schema that converts the
// supplied value to lower before saving to state for consistency.
func ignoreCaseStateFunc(val interface{}) string {
	return strings.ToLower(val.(string))
}

func userDataStateFunc(v interface{}) string {
	switch s := v.(type) {
	case string:
		s = base64Encode(s)
		hash := sha1.Sum([]byte(s))
		return hex.EncodeToString(hash[:])
	default:
		return ""
	}
}

// base64Encode encodes data if the input isn't already encoded using
// base64.StdEncoding.EncodeToString. If the input is already base64 encoded,
// return the original input unchanged.
func base64Encode(data string) string {
	// Check whether the data is already Base64 encoded; don't double-encode
	if isBase64Encoded(data) {
		return data
	}
	// data has not been encoded encode and return
	return base64.StdEncoding.EncodeToString([]byte(data))
}

func isBase64Encoded(data string) bool {
	_, err := base64.StdEncoding.DecodeString(data)
	return err == nil
}
<commit_msg>Fixing the casing on the resource provider registration<commit_after>package azurerm

import (
	"crypto/sha1"
	"encoding/base64"
	"encoding/hex"
	"fmt"
	"log"
	"reflect"
	"strings"
	"sync"

	"github.com/Azure/azure-sdk-for-go/arm/resources/resources"
	"github.com/hashicorp/go-multierror"
	"github.com/hashicorp/terraform/helper/mutexkv"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/terraform"
	riviera "github.com/jen20/riviera/azure"
)

// Provider returns a terraform.ResourceProvider.
func Provider() terraform.ResourceProvider {
	var p *schema.Provider
	p = &schema.Provider{
		Schema: map[string]*schema.Schema{
			"subscription_id": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_SUBSCRIPTION_ID", ""),
			},

			"client_id": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_CLIENT_ID", ""),
			},

			"client_secret": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_CLIENT_SECRET", ""),
			},

			"tenant_id": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_TENANT_ID", ""),
			},

			"environment": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_ENVIRONMENT", "public"),
			},

			"skip_provider_registration": {
				Type:        schema.TypeBool,
				Optional:    true,
				DefaultFunc: schema.EnvDefaultFunc("ARM_SKIP_PROVIDER_REGISTRATION", false),
			},
		},

		DataSourcesMap: map[string]*schema.Resource{
			"azurerm_client_config":  dataSourceArmClientConfig(),
			"azurerm_resource_group": dataSourceArmResourceGroup(),
			"azurerm_public_ip":      dataSourceArmPublicIP(),
			"azurerm_managed_disk":   dataSourceArmManagedDisk(),
		},

		ResourcesMap: map[string]*schema.Resource{
			// These resources use the Azure ARM SDK
			"azurerm_application_insights": resourceArmApplicationInsights(),
			"azurerm_availability_set":     resourceArmAvailabilitySet(),
			"azurerm_cdn_endpoint":         resourceArmCdnEndpoint(),
			"azurerm_cdn_profile":          resourceArmCdnProfile(),
			"azurerm_container_registry":   resourceArmContainerRegistry(),
			"azurerm_container_service":    resourceArmContainerService(),
			"azurerm_cosmosdb_account":     resourceArmCosmosDBAccount(),

			"azurerm_dns_a_record":     resourceArmDnsARecord(),
			"azurerm_dns_aaaa_record":  resourceArmDnsAAAARecord(),
			"azurerm_dns_cname_record": resourceArmDnsCNameRecord(),
			"azurerm_dns_mx_record":    resourceArmDnsMxRecord(),
			"azurerm_dns_ns_record":    resourceArmDnsNsRecord(),
			"azurerm_dns_ptr_record":   resourceArmDnsPtrRecord(),
			"azurerm_dns_srv_record":   resourceArmDnsSrvRecord(),
			"azurerm_dns_txt_record":   resourceArmDnsTxtRecord(),
			"azurerm_dns_zone":         resourceArmDnsZone(),

			"azurerm_eventgrid_topic":             resourceArmEventGridTopic(),
			"azurerm_eventhub":                    resourceArmEventHub(),
			"azurerm_eventhub_authorization_rule": resourceArmEventHubAuthorizationRule(),
			"azurerm_eventhub_consumer_group":     resourceArmEventHubConsumerGroup(),
			"azurerm_eventhub_namespace":          resourceArmEventHubNamespace(),
			"azurerm_express_route_circuit":       resourceArmExpressRouteCircuit(),

			"azurerm_image":            resourceArmImage(),
			"azurerm_key_vault":        resourceArmKeyVault(),
			"azurerm_key_vault_secret": resourceArmKeyVaultSecret(),

			"azurerm_lb":                      resourceArmLoadBalancer(),
			"azurerm_lb_backend_address_pool": resourceArmLoadBalancerBackendAddressPool(),
			"azurerm_lb_nat_rule":             resourceArmLoadBalancerNatRule(),
			"azurerm_lb_nat_pool":             resourceArmLoadBalancerNatPool(),
			"azurerm_lb_probe":                resourceArmLoadBalancerProbe(),
			"azurerm_lb_rule":                 resourceArmLoadBalancerRule(),
			"azurerm_local_network_gateway":   resourceArmLocalNetworkGateway(),

			"azurerm_managed_disk":           resourceArmManagedDisk(),
			"azurerm_network_interface":      resourceArmNetworkInterface(),
			"azurerm_network_security_group": resourceArmNetworkSecurityGroup(),
			"azurerm_network_security_rule":  resourceArmNetworkSecurityRule(),
			"azurerm_public_ip":              resourceArmPublicIp(),

			"azurerm_redis_cache": resourceArmRedisCache(),
			"azurerm_route":       resourceArmRoute(),
			"azurerm_route_table": resourceArmRouteTable(),

			"azurerm_servicebus_namespace":    resourceArmServiceBusNamespace(),
			"azurerm_servicebus_queue":        resourceArmServiceBusQueue(),
			"azurerm_servicebus_subscription": resourceArmServiceBusSubscription(),
			"azurerm_servicebus_topic":        resourceArmServiceBusTopic(),
			"azurerm_sql_elasticpool":         resourceArmSqlElasticPool(),
			"azurerm_storage_account":         resourceArmStorageAccount(),
			"azurerm_storage_blob":            resourceArmStorageBlob(),
			"azurerm_storage_container":       resourceArmStorageContainer(),
			"azurerm_storage_share":           resourceArmStorageShare(),
			"azurerm_storage_queue":           resourceArmStorageQueue(),
			"azurerm_storage_table":           resourceArmStorageTable(),
			"azurerm_subnet":                  resourceArmSubnet(),

			"azurerm_template_deployment":       resourceArmTemplateDeployment(),
			"azurerm_traffic_manager_endpoint":  resourceArmTrafficManagerEndpoint(),
			"azurerm_traffic_manager_profile":   resourceArmTrafficManagerProfile(),
			"azurerm_virtual_machine_extension": resourceArmVirtualMachineExtensions(),
			"azurerm_virtual_machine":           resourceArmVirtualMachine(),
			"azurerm_virtual_machine_scale_set": resourceArmVirtualMachineScaleSet(),
			"azurerm_virtual_network":           resourceArmVirtualNetwork(),
			"azurerm_virtual_network_peering":   resourceArmVirtualNetworkPeering(),

			"azurerm_app_service_plan": resourceArmAppServicePlan(),

			// These resources use the Riviera SDK
			"azurerm_resource_group":    resourceArmResourceGroup(),
			"azurerm_search_service":    resourceArmSearchService(),
			"azurerm_sql_database":      resourceArmSqlDatabase(),
			"azurerm_sql_firewall_rule": resourceArmSqlFirewallRule(),
			"azurerm_sql_server":        resourceArmSqlServer(),
		},
	}

	p.ConfigureFunc = providerConfigure(p)

	return p
}

// Config is the configuration structure used to instantiate a
// new Azure management client.
type Config struct {
	ManagementURL string

	SubscriptionID           string
	ClientID                 string
	ClientSecret             string
	TenantID                 string
	Environment              string
	SkipProviderRegistration bool

	validateCredentialsOnce sync.Once
}

func (c *Config) validate() error {
	var err *multierror.Error

	if c.SubscriptionID == "" {
		err = multierror.Append(err, fmt.Errorf("Subscription ID must be configured for the AzureRM provider"))
	}
	if c.ClientID == "" {
		err = multierror.Append(err, fmt.Errorf("Client ID must be configured for the AzureRM provider"))
	}
	if c.ClientSecret == "" {
		err = multierror.Append(err, fmt.Errorf("Client Secret must be configured for the AzureRM provider"))
	}
	if c.TenantID == "" {
		err = multierror.Append(err, fmt.Errorf("Tenant ID must be configured for the AzureRM provider"))
	}
	if c.Environment == "" {
		err = multierror.Append(err, fmt.Errorf("Environment must be configured for the AzureRM provider"))
	}

	return err.ErrorOrNil()
}

func providerConfigure(p *schema.Provider) schema.ConfigureFunc {
	return func(d *schema.ResourceData) (interface{}, error) {
		config := &Config{
			SubscriptionID:           d.Get("subscription_id").(string),
			ClientID:                 d.Get("client_id").(string),
			ClientSecret:             d.Get("client_secret").(string),
			TenantID:                 d.Get("tenant_id").(string),
			Environment:              d.Get("environment").(string),
			SkipProviderRegistration: d.Get("skip_provider_registration").(bool),
		}

		if err := config.validate(); err != nil {
			return nil, err
		}

		client, err := config.getArmClient()
		if err != nil {
			return nil, err
		}

		client.StopContext = p.StopContext()

		// replaces the context between tests
		p.MetaReset = func() error {
			client.StopContext = p.StopContext()
			return nil
		}

		// List all the available providers and their registration state to avoid unnecessary
		// requests. This also lets us check if the provider credentials are correct.
		providerList, err := client.providers.List(nil, "")
		if err != nil {
			return nil, fmt.Errorf("Unable to list provider registration status, it is possible that this is due to invalid "+
				"credentials or the service principal does not have permission to use the Resource Manager API, Azure "+
				"error: %s", err)
		}

		if !config.SkipProviderRegistration {
			err = registerAzureResourceProvidersWithSubscription(*providerList.Value, client.providers)
			if err != nil {
				return nil, err
			}
		}

		return client, nil
	}
}

func registerProviderWithSubscription(providerName string, client resources.ProvidersClient) error {
	_, err := client.Register(providerName)
	if err != nil {
		return fmt.Errorf("Cannot register provider %s with Azure Resource Manager: %s.", providerName, err)
	}

	return nil
}

var providerRegistrationOnce sync.Once

// registerAzureResourceProvidersWithSubscription uses the providers client to register
// all Azure resource providers which the Terraform provider may require (regardless of
// whether they are actually used by the configuration or not). It was confirmed by Microsoft
// that this is the approach their own internal tools also take.
func registerAzureResourceProvidersWithSubscription(providerList []resources.Provider, client resources.ProvidersClient) error {
	var err error
	providerRegistrationOnce.Do(func() {
		providers := map[string]struct{}{
			"Microsoft.Cache":             struct{}{},
			"Microsoft.Cdn":               struct{}{},
			"Microsoft.Compute":           struct{}{},
			"Microsoft.ContainerRegistry": struct{}{},
			"Microsoft.ContainerService":  struct{}{},
			"Microsoft.DocumentDB":        struct{}{},
			"Microsoft.EventGrid":         struct{}{},
			"Microsoft.EventHub":          struct{}{},
			"Microsoft.KeyVault":          struct{}{},
			"microsoft.insights":          struct{}{},
			"Microsoft.Network":           struct{}{},
			"Microsoft.Resources":         struct{}{},
			"Microsoft.Search":            struct{}{},
			"Microsoft.ServiceBus":        struct{}{},
			"Microsoft.Sql":               struct{}{},
			"Microsoft.Storage":           struct{}{},
		}

		// filter out any providers already registered
		for _, p := range providerList {
			if _, ok := providers[*p.Namespace]; !ok {
				continue
			}

			if strings.ToLower(*p.RegistrationState) == "registered" {
				log.Printf("[DEBUG] Skipping provider registration for namespace %s\n", *p.Namespace)
				delete(providers, *p.Namespace)
			}
		}

		var wg sync.WaitGroup
		wg.Add(len(providers))
		for providerName := range providers {
			go func(p string) {
				defer wg.Done()
				log.Printf("[DEBUG] Registering provider with namespace %s\n", p)
				if innerErr := registerProviderWithSubscription(p, client); err != nil {
					err = innerErr
				}
			}(providerName)
		}
		wg.Wait()
	})

	return err
}

// armMutexKV is the instance of MutexKV for ARM resources
var armMutexKV = mutexkv.NewMutexKV()

func azureStateRefreshFunc(resourceURI string, client *ArmClient, command riviera.APICall) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		req := client.rivieraClient.NewRequestForURI(resourceURI)
		req.Command = command

		res, err := req.Execute()
		if err != nil {
			return nil, "", fmt.Errorf("Error executing %T command in azureStateRefreshFunc", req.Command)
		}

		var value reflect.Value
		if reflect.ValueOf(res.Parsed).Kind() == reflect.Ptr {
			value = reflect.ValueOf(res.Parsed).Elem()
		} else {
			value = reflect.ValueOf(res.Parsed)
		}

		for i := 0; i < value.NumField(); i++ { // iterates through every struct type field
			tag := value.Type().Field(i).Tag // returns the tag string
			tagValue := tag.Get("mapstructure")
			if tagValue == "provisioningState" {
				return res.Parsed, value.Field(i).Elem().String(), nil
			}
		}

		panic(fmt.Errorf("azureStateRefreshFunc called on structure %T with no mapstructure:provisioningState tag. This is a bug", res.Parsed))
	}
}

// Resource group names can be capitalised, but we store them in lowercase.
// Use a custom diff function to avoid creation of new resources.
func resourceAzurermResourceGroupNameDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
	return strings.ToLower(old) == strings.ToLower(new)
}

// ignoreCaseDiffSuppressFunc is a DiffSuppressFunc from helper/schema that is
// used to ignore any case-changes in a return value.
func ignoreCaseDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool {
	return strings.ToLower(old) == strings.ToLower(new)
}

// ignoreCaseStateFunc is a StateFunc from helper/schema that converts the
// supplied value to lower before saving to state for consistency.
func ignoreCaseStateFunc(val interface{}) string {
	return strings.ToLower(val.(string))
}

func userDataStateFunc(v interface{}) string {
	switch s := v.(type) {
	case string:
		s = base64Encode(s)
		hash := sha1.Sum([]byte(s))
		return hex.EncodeToString(hash[:])
	default:
		return ""
	}
}

// base64Encode encodes data if the input isn't already encoded using
// base64.StdEncoding.EncodeToString. If the input is already base64 encoded,
// return the original input unchanged.
func base64Encode(data string) string {
	// Check whether the data is already Base64 encoded; don't double-encode
	if isBase64Encoded(data) {
		return data
	}
	// data has not been encoded encode and return
	return base64.StdEncoding.EncodeToString([]byte(data))
}

func isBase64Encoded(data string) bool {
	_, err := base64.StdEncoding.DecodeString(data)
	return err == nil
}
<|endoftext|>


<commit_before>// 28 october 2014

package ui

import (
	"strconv"
	"unsafe"
)

// #include "winapi_windows.h"
import "C"

// TODO do we have to manually monitor user changes to the edit control?
// TODO WS_EX_CLIENTEDGE on the updown?

type spinbox struct {
	hwndEdit			C.HWND
	hwndUpDown		C.HWND
	changed			*event
	// updown state
	updownVisible		bool
	// keep these here to avoid having to get them out
	value			int
	min				int
	max				int
}

func newSpinbox(min int, max int) Spinbox {
	s := new(spinbox)
	s.hwndEdit = C.newControl(editclass,
		C.textfieldStyle | C.ES_NUMBER,
		C.textfieldExtStyle)
	s.changed = newEvent()
	s.updownVisible = true		// initially shown
	s.min = min
	s.max = max
	s.value = s.min
	s.remakeUpDown()
	C.setSpinboxEditSubclass(s.hwndEdit, unsafe.Pointer(s))
	return s
}

func (s *spinbox) cap() {
	if s.value < s.min {
		s.value = s.min
	}
	if s.value > s.max {
		s.value = s.max
	}
}

func (s *spinbox) Value() int {
	return s.value
}

func (s *spinbox) SetValue(value int) {
	// UDM_SETPOS32 is documented to do what we want, but since we're keeping a copy of value we need to do it anyway
	s.value = value
	s.cap()
	C.SendMessageW(s.hwndUpDown, C.UDM_SETPOS32, 0, C.LPARAM(s.value))
}

func (s *spinbox) OnChanged(e func()) {
	s.changed.set(e)
}

//export spinboxUpDownClicked
func spinboxUpDownClicked(data unsafe.Pointer, nud *C.NMUPDOWN) {
	// this is where we do custom increments
	s := (*spinbox)(data)
	s.value = int(nud.iPos + nud.iDelta)
	// this can go above or below the bounds (the spinbox only rejects invalid values after the UDN_DELTAPOS notification is processed)
	// because we have a copy of the value, we need to fix that here
	s.cap()
	s.changed.fire()
}

//export spinboxEditChanged
func spinboxEditChanged(data unsafe.Pointer) {
	// we're basically on our own here
	s := (*spinbox)(unsafe.Pointer(data))
	// this basically does what OS X does: values too low get clamped to the minimum, values too high get clamped to the maximum, and deleting everything clamps to the minimum
	value, err := strconv.Atoi(getWindowText(s.hwndEdit))
	if err != nil {
		// best we can do fo rnow in this case :S
		// a partial atoi() like in C would be more optimal
		// it handles the deleting everything case just fine
		value = s.min
	}
	s.value = value
	s.cap()
	C.SendMessageW(s.hwndUpDown, C.UDM_SETPOS32, 0, C.LPARAM(s.value))
	// TODO position the insertion caret at the end (or wherever is appropriate)
	s.changed.fire()
}

func (s *spinbox) setParent(p *controlParent) {
	C.controlSetParent(s.hwndEdit, p.hwnd)
	C.controlSetParent(s.hwndUpDown, p.hwnd)
}

// an up-down control will only properly position itself the first time
// stupidly, there are no messages to force a size calculation, nor can I seem to reset the buddy window to force a new position
// alas, we have to make a new up/down control each time :(
// TODO we'll need to store a copy of the current position and range for this
func (s *spinbox) remakeUpDown() {
	// destroying the previous one, setting the parent properly, and subclassing are handled here
	s.hwndUpDown = C.newUpDown(s.hwndUpDown, unsafe.Pointer(s))
	// for this to work, hwndUpDown needs to have rect [0 0 0 0]
	C.moveWindow(s.hwndUpDown, 0, 0, 0, 0)
	C.SendMessageW(s.hwndUpDown, C.UDM_SETBUDDY, C.WPARAM(uintptr(unsafe.Pointer(s.hwndEdit))), 0)
	C.SendMessageW(s.hwndUpDown, C.UDM_SETRANGE32, C.WPARAM(s.min), C.LPARAM(s.max))
	C.SendMessageW(s.hwndUpDown, C.UDM_SETPOS32, 0, C.LPARAM(s.value))
	if s.updownVisible {
		C.ShowWindow(s.hwndUpDown, C.SW_SHOW)
	}
}

func (s *spinbox) preferredSize(d *sizing) (width, height int) {
	// TODO
	return 20, 20
}

func (s *spinbox) resize(x int, y int, width int, height int, d *sizing) {
	C.moveWindow(s.hwndEdit, C.int(x), C.int(y), C.int(width), C.int(height))
	s.remakeUpDown()
}

func (s *spinbox) nTabStops() int {
	// TODO does the up-down control count?
	return 1
}

// TODO be sure to modify this when we add Show()/Hide()
func (s *spinbox) containerShow() {
	C.ShowWindow(s.hwndEdit, C.SW_SHOW)
	C.ShowWindow(s.hwndUpDown, C.SW_SHOW)
	s.updownVisible = true
}

// TODO be sure to modify this when we add Show()/Hide()
func (s *spinbox) containerHide() {
	C.ShowWindow(s.hwndEdit, C.SW_HIDE)
	C.ShowWindow(s.hwndUpDown, C.SW_HIDE)
	s.updownVisible = false
}
<commit_msg>Fixed up Spinbox appearance on Windows.<commit_after>// 28 october 2014

package ui

import (
	"strconv"
	"unsafe"
)

// #include "winapi_windows.h"
import "C"

// TODO do we have to manually monitor user changes to the edit control?
// TODO WS_EX_CLIENTEDGE on the updown?

type spinbox struct {
	hwndEdit			C.HWND
	hwndUpDown		C.HWND
	changed			*event
	// updown state
	updownVisible		bool
	// keep these here to avoid having to get them out
	value			int
	min				int
	max				int
}

func newSpinbox(min int, max int) Spinbox {
	s := new(spinbox)
	s.hwndEdit = C.newControl(editclass,
		C.textfieldStyle | C.ES_NUMBER,
		C.textfieldExtStyle)
	s.changed = newEvent()
	s.updownVisible = true		// initially shown
	s.min = min
	s.max = max
	s.value = s.min
	s.remakeUpDown()
	C.controlSetControlFont(s.hwndEdit)
	C.setSpinboxEditSubclass(s.hwndEdit, unsafe.Pointer(s))
	return s
}

func (s *spinbox) cap() {
	if s.value < s.min {
		s.value = s.min
	}
	if s.value > s.max {
		s.value = s.max
	}
}

func (s *spinbox) Value() int {
	return s.value
}

func (s *spinbox) SetValue(value int) {
	// UDM_SETPOS32 is documented to do what we want, but since we're keeping a copy of value we need to do it anyway
	s.value = value
	s.cap()
	C.SendMessageW(s.hwndUpDown, C.UDM_SETPOS32, 0, C.LPARAM(s.value))
}

func (s *spinbox) OnChanged(e func()) {
	s.changed.set(e)
}

//export spinboxUpDownClicked
func spinboxUpDownClicked(data unsafe.Pointer, nud *C.NMUPDOWN) {
	// this is where we do custom increments
	s := (*spinbox)(data)
	s.value = int(nud.iPos + nud.iDelta)
	// this can go above or below the bounds (the spinbox only rejects invalid values after the UDN_DELTAPOS notification is processed)
	// because we have a copy of the value, we need to fix that here
	s.cap()
	s.changed.fire()
}

//export spinboxEditChanged
func spinboxEditChanged(data unsafe.Pointer) {
	// we're basically on our own here
	s := (*spinbox)(unsafe.Pointer(data))
	// this basically does what OS X does: values too low get clamped to the minimum, values too high get clamped to the maximum, and deleting everything clamps to the minimum
	value, err := strconv.Atoi(getWindowText(s.hwndEdit))
	if err != nil {
		// best we can do fo rnow in this case :S
		// a partial atoi() like in C would be more optimal
		// it handles the deleting everything case just fine
		value = s.min
	}
	s.value = value
	s.cap()
	C.SendMessageW(s.hwndUpDown, C.UDM_SETPOS32, 0, C.LPARAM(s.value))
	// TODO position the insertion caret at the end (or wherever is appropriate)
	s.changed.fire()
}

func (s *spinbox) setParent(p *controlParent) {
	C.controlSetParent(s.hwndEdit, p.hwnd)
	C.controlSetParent(s.hwndUpDown, p.hwnd)
}

// an up-down control will only properly position itself the first time
// stupidly, there are no messages to force a size calculation, nor can I seem to reset the buddy window to force a new position
// alas, we have to make a new up/down control each time :(
// TODO we'll need to store a copy of the current position and range for this
func (s *spinbox) remakeUpDown() {
	// destroying the previous one, setting the parent properly, and subclassing are handled here
	s.hwndUpDown = C.newUpDown(s.hwndUpDown, unsafe.Pointer(s))
	// for this to work, hwndUpDown needs to have rect [0 0 0 0]
	C.moveWindow(s.hwndUpDown, 0, 0, 0, 0)
	C.SendMessageW(s.hwndUpDown, C.UDM_SETBUDDY, C.WPARAM(uintptr(unsafe.Pointer(s.hwndEdit))), 0)
	C.SendMessageW(s.hwndUpDown, C.UDM_SETRANGE32, C.WPARAM(s.min), C.LPARAM(s.max))
	C.SendMessageW(s.hwndUpDown, C.UDM_SETPOS32, 0, C.LPARAM(s.value))
	if s.updownVisible {
		C.ShowWindow(s.hwndUpDown, C.SW_SHOW)
	}
}

// use the same height as normal text fields
// TODO constrain the width somehow
func (s *spinbox) preferredSize(d *sizing) (width, height int) {
	return fromdlgunitsX(textfieldWidth, d), fromdlgunitsY(textfieldHeight, d)
}

func (s *spinbox) resize(x int, y int, width int, height int, d *sizing) {
	C.moveWindow(s.hwndEdit, C.int(x), C.int(y), C.int(width), C.int(height))
	s.remakeUpDown()
}

func (s *spinbox) nTabStops() int {
	// TODO does the up-down control count?
	return 1
}

// TODO be sure to modify this when we add Show()/Hide()
func (s *spinbox) containerShow() {
	C.ShowWindow(s.hwndEdit, C.SW_SHOW)
	C.ShowWindow(s.hwndUpDown, C.SW_SHOW)
	s.updownVisible = true
}

// TODO be sure to modify this when we add Show()/Hide()
func (s *spinbox) containerHide() {
	C.ShowWindow(s.hwndEdit, C.SW_HIDE)
	C.ShowWindow(s.hwndUpDown, C.SW_HIDE)
	s.updownVisible = false
}
<|endoftext|>