<commit_before>package main

import (
	"errors"
	log "github.com/GameGophers/nsq-logger"
	"github.com/boltdb/bolt"
	"golang.org/x/net/context"
	"os"
	"os/signal"
	pb "proto"
	"sync"
	"syscall"
	"time"
)

const (
	SERVICE = "[RANK]"
)

const (
	BOLTDB_FILE    = "/data/RANK-DUMP.DAT"
	BOLTDB_BUCKET  = "RANKING"
	CHANGES_SIZE   = 65536
	CHECK_INTERVAL = 10 * time.Second // if ranking has changed, how long to check
)

var (
	ERROR_NAME_NOT_EXISTS = errors.New("name not exists")
)

type server struct {
	ranks   map[string]*RankSet
	pending chan string
	sync.RWMutex
}

func (s *server) init() {
	s.ranks = make(map[string]*RankSet)
	s.pending = make(chan string, CHANGES_SIZE)
	s.restore()
	go s.persistence_task()
}

func (s *server) lock_read(f func()) {
	s.RLock()
	defer s.RUnlock()
	f()
}

func (s *server) lock_write(f func()) {
	s.Lock()
	defer s.Unlock()
	f()
}

func (s *server) RankChange(ctx context.Context, in *pb.Ranking_Change) (*pb.Ranking_NullResult, error) {
	// check name existence
	var rs *RankSet
	s.lock_write(func() {
		rs = s.ranks[in.Name]
		if rs == nil {
			rs = &RankSet{}
			rs.init()
			s.ranks[in.Name] = rs
		}
	})

	// apply update one the rankset
	rs.Update(in.UserId, in.Score)
	s.pending <- in.Name
	return &pb.Ranking_NullResult{}, nil
}

func (s *server) QueryRankRange(ctx context.Context, in *pb.Ranking_Range) (*pb.Ranking_RankList, error) {
	var rs *RankSet
	s.lock_read(func() {
		rs = s.ranks[in.Name]
	})

	if rs == nil {
		return nil, ERROR_NAME_NOT_EXISTS
	}

	ids, cups := rs.GetList(int(in.StartNo), int(in.EndNo))
	return &pb.Ranking_RankList{UserIds: ids, Scores: cups}, nil
}

func (s *server) QueryUsers(ctx context.Context, in *pb.Ranking_Users) (*pb.Ranking_UserList, error) {
	var rs *RankSet
	s.lock_read(func() {
		rs = s.ranks[in.Name]
	})

	if rs == nil {
		return nil, ERROR_NAME_NOT_EXISTS
	}

	ranks := make([]int32, 0, len(in.UserIds))
	scores := make([]int32, 0, len(in.UserIds))
	for _, id := range in.UserIds {
		rank, score := rs.Rank(id)
		ranks = append(ranks, rank)
		scores = append(scores, score)
	}
	return &pb.Ranking_UserList{Ranks: ranks, Scores: scores}, nil
}

// persistence ranking tree into db
func (s *server) persistence_task() {
	timer := time.After(CHECK_INTERVAL)
	db := s.open_db()
	changes := make(map[string]bool)
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, syscall.SIGTERM)

	for {
		select {
		case key := <-s.pending:
			changes[key] = true
		case <-timer:
			s.dump_changes(db, changes)
			log.Infof("perisisted %v trees:", len(changes))
			changes = make(map[string]bool)
			timer = time.After(CHECK_INTERVAL)
		case <-sig:
			s.dump_changes(db, changes)
			db.Close()
			os.Exit(0)
		}
	}
}

func (s *server) dump_changes(db *bolt.DB, changes map[string]bool) {
	for k := range changes {
		// marshal
		var rs *RankSet
		s.lock_read(func() {
			rs = s.ranks[k]
		})
		if rs == nil {
			log.Error("empty rankset:", k)
			continue
		}

		// serialization and save
		bin, err := rs.Marshal()
		if err != nil {
			log.Critical("cannot marshal:", err)
			os.Exit(-1)
		}

		db.Update(func(tx *bolt.Tx) error {
			b := tx.Bucket([]byte(BOLTDB_BUCKET))
			err := b.Put([]byte(k), bin)
			return err
		})
	}
}

func (s *server) open_db() *bolt.DB {
	db, err := bolt.Open(BOLTDB_FILE, 0600, nil)
	if err != nil {
		log.Critical(err)
		os.Exit(-1)
	}
	// create bulket
	db.Update(func(tx *bolt.Tx) error {
		_, err := tx.CreateBucketIfNotExists([]byte(BOLTDB_BUCKET))
		if err != nil {
			log.Criticalf("create bucket: %s", err)
			os.Exit(-1)
		}
		return nil
	})
	return db
}

func (s *server) restore() {
	// restore data from db file
	db := s.open_db()
	defer db.Close()
	db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(BOLTDB_BUCKET))
		c := b.Cursor()

		for k, v := c.First(); k != nil; k, v = c.Next() {
			rs := &RankSet{}
			rs.init()
			err := rs.Unmarshal(v)
			if err != nil {
				log.Critical("rank data corrupted:", err)
				os.Exit(-1)
			}
			s.ranks[string(k)] = rs
		}

		return nil
	})
}
<commit_msg>catch sigint<commit_after>package main

import (
	"errors"
	log "github.com/GameGophers/nsq-logger"
	"github.com/boltdb/bolt"
	"golang.org/x/net/context"
	"os"
	"os/signal"
	pb "proto"
	"sync"
	"syscall"
	"time"
)

const (
	SERVICE = "[RANK]"
)

const (
	BOLTDB_FILE    = "/data/RANK-DUMP.DAT"
	BOLTDB_BUCKET  = "RANKING"
	CHANGES_SIZE   = 65536
	CHECK_INTERVAL = 10 * time.Second // if ranking has changed, how long to check
)

var (
	ERROR_NAME_NOT_EXISTS = errors.New("name not exists")
)

type server struct {
	ranks   map[string]*RankSet
	pending chan string
	sync.RWMutex
}

func (s *server) init() {
	s.ranks = make(map[string]*RankSet)
	s.pending = make(chan string, CHANGES_SIZE)
	s.restore()
	go s.persistence_task()
}

func (s *server) lock_read(f func()) {
	s.RLock()
	defer s.RUnlock()
	f()
}

func (s *server) lock_write(f func()) {
	s.Lock()
	defer s.Unlock()
	f()
}

func (s *server) RankChange(ctx context.Context, in *pb.Ranking_Change) (*pb.Ranking_NullResult, error) {
	// check name existence
	var rs *RankSet
	s.lock_write(func() {
		rs = s.ranks[in.Name]
		if rs == nil {
			rs = &RankSet{}
			rs.init()
			s.ranks[in.Name] = rs
		}
	})

	// apply update one the rankset
	rs.Update(in.UserId, in.Score)
	s.pending <- in.Name
	return &pb.Ranking_NullResult{}, nil
}

func (s *server) QueryRankRange(ctx context.Context, in *pb.Ranking_Range) (*pb.Ranking_RankList, error) {
	var rs *RankSet
	s.lock_read(func() {
		rs = s.ranks[in.Name]
	})

	if rs == nil {
		return nil, ERROR_NAME_NOT_EXISTS
	}

	ids, cups := rs.GetList(int(in.StartNo), int(in.EndNo))
	return &pb.Ranking_RankList{UserIds: ids, Scores: cups}, nil
}

func (s *server) QueryUsers(ctx context.Context, in *pb.Ranking_Users) (*pb.Ranking_UserList, error) {
	var rs *RankSet
	s.lock_read(func() {
		rs = s.ranks[in.Name]
	})

	if rs == nil {
		return nil, ERROR_NAME_NOT_EXISTS
	}

	ranks := make([]int32, 0, len(in.UserIds))
	scores := make([]int32, 0, len(in.UserIds))
	for _, id := range in.UserIds {
		rank, score := rs.Rank(id)
		ranks = append(ranks, rank)
		scores = append(scores, score)
	}
	return &pb.Ranking_UserList{Ranks: ranks, Scores: scores}, nil
}

// persistence ranking tree into db
func (s *server) persistence_task() {
	timer := time.After(CHECK_INTERVAL)
	db := s.open_db()
	changes := make(map[string]bool)
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, syscall.SIGTERM, syscall.SIGINT)

	for {
		select {
		case key := <-s.pending:
			changes[key] = true
		case <-timer:
			s.dump_changes(db, changes)
			log.Infof("perisisted %v trees:", len(changes))
			changes = make(map[string]bool)
			timer = time.After(CHECK_INTERVAL)
		case <-sig:
			s.dump_changes(db, changes)
			db.Close()
			log.Info("SIGTERM")
			os.Exit(0)
		}
	}
}

func (s *server) dump_changes(db *bolt.DB, changes map[string]bool) {
	for k := range changes {
		// marshal
		var rs *RankSet
		s.lock_read(func() {
			rs = s.ranks[k]
		})
		if rs == nil {
			log.Error("empty rankset:", k)
			continue
		}

		// serialization and save
		bin, err := rs.Marshal()
		if err != nil {
			log.Critical("cannot marshal:", err)
			os.Exit(-1)
		}

		db.Update(func(tx *bolt.Tx) error {
			b := tx.Bucket([]byte(BOLTDB_BUCKET))
			err := b.Put([]byte(k), bin)
			return err
		})
	}
}

func (s *server) open_db() *bolt.DB {
	db, err := bolt.Open(BOLTDB_FILE, 0600, nil)
	if err != nil {
		log.Critical(err)
		os.Exit(-1)
	}
	// create bulket
	db.Update(func(tx *bolt.Tx) error {
		_, err := tx.CreateBucketIfNotExists([]byte(BOLTDB_BUCKET))
		if err != nil {
			log.Criticalf("create bucket: %s", err)
			os.Exit(-1)
		}
		return nil
	})
	return db
}

func (s *server) restore() {
	// restore data from db file
	db := s.open_db()
	defer db.Close()
	db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(BOLTDB_BUCKET))
		c := b.Cursor()

		for k, v := c.First(); k != nil; k, v = c.Next() {
			rs := &RankSet{}
			rs.init()
			err := rs.Unmarshal(v)
			if err != nil {
				log.Critical("rank data corrupted:", err)
				os.Exit(-1)
			}
			s.ranks[string(k)] = rs
		}

		return nil
	})
}
<|endoftext|>


<commit_before>// Copyright 2017 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package client

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"strings"
	"text/tabwriter"

	"github.com/keybase/cli"
	"github.com/keybase/client/go/libcmdline"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/keybase1"
)

type CmdTeamListMemberships struct {
	libkb.Contextified
	team                 string
	json                 bool
	forcePoll            bool
	userAssertion        string
	includeImplicitTeams bool
	showAll              bool
	verbose              bool
	tabw                 *tabwriter.Writer
}

func (c *CmdTeamListMemberships) SetTeam(s string) {
	c.team = s
}

func (c *CmdTeamListMemberships) SetJSON(b bool) {
	c.json = b
}

func (c *CmdTeamListMemberships) SetForcePoll(b bool) {
	c.forcePoll = b
}

func NewCmdTeamListMembershipsRunner(g *libkb.GlobalContext) *CmdTeamListMemberships {
	return &CmdTeamListMemberships{Contextified: libkb.NewContextified(g)}
}

func newCmdTeamListMemberships(cl *libcmdline.CommandLine, g *libkb.GlobalContext) cli.Command {
	flags := []cli.Flag{
		cli.BoolFlag{
			Name:  "j, json",
			Usage: "Output memberships as JSON",
		},
		cli.BoolFlag{
			Name:  "force-poll",
			Usage: "Force a poll of the server for all identities",
		},
		cli.StringFlag{
			Name:  "u, user",
			Usage: "List memberships for a user assertion",
		},
		cli.BoolFlag{
			Name:  "include-subteams",
			Usage: "Include any subteam memberships as well",
		},
		cli.BoolFlag{
			Name:  "all",
			Usage: "Show all members of all teams you belong to",
		},
		cli.BoolFlag{
			Name:  "v, verbose",
			Usage: "Include more verbose output",
		},
	}
	if develUsage {
		flags = append(flags, cli.BoolFlag{
			Name:  "include-implicit-teams",
			Usage: "[devel only] Include automatic teams that are not normally visible",
		})
	}
	return cli.Command{
		Name:         "list-memberships",
		ArgumentHelp: "[team name] [--user=username]",
		Aliases:      []string{"list-members"},
		Usage:        "List your teams, or people on a team.",
		Action: func(c *cli.Context) {
			cmd := NewCmdTeamListMembershipsRunner(g)
			cl.ChooseCommand(cmd, "list-memberships", c)
		},
		Flags: flags,
	}
}

func (c *CmdTeamListMemberships) ParseArgv(ctx *cli.Context) error {
	if len(ctx.Args()) > 1 {
		return errors.New("at most one team name argument allowed, multiple found")
	}
	if len(ctx.Args()) > 0 {
		c.team = ctx.Args()[0]
	}
	c.userAssertion = ctx.String("user")
	c.includeImplicitTeams = ctx.Bool("include-implicit-teams")
	c.showAll = ctx.Bool("all")

	if c.showAll {
		if c.team != "" {
			return errors.New("cannot specify a team and --all, please choose one")
		}
		if c.userAssertion != "" {
			return errors.New("cannot specify a user and --all, please choose one")
		}
	}

	c.json = ctx.Bool("json")
	c.forcePoll = ctx.Bool("force-poll")
	c.verbose = ctx.Bool("verbose")

	return nil
}

func (c *CmdTeamListMemberships) Run() error {
	cli, err := GetTeamsClient(c.G())
	if err != nil {
		return err
	}

	if c.team != "" {
		return c.runGet(cli)
	}

	return c.runUser(cli)
}

func (c *CmdTeamListMemberships) runGet(cli keybase1.TeamsClient) error {
	details, err := cli.TeamGet(context.Background(), keybase1.TeamGetArg{Name: c.team, ForceRepoll: c.forcePoll})
	if err != nil {
		return err
	}

	return c.output(details)
}

func (c *CmdTeamListMemberships) runUser(cli keybase1.TeamsClient) error {
	arg := keybase1.TeamListArg{
		UserAssertion:        c.userAssertion,
		All:                  c.showAll,
		IncludeImplicitTeams: c.includeImplicitTeams,
	}
	list, err := cli.TeamList(context.Background(), arg)
	if err != nil {
		return err
	}

	if c.json {
		b, err := json.MarshalIndent(list, "", "    ")
		if err != nil {
			return err
		}
		dui := c.G().UI.GetDumbOutputUI()
		_, err = dui.Printf(string(b) + "\n")
		return err
	}

	dui := c.G().UI.GetTerminalUI()
	c.tabw = new(tabwriter.Writer)
	c.tabw.Init(dui.OutputWriter(), 0, 8, 4, ' ', 0)

	// Only print the username and full name columns when we're showing other users.
	if c.showAll {
		fmt.Fprintf(c.tabw, "Team\tRole\tUsername\tFull name\n")
	} else {
		fmt.Fprintf(c.tabw, "Team\tRole\n")
	}
	for _, t := range list.Teams {
		var role string
		if t.Implicit != nil {
			role += "implied admin"
		}
		if t.Role != keybase1.TeamRole_NONE {
			if t.Implicit != nil {
				role += ", "
			}
			role += strings.ToLower(t.Role.String())
		}
		if c.showAll {
			fmt.Fprintf(c.tabw, "%s\t%s\t%s\t%s\n", t.FqName, role, t.Username, t.FullName)
		} else {
			fmt.Fprintf(c.tabw, "%s\t%s\n", t.FqName, role)
		}
	}
	if c.showAll {
		c.outputInvites(list.AnnotatedActiveInvites)
	}

	c.tabw.Flush()

	return nil
}

func (c *CmdTeamListMemberships) output(details keybase1.TeamDetails) error {
	if c.json {
		return c.outputJSON(details)
	}

	return c.outputTerminal(details)
}

func (c *CmdTeamListMemberships) outputJSON(details keybase1.TeamDetails) error {
	b, err := json.MarshalIndent(details, "", "    ")
	if err != nil {
		return err
	}
	dui := c.G().UI.GetDumbOutputUI()
	_, err = dui.Printf(string(b) + "\n")
	return err
}

func (c *CmdTeamListMemberships) outputTerminal(details keybase1.TeamDetails) error {
	dui := c.G().UI.GetTerminalUI()
	c.tabw = new(tabwriter.Writer)
	c.tabw.Init(dui.OutputWriter(), 0, 8, 2, ' ', 0)

	c.outputRole("owner", details.Members.Owners)
	c.outputRole("admin", details.Members.Admins)
	c.outputRole("writer", details.Members.Writers)
	c.outputRole("reader", details.Members.Readers)
	c.outputInvites(details.AnnotatedActiveInvites)
	c.tabw.Flush()

	if c.verbose {
		dui.Printf("At team key generation: %d\n", details.KeyGeneration)
	}

	return nil
}

func (c *CmdTeamListMemberships) outputRole(role string, members []keybase1.TeamMemberDetails) {
	for _, member := range members {
		var reset string
		if !member.Active {
			reset = " (inactive due to account reset)"
		}
		fmt.Fprintf(c.tabw, "%s\t%s\t%s%s\n", c.team, role, member.Username, reset)
	}
}

func (c *CmdTeamListMemberships) outputInvites(invites map[keybase1.TeamInviteID]keybase1.AnnotatedTeamInvite) {
	for _, invite := range invites {
		fmtstring := "%s\t%s*\t%s\t(* added by %s; awaiting acceptance)\n"
		fmt.Fprintf(c.tabw, fmtstring, invite.TeamName, strings.ToLower(invite.Role.String()), invite.Name, invite.InviterUsername)
	}
}

func (c *CmdTeamListMemberships) GetUsage() libkb.Usage {
	return libkb.Usage{
		Config:    true,
		API:       true,
		KbKeyring: true,
	}
}
<commit_msg>format invites in list-members with social service (#8994)<commit_after>// Copyright 2017 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package client

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"strings"
	"text/tabwriter"

	"github.com/keybase/cli"
	"github.com/keybase/client/go/libcmdline"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/keybase1"
)

type CmdTeamListMemberships struct {
	libkb.Contextified
	team                 string
	json                 bool
	forcePoll            bool
	userAssertion        string
	includeImplicitTeams bool
	showAll              bool
	verbose              bool
	tabw                 *tabwriter.Writer
}

func (c *CmdTeamListMemberships) SetTeam(s string) {
	c.team = s
}

func (c *CmdTeamListMemberships) SetJSON(b bool) {
	c.json = b
}

func (c *CmdTeamListMemberships) SetForcePoll(b bool) {
	c.forcePoll = b
}

func NewCmdTeamListMembershipsRunner(g *libkb.GlobalContext) *CmdTeamListMemberships {
	return &CmdTeamListMemberships{Contextified: libkb.NewContextified(g)}
}

func newCmdTeamListMemberships(cl *libcmdline.CommandLine, g *libkb.GlobalContext) cli.Command {
	flags := []cli.Flag{
		cli.BoolFlag{
			Name:  "j, json",
			Usage: "Output memberships as JSON",
		},
		cli.BoolFlag{
			Name:  "force-poll",
			Usage: "Force a poll of the server for all identities",
		},
		cli.StringFlag{
			Name:  "u, user",
			Usage: "List memberships for a user assertion",
		},
		cli.BoolFlag{
			Name:  "include-subteams",
			Usage: "Include any subteam memberships as well",
		},
		cli.BoolFlag{
			Name:  "all",
			Usage: "Show all members of all teams you belong to",
		},
		cli.BoolFlag{
			Name:  "v, verbose",
			Usage: "Include more verbose output",
		},
	}
	if develUsage {
		flags = append(flags, cli.BoolFlag{
			Name:  "include-implicit-teams",
			Usage: "[devel only] Include automatic teams that are not normally visible",
		})
	}
	return cli.Command{
		Name:         "list-memberships",
		ArgumentHelp: "[team name] [--user=username]",
		Aliases:      []string{"list-members"},
		Usage:        "List your teams, or people on a team.",
		Action: func(c *cli.Context) {
			cmd := NewCmdTeamListMembershipsRunner(g)
			cl.ChooseCommand(cmd, "list-memberships", c)
		},
		Flags: flags,
	}
}

func (c *CmdTeamListMemberships) ParseArgv(ctx *cli.Context) error {
	if len(ctx.Args()) > 1 {
		return errors.New("at most one team name argument allowed, multiple found")
	}
	if len(ctx.Args()) > 0 {
		c.team = ctx.Args()[0]
	}
	c.userAssertion = ctx.String("user")
	c.includeImplicitTeams = ctx.Bool("include-implicit-teams")
	c.showAll = ctx.Bool("all")

	if c.showAll {
		if c.team != "" {
			return errors.New("cannot specify a team and --all, please choose one")
		}
		if c.userAssertion != "" {
			return errors.New("cannot specify a user and --all, please choose one")
		}
	}

	c.json = ctx.Bool("json")
	c.forcePoll = ctx.Bool("force-poll")
	c.verbose = ctx.Bool("verbose")

	return nil
}

func (c *CmdTeamListMemberships) Run() error {
	cli, err := GetTeamsClient(c.G())
	if err != nil {
		return err
	}

	if c.team != "" {
		return c.runGet(cli)
	}

	return c.runUser(cli)
}

func (c *CmdTeamListMemberships) runGet(cli keybase1.TeamsClient) error {
	details, err := cli.TeamGet(context.Background(), keybase1.TeamGetArg{Name: c.team, ForceRepoll: c.forcePoll})
	if err != nil {
		return err
	}

	return c.output(details)
}

func (c *CmdTeamListMemberships) runUser(cli keybase1.TeamsClient) error {
	arg := keybase1.TeamListArg{
		UserAssertion:        c.userAssertion,
		All:                  c.showAll,
		IncludeImplicitTeams: c.includeImplicitTeams,
	}
	list, err := cli.TeamList(context.Background(), arg)
	if err != nil {
		return err
	}

	if c.json {
		b, err := json.MarshalIndent(list, "", "    ")
		if err != nil {
			return err
		}
		dui := c.G().UI.GetDumbOutputUI()
		_, err = dui.Printf(string(b) + "\n")
		return err
	}

	dui := c.G().UI.GetTerminalUI()
	c.tabw = new(tabwriter.Writer)
	c.tabw.Init(dui.OutputWriter(), 0, 8, 4, ' ', 0)

	// Only print the username and full name columns when we're showing other users.
	if c.showAll {
		fmt.Fprintf(c.tabw, "Team\tRole\tUsername\tFull name\n")
	} else {
		fmt.Fprintf(c.tabw, "Team\tRole\n")
	}
	for _, t := range list.Teams {
		var role string
		if t.Implicit != nil {
			role += "implied admin"
		}
		if t.Role != keybase1.TeamRole_NONE {
			if t.Implicit != nil {
				role += ", "
			}
			role += strings.ToLower(t.Role.String())
		}
		if c.showAll {
			fmt.Fprintf(c.tabw, "%s\t%s\t%s\t%s\n", t.FqName, role, t.Username, t.FullName)
		} else {
			fmt.Fprintf(c.tabw, "%s\t%s\n", t.FqName, role)
		}
	}
	if c.showAll {
		c.outputInvites(list.AnnotatedActiveInvites)
	}

	c.tabw.Flush()

	return nil
}

func (c *CmdTeamListMemberships) output(details keybase1.TeamDetails) error {
	if c.json {
		return c.outputJSON(details)
	}

	return c.outputTerminal(details)
}

func (c *CmdTeamListMemberships) outputJSON(details keybase1.TeamDetails) error {
	b, err := json.MarshalIndent(details, "", "    ")
	if err != nil {
		return err
	}
	dui := c.G().UI.GetDumbOutputUI()
	_, err = dui.Printf(string(b) + "\n")
	return err
}

func (c *CmdTeamListMemberships) outputTerminal(details keybase1.TeamDetails) error {
	dui := c.G().UI.GetTerminalUI()
	c.tabw = new(tabwriter.Writer)
	c.tabw.Init(dui.OutputWriter(), 0, 8, 2, ' ', 0)

	c.outputRole("owner", details.Members.Owners)
	c.outputRole("admin", details.Members.Admins)
	c.outputRole("writer", details.Members.Writers)
	c.outputRole("reader", details.Members.Readers)
	c.outputInvites(details.AnnotatedActiveInvites)
	c.tabw.Flush()

	if c.verbose {
		dui.Printf("At team key generation: %d\n", details.KeyGeneration)
	}

	return nil
}

func (c *CmdTeamListMemberships) outputRole(role string, members []keybase1.TeamMemberDetails) {
	for _, member := range members {
		var reset string
		if !member.Active {
			reset = " (inactive due to account reset)"
		}
		fmt.Fprintf(c.tabw, "%s\t%s\t%s%s\n", c.team, role, member.Username, reset)
	}
}

func (c *CmdTeamListMemberships) formatInviteName(invite keybase1.AnnotatedTeamInvite) (res string) {
	res = string(invite.Name)
	category, err := invite.Type.C()
	if err == nil {
		switch category {
		case keybase1.TeamInviteCategory_SBS:
			res = fmt.Sprintf("%s@%s", invite.Name, string(invite.Type.Sbs()))
		}
	}
	return res
}

func (c *CmdTeamListMemberships) outputInvites(invites map[keybase1.TeamInviteID]keybase1.AnnotatedTeamInvite) {
	for _, invite := range invites {
		fmtstring := "%s\t%s*\t%s\t(* added by %s; awaiting acceptance)\n"
		fmt.Fprintf(c.tabw, fmtstring, invite.TeamName, strings.ToLower(invite.Role.String()),
			c.formatInviteName(invite), invite.InviterUsername)
	}
}

func (c *CmdTeamListMemberships) GetUsage() libkb.Usage {
	return libkb.Usage{
		Config:    true,
		API:       true,
		KbKeyring: true,
	}
}
<|endoftext|>


<commit_before>// GOMAXPROCS=10 go test
// GOMAXPROCS=10 go test -bench . -race

package spin

import (
	"runtime"
	"sync/atomic"
	"testing"
)

func HammerSpinlock(l *Lock, loops int, done chan bool) {
	for i := 0; i < loops; i++ {
		l.Lock()
		l.Unlock()
	}
	done <- true
}

func TestSpinlock(t *testing.T) {
	l := new(Lock)
	c := make(chan bool)
	for i := 0; i < 10; i++ {
		go HammerSpinlock(l, 1000, c)
	}
	for i := 0; i < 10; i++ {
		<-c
	}
}

func BenchmarkUncontendedSpinlock(b *testing.B) {
	l := new(Lock)
	HammerSpinlock(l, b.N, make(chan bool, 2))
}

func BenchmarkContendedSpinlock(b *testing.B) {
	b.StopTimer()
	l := new(Lock)
	c := make(chan bool)
	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
	b.StartTimer()

	go HammerSpinlock(l, b.N/2, c)
	go HammerSpinlock(l, b.N/2, c)
	<-c
	<-c
}

func TestSpinlockPanic(t *testing.T) {
	defer func() {
		if recover() == nil {
			t.Fatalf("unlock of unlocked spinlock did not panic")
		}
	}()

	var l Lock
	l.Lock()
	l.Unlock()
	l.Unlock()
}

func BenchmarkSpinlockUncontended(b *testing.B) {
	type PaddedSpinlock struct {
		Lock
		pad [128]uint8
	}
	const CallsPerSched = 1000
	procs := runtime.GOMAXPROCS(-1)
	N := int32(b.N / CallsPerSched)
	c := make(chan bool, procs)
	for p := 0; p < procs; p++ {
		go func() {
			var l PaddedSpinlock
			for atomic.AddInt32(&N, -1) >= 0 {
				runtime.Gosched()
				for g := 0; g < CallsPerSched; g++ {
					l.Lock.Lock()
					l.Unlock()
				}
			}
			c <- true
		}()
	}
	for p := 0; p < procs; p++ {
		<-c
	}
}

func benchmarkSpinlock(b *testing.B, slack, work bool) {
	const (
		CallsPerSched  = 1000
		LocalWork      = 100
		GoroutineSlack = 10
	)
	procs := runtime.GOMAXPROCS(-1)
	if slack {
		procs *= GoroutineSlack
	}
	N := int32(b.N / CallsPerSched)
	c := make(chan bool, procs)
	l := new(Lock)
	for p := 0; p < procs; p++ {
		go func() {
			foo := 0
			for atomic.AddInt32(&N, -1) >= 0 {
				runtime.Gosched()
				for g := 0; g < CallsPerSched; g++ {
					l.Lock()
					l.Unlock()
					if work {
						for i := 0; i < LocalWork; i++ {
							foo *= 2
							foo /= 2
						}
					}
				}
			}
			c <- foo == 42
		}()
	}
	for p := 0; p < procs; p++ {
		<-c
	}
}

func BenchmarkSpinlock(b *testing.B) {
	benchmarkSpinlock(b, false, false)
}

func BenchmarkSpinlockSlack(b *testing.B) {
	benchmarkSpinlock(b, true, false)
}

func BenchmarkSpinlockWork(b *testing.B) {
	benchmarkSpinlock(b, false, true)
}

func BenchmarkSpinlockWorkSlack(b *testing.B) {
	benchmarkSpinlock(b, true, true)
}
<commit_msg>Added comparison mutex benchmarks<commit_after>// GOMAXPROCS=10 go test
// GOMAXPROCS=10 go test -bench . -race

package spin

import (
	"runtime"
	"sync"
	"sync/atomic"
	"testing"
)

func HammerSpinlock(l *Lock, loops int, done chan bool) {
	for i := 0; i < loops; i++ {
		l.Lock()
		l.Unlock()
	}
	done <- true
}

func TestSpinlock(t *testing.T) {
	l := new(Lock)
	c := make(chan bool)
	for i := 0; i < 10; i++ {
		go HammerSpinlock(l, 1000, c)
	}
	for i := 0; i < 10; i++ {
		<-c
	}
}

func BenchmarkUncontendedSpinlock(b *testing.B) {
	l := new(Lock)
	HammerSpinlock(l, b.N, make(chan bool, 2))
}

func BenchmarkContendedSpinlock(b *testing.B) {
	b.StopTimer()
	l := new(Lock)
	c := make(chan bool)
	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
	b.StartTimer()

	go HammerSpinlock(l, b.N/2, c)
	go HammerSpinlock(l, b.N/2, c)
	<-c
	<-c
}

func TestSpinlockPanic(t *testing.T) {
	defer func() {
		if recover() == nil {
			t.Fatalf("unlock of unlocked spinlock did not panic")
		}
	}()

	var l Lock
	l.Lock()
	l.Unlock()
	l.Unlock()
}

func BenchmarkSpinlockUncontended(b *testing.B) {
	type PaddedSpinlock struct {
		Lock
		pad [128]uint8
	}
	const CallsPerSched = 1000
	procs := runtime.GOMAXPROCS(-1)
	N := int32(b.N / CallsPerSched)
	c := make(chan bool, procs)
	for p := 0; p < procs; p++ {
		go func() {
			var l PaddedSpinlock
			for atomic.AddInt32(&N, -1) >= 0 {
				runtime.Gosched()
				for g := 0; g < CallsPerSched; g++ {
					l.Lock.Lock()
					l.Unlock()
				}
			}
			c <- true
		}()
	}
	for p := 0; p < procs; p++ {
		<-c
	}
}

func BenchmarkMutexUncontended(b *testing.B) {
	type PaddedMutex struct {
		sync.Mutex
		pad [128]uint8
	}
	const CallsPerSched = 1000
	procs := runtime.GOMAXPROCS(-1)
	N := int32(b.N / CallsPerSched)
	c := make(chan bool, procs)
	for p := 0; p < procs; p++ {
		go func() {
			var mu PaddedMutex
			for atomic.AddInt32(&N, -1) >= 0 {
				runtime.Gosched()
				for g := 0; g < CallsPerSched; g++ {
					mu.Lock()
					mu.Unlock()
				}
			}
			c <- true
		}()
	}
	for p := 0; p < procs; p++ {
		<-c
	}
}

func benchmarkSpinlock(b *testing.B, slack, work bool) {
	const (
		CallsPerSched  = 1000
		LocalWork      = 100
		GoroutineSlack = 10
	)
	procs := runtime.GOMAXPROCS(-1)
	if slack {
		procs *= GoroutineSlack
	}
	N := int32(b.N / CallsPerSched)
	c := make(chan bool, procs)
	var l Lock
	for p := 0; p < procs; p++ {
		go func() {
			foo := 0
			for atomic.AddInt32(&N, -1) >= 0 {
				runtime.Gosched()
				for g := 0; g < CallsPerSched; g++ {
					l.Lock()
					l.Unlock()
					if work {
						for i := 0; i < LocalWork; i++ {
							foo *= 2
							foo /= 2
						}
					}
				}
			}
			c <- foo == 42
		}()
	}
	for p := 0; p < procs; p++ {
		<-c
	}
}

func benchmarkMutex(b *testing.B, slack, work bool) {
	const (
		CallsPerSched  = 1000
		LocalWork      = 100
		GoroutineSlack = 10
	)
	procs := runtime.GOMAXPROCS(-1)
	if slack {
		procs *= GoroutineSlack
	}
	N := int32(b.N / CallsPerSched)
	c := make(chan bool, procs)
	var mu sync.Mutex
	for p := 0; p < procs; p++ {
		go func() {
			foo := 0
			for atomic.AddInt32(&N, -1) >= 0 {
				runtime.Gosched()
				for g := 0; g < CallsPerSched; g++ {
					mu.Lock()
					mu.Unlock()
					if work {
						for i := 0; i < LocalWork; i++ {
							foo *= 2
							foo /= 2
						}
					}
				}
			}
			c <- foo == 42
		}()
	}
	for p := 0; p < procs; p++ {
		<-c
	}
}

func BenchmarkSpinlock(b *testing.B) {
	benchmarkSpinlock(b, false, false)
}

func BenchmarkMutex(b *testing.B) {
	benchmarkMutex(b, false, false)
}

func BenchmarkSpinlockSlack(b *testing.B) {
	benchmarkSpinlock(b, true, false)
}

func BenchmarkMutexSlack(b *testing.B) {
	benchmarkMutex(b, true, false)
}

func BenchmarkSpinlockWork(b *testing.B) {
	benchmarkSpinlock(b, false, true)
}

func BenchmarkMutexWork(b *testing.B) {
	benchmarkMutex(b, false, true)
}

func BenchmarkSpinlockWorkSlack(b *testing.B) {
	benchmarkSpinlock(b, true, true)
}

func BenchmarkMutexWorkSlack(b *testing.B) {
	benchmarkMutex(b, true, true)
}
<|endoftext|>


<commit_before>package response

import (
	"testing"
	"time"

	"github.com/coredns/coredns/plugin/test"

	"github.com/miekg/dns"
)

func TestTypifyNilMsg(t *testing.T) {
	var m *dns.Msg

	ty, _ := Typify(m, time.Now().UTC())
	if ty != OtherError {
		t.Errorf("Message wrongly typified, expected OtherError, got %s", ty)
	}
}

func TestTypifyDelegation(t *testing.T) {
	m := delegationMsg()
	mt, _ := Typify(m, time.Now().UTC())
	if mt != Delegation {
		t.Errorf("Message is wrongly typified, expected Delegation, got %s", mt)
	}
}

func TestTypifyRRSIG(t *testing.T) {
	now, _ := time.Parse(time.UnixDate, "Fri Apr 21 10:51:21 BST 2017")
	utc := now.UTC()

	m := delegationMsgRRSIGOK()
	if mt, _ := Typify(m, utc); mt != Delegation {
		t.Errorf("Message is wrongly typified, expected Delegation, got %s", mt)
	}

	// Still a Delegation because EDNS0 OPT DO bool is not set, so we won't check the sigs.
	m = delegationMsgRRSIGFail()
	if mt, _ := Typify(m, utc); mt != Delegation {
		t.Errorf("Message is wrongly typified, expected Delegation, got %s", mt)
	}

	m = delegationMsgRRSIGFail()
	m = addOpt(m)
	if mt, _ := Typify(m, utc); mt != OtherError {
		t.Errorf("Message is wrongly typified, expected OtherError, got %s", mt)
	}
}

func delegationMsg() *dns.Msg {
	return &dns.Msg{
		Ns: []dns.RR{
			test.NS("miek.nl.	3600	IN	NS	linode.atoom.net."),
			test.NS("miek.nl.	3600	IN	NS	ns-ext.nlnetlabs.nl."),
			test.NS("miek.nl.	3600	IN	NS	omval.tednet.nl."),
		},
		Extra: []dns.RR{
			test.A("omval.tednet.nl.	3600	IN	A	185.49.141.42"),
			test.AAAA("omval.tednet.nl.	3600	IN	AAAA	2a04:b900:0:100::42"),
		},
	}
}

func delegationMsgRRSIGOK() *dns.Msg {
	del := delegationMsg()
	del.Ns = append(del.Ns,
		test.RRSIG("miek.nl.		1800	IN	RRSIG	NS 8 2 1800 20170521031301 20170421031301 12051 miek.nl. PIUu3TKX/sB/N1n1E1yWxHHIcPnc2q6Wq9InShk+5ptRqChqKdZNMLDm gCq+1bQAZ7jGvn2PbwTwE65JzES7T+hEiqR5PU23DsidvZyClbZ9l0xG JtKwgzGXLtUHxp4xv/Plq+rq/7pOG61bNCxRyS7WS7i7QcCCWT1BCcv+ wZ0="),
	)
	return del
}

func delegationMsgRRSIGFail() *dns.Msg {
	del := delegationMsg()
	del.Ns = append(del.Ns,
		test.RRSIG("miek.nl.		1800	IN	RRSIG	NS 8 2 1800 20160521031301 20160421031301 12051 miek.nl. PIUu3TKX/sB/N1n1E1yWxHHIcPnc2q6Wq9InShk+5ptRqChqKdZNMLDm gCq+1bQAZ7jGvn2PbwTwE65JzES7T+hEiqR5PU23DsidvZyClbZ9l0xG JtKwgzGXLtUHxp4xv/Plq+rq/7pOG61bNCxRyS7WS7i7QcCCWT1BCcv+ wZ0="),
	)
	return del
}

func addOpt(m *dns.Msg) *dns.Msg {
	m.Extra = append(m.Extra, test.OPT(4096, true))
	return m
}
<commit_msg>pkg/response: add extra test for impossible msg (#2727)<commit_after>package response

import (
	"testing"
	"time"

	"github.com/coredns/coredns/plugin/test"

	"github.com/miekg/dns"
)

func TestTypifyNilMsg(t *testing.T) {
	var m *dns.Msg

	ty, _ := Typify(m, time.Now().UTC())
	if ty != OtherError {
		t.Errorf("Message wrongly typified, expected OtherError, got %s", ty)
	}
}

func TestTypifyDelegation(t *testing.T) {
	m := delegationMsg()
	mt, _ := Typify(m, time.Now().UTC())
	if mt != Delegation {
		t.Errorf("Message is wrongly typified, expected Delegation, got %s", mt)
	}
}

func TestTypifyRRSIG(t *testing.T) {
	now, _ := time.Parse(time.UnixDate, "Fri Apr 21 10:51:21 BST 2017")
	utc := now.UTC()

	m := delegationMsgRRSIGOK()
	if mt, _ := Typify(m, utc); mt != Delegation {
		t.Errorf("Message is wrongly typified, expected Delegation, got %s", mt)
	}

	// Still a Delegation because EDNS0 OPT DO bool is not set, so we won't check the sigs.
	m = delegationMsgRRSIGFail()
	if mt, _ := Typify(m, utc); mt != Delegation {
		t.Errorf("Message is wrongly typified, expected Delegation, got %s", mt)
	}

	m = delegationMsgRRSIGFail()
	m.Extra = append(m.Extra, test.OPT(4096, true))
	if mt, _ := Typify(m, utc); mt != OtherError {
		t.Errorf("Message is wrongly typified, expected OtherError, got %s", mt)
	}
}

func TestTypifyImpossible(t *testing.T) {
	// create impossible message that denies it's own existence
	m := new(dns.Msg)
	m.SetQuestion("bar.www.example.org.", dns.TypeAAAA)
	m.Rcode = dns.RcodeNameError                                                      // name does not exist
	m.Answer = []dns.RR{test.CNAME("bar.www.example.org. IN CNAME foo.example.org.")} // but we add a cname with the name!
	mt, _ := Typify(m, time.Now().UTC())
	if mt != OtherError {
		t.Errorf("Impossible message not typified as OtherError, got %s", mt)
	}
}

func delegationMsg() *dns.Msg {
	return &dns.Msg{
		Ns: []dns.RR{
			test.NS("miek.nl.	3600	IN	NS	linode.atoom.net."),
			test.NS("miek.nl.	3600	IN	NS	ns-ext.nlnetlabs.nl."),
			test.NS("miek.nl.	3600	IN	NS	omval.tednet.nl."),
		},
		Extra: []dns.RR{
			test.A("omval.tednet.nl.	3600	IN	A	185.49.141.42"),
			test.AAAA("omval.tednet.nl.	3600	IN	AAAA	2a04:b900:0:100::42"),
		},
	}
}

func delegationMsgRRSIGOK() *dns.Msg {
	del := delegationMsg()
	del.Ns = append(del.Ns,
		test.RRSIG("miek.nl.		1800	IN	RRSIG	NS 8 2 1800 20170521031301 20170421031301 12051 miek.nl. PIUu3TKX/sB/N1n1E1yWxHHIcPnc2q6Wq9InShk+5ptRqChqKdZNMLDm gCq+1bQAZ7jGvn2PbwTwE65JzES7T+hEiqR5PU23DsidvZyClbZ9l0xG JtKwgzGXLtUHxp4xv/Plq+rq/7pOG61bNCxRyS7WS7i7QcCCWT1BCcv+ wZ0="),
	)
	return del
}

func delegationMsgRRSIGFail() *dns.Msg {
	del := delegationMsg()
	del.Ns = append(del.Ns,
		test.RRSIG("miek.nl.		1800	IN	RRSIG	NS 8 2 1800 20160521031301 20160421031301 12051 miek.nl. PIUu3TKX/sB/N1n1E1yWxHHIcPnc2q6Wq9InShk+5ptRqChqKdZNMLDm gCq+1bQAZ7jGvn2PbwTwE65JzES7T+hEiqR5PU23DsidvZyClbZ9l0xG JtKwgzGXLtUHxp4xv/Plq+rq/7pOG61bNCxRyS7WS7i7QcCCWT1BCcv+ wZ0="),
	)
	return del
}
<|endoftext|>


<commit_before>package npm

import (
	"archive/tar"
	"compress/gzip"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/jfrog/jfrog-cli-go/artifactory/utils"
	"github.com/jfrog/jfrog-cli-go/artifactory/utils/npm"
	"github.com/jfrog/jfrog-cli-go/utils/config"
	"github.com/jfrog/jfrog-client-go/artifactory/buildinfo"
	"github.com/jfrog/jfrog-client-go/artifactory/services"
	specutils "github.com/jfrog/jfrog-client-go/artifactory/services/utils"
	clientutils "github.com/jfrog/jfrog-client-go/utils"
	"github.com/jfrog/jfrog-client-go/utils/errorutils"
	"github.com/jfrog/jfrog-client-go/utils/log"
)

type NpmPublishCommandArgs struct {
	NpmCommand
	executablePath   string
	workingDirectory string
	collectBuildInfo bool
	packedFilePath   string
	packageInfo      *npm.PackageInfo
	publishPath      string
	tarballProvided  bool
	artifactData     []specutils.FileInfo
}

type NpmPublishCommand struct {
	configFilePath string
	commandName    string
	*NpmPublishCommandArgs
}

func NewNpmPublishCommand() *NpmPublishCommand {
	return &NpmPublishCommand{NpmPublishCommandArgs: NewNpmPublishCommandArgs(), commandName: "rt_npm_publish"}
}

func NewNpmPublishCommandArgs() *NpmPublishCommandArgs {
	return &NpmPublishCommandArgs{}
}

func (npc *NpmPublishCommand) RtDetails() (*config.ArtifactoryDetails, error) {
	return npc.rtDetails, nil
}

func (npc *NpmPublishCommand) SetConfigFilePath(configFilePath string) *NpmPublishCommand {
	npc.configFilePath = configFilePath
	return npc
}

func (nic *NpmPublishCommand) SetArgs(args []string) *NpmPublishCommand {
	nic.NpmPublishCommandArgs.npmArgs = args
	return nic
}

func (npc *NpmPublishCommand) Run() error {
	if npc.configFilePath != "" {
		// Read config file.
		log.Debug("Preparing to read the config file", npc.configFilePath)
		vConfig, err := utils.ReadConfigFile(npc.configFilePath, utils.YAML)
		if err != nil {
			return err
		}
		// Extract resolution params.
		deployerParams, err := utils.GetRepoConfigByPrefix(npc.configFilePath, utils.ProjectConfigDeployerPrefix, vConfig)
		if err != nil {
			return err
		}
		_, filteredNpmArgs, buildConfiguration, err := utils.ExtractNpmOptionsFromArgs(npc.NpmPublishCommandArgs.npmArgs)
		RtDetails, err := deployerParams.RtDetails()
		if err != nil {
			return errorutils.CheckError(err)
		}
		npc.SetBuildConfiguration(buildConfiguration).SetRepo(deployerParams.TargetRepo()).SetNpmArgs(filteredNpmArgs).SetRtDetails(RtDetails)
	}
	return npc.run()
}

func (npc *NpmPublishCommand) run() error {
	log.Info("Running npm Publish")
	if err := npc.preparePrerequisites(); err != nil {
		return err
	}

	if !npc.tarballProvided {
		if err := npc.pack(); err != nil {
			return err
		}
	}

	if err := npc.deploy(); err != nil {
		if npc.tarballProvided {
			return err
		}
		// We should delete the tarball we created
		return deleteCreatedTarballAndError(npc.packedFilePath, err)
	}

	if !npc.tarballProvided {
		if err := deleteCreatedTarball(npc.packedFilePath); err != nil {
			return err
		}
	}

	if !npc.collectBuildInfo {
		log.Info("npm publish finished successfully.")
		return nil
	}

	if err := npc.saveArtifactData(); err != nil {
		return err
	}

	log.Info("npm publish finished successfully.")
	return nil
}

func (npc *NpmPublishCommand) CommandName() string {
	return npc.CommandName()
}

func (npc *NpmPublishCommand) preparePrerequisites() error {
	log.Debug("Preparing prerequisites.")
	npmExecPath, err := exec.LookPath("npm")
	if err != nil {
		return errorutils.CheckError(err)
	}

	if npmExecPath == "" {
		return errorutils.CheckError(errors.New("Could not find 'npm' executable"))
	}

	npc.executablePath = npmExecPath
	log.Debug("Using npm executable:", npc.executablePath)
	currentDir, err := os.Getwd()
	if err != nil {
		return errorutils.CheckError(err)
	}

	currentDir, err = filepath.Abs(currentDir)
	if err != nil {
		return errorutils.CheckError(err)
	}

	npc.workingDirectory = currentDir
	log.Debug("Working directory set to:", npc.workingDirectory)
	npc.collectBuildInfo = len(npc.buildConfiguration.BuildName) > 0 && len(npc.buildConfiguration.BuildNumber) > 0
	if err = npc.setPublishPath(); err != nil {
		return err
	}

	artDetails, err := npc.rtDetails.CreateArtAuthConfig()
	if err != nil {
		return err
	}

	if err = utils.CheckIfRepoExists(npc.repo, artDetails); err != nil {
		return err
	}

	return npc.setPackageInfo()
}

func (npc *NpmPublishCommand) pack() error {
	log.Debug("Creating npm package.")
	if err := npm.Pack(npc.npmArgs, npc.executablePath); err != nil {
		return err
	}

	npc.packedFilePath = filepath.Join(npc.workingDirectory, npc.packageInfo.GetExpectedPackedFileName())
	log.Debug("Created npm package at", npc.packedFilePath)
	return nil
}

func (npc *NpmPublishCommand) deploy() (err error) {
	log.Debug("Deploying npm package.")
	if err = npc.readPackageInfoFromTarball(); err != nil {
		return err
	}

	target := fmt.Sprintf("%s/%s", npc.repo, npc.packageInfo.GetDeployPath())
	artifactsFileInfo, err := npc.doDeploy(target, npc.rtDetails)
	if err != nil {
		return err
	}

	npc.artifactData = artifactsFileInfo
	return nil
}

func (npc *NpmPublishCommand) doDeploy(target string, artDetails *config.ArtifactoryDetails) (artifactsFileInfo []specutils.FileInfo, err error) {
	servicesManager, err := utils.CreateServiceManager(artDetails, false)
	if err != nil {
		return nil, err
	}
	up := services.UploadParams{}
	up.ArtifactoryCommonParams = &specutils.ArtifactoryCommonParams{Pattern: npc.packedFilePath, Target: target}
	if npc.collectBuildInfo {
		utils.SaveBuildGeneralDetails(npc.buildConfiguration.BuildName, npc.buildConfiguration.BuildNumber)
		props, err := utils.CreateBuildProperties(npc.buildConfiguration.BuildName, npc.buildConfiguration.BuildNumber)
		if err != nil {
			return nil, err
		}
		up.ArtifactoryCommonParams.Props = props
	}
	artifactsFileInfo, _, failed, err := servicesManager.UploadFiles(up)
	if err != nil {
		return nil, err
	}

	// We deploying only one Artifact which have to be deployed, in case of failure we should fail
	if failed > 0 {
		return nil, errorutils.CheckError(errors.New("Failed to upload the npm package to Artifactory. See Artifactory logs for more details."))
	}
	return artifactsFileInfo, nil
}

func (npc *NpmPublishCommand) saveArtifactData() error {
	log.Debug("Saving npm package artifact build info data.")
	var buildArtifacts []buildinfo.Artifact
	for _, artifact := range npc.artifactData {
		buildArtifacts = append(buildArtifacts, artifact.ToBuildArtifacts())
	}

	populateFunc := func(partial *buildinfo.Partial) {
		partial.Artifacts = buildArtifacts
		if npc.buildConfiguration.Module == "" {
			npc.buildConfiguration.Module = npc.packageInfo.BuildInfoModuleId()
		}
		partial.ModuleId = npc.buildConfiguration.Module
	}
	return utils.SavePartialBuildInfo(npc.buildConfiguration.BuildName, npc.buildConfiguration.BuildNumber, populateFunc)
}

func (npc *NpmPublishCommand) setPublishPath() error {
	log.Debug("Reading Package Json.")

	npc.publishPath = npc.workingDirectory
	if len(npc.npmArgs) > 0 && !strings.HasPrefix(strings.TrimSpace(npc.npmArgs[0]), "-") {
		path := strings.TrimSpace(npc.npmArgs[0])
		path = clientutils.ReplaceTildeWithUserHome(path)

		if filepath.IsAbs(path) {
			npc.publishPath = path
		} else {
			npc.publishPath = filepath.Join(npc.workingDirectory, path)
		}
	}
	return nil
}

func (npc *NpmPublishCommand) setPackageInfo() error {
	log.Debug("Setting Package Info.")
	fileInfo, err := os.Stat(npc.publishPath)
	if err != nil {
		return errorutils.CheckError(err)
	}

	if fileInfo.IsDir() {
		npc.packageInfo, err = npm.ReadPackageInfoFromPackageJson(npc.publishPath)
		return err
	}
	log.Debug("The provided path is not a directory, we assume this is a compressed npm package")
	npc.tarballProvided = true
	npc.packedFilePath = npc.publishPath
	return npc.readPackageInfoFromTarball()
}

func (npc *NpmPublishCommand) readPackageInfoFromTarball() error {
	log.Debug("Extracting info from npm package:", npc.packedFilePath)
	tarball, err := os.Open(npc.packedFilePath)
	if err != nil {
		return errorutils.CheckError(err)
	}
	defer tarball.Close()
	gZipReader, err := gzip.NewReader(tarball)
	if err != nil {
		return errorutils.CheckError(err)
	}

	tarReader := tar.NewReader(gZipReader)
	for {
		hdr, err := tarReader.Next()
		if err != nil {
			if err == io.EOF {
				return errorutils.CheckError(errors.New("Could not find 'package.json' in the compressed npm package: " + npc.packedFilePath))
			}
			return errorutils.CheckError(err)
		}
		if strings.HasSuffix(hdr.Name, "package.json") {
			packageJson, err := ioutil.ReadAll(tarReader)
			if err != nil {
				return errorutils.CheckError(err)
			}

			npc.packageInfo, err = npm.ReadPackageInfo(packageJson)
			return err
		}
	}
}

func deleteCreatedTarballAndError(packedFilePath string, currentError error) error {
	if err := deleteCreatedTarball(packedFilePath); err != nil {
		errorText := fmt.Sprintf("Two errors occurred: \n%s \n%s", currentError, err)
		return errorutils.CheckError(errors.New(errorText))
	}
	return currentError
}

func deleteCreatedTarball(packedFilePath string) error {
	if err := os.Remove(packedFilePath); err != nil {
		return errorutils.CheckError(err)
	}
	log.Debug("Successfully deleted the created npm package:", packedFilePath)
	return nil
}
<commit_msg>Fix stackoverflow in npm publish (#504)<commit_after>package npm

import (
	"archive/tar"
	"compress/gzip"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/jfrog/jfrog-cli-go/artifactory/utils"
	"github.com/jfrog/jfrog-cli-go/artifactory/utils/npm"
	"github.com/jfrog/jfrog-cli-go/utils/config"
	"github.com/jfrog/jfrog-client-go/artifactory/buildinfo"
	"github.com/jfrog/jfrog-client-go/artifactory/services"
	specutils "github.com/jfrog/jfrog-client-go/artifactory/services/utils"
	clientutils "github.com/jfrog/jfrog-client-go/utils"
	"github.com/jfrog/jfrog-client-go/utils/errorutils"
	"github.com/jfrog/jfrog-client-go/utils/log"
)

type NpmPublishCommandArgs struct {
	NpmCommand
	executablePath   string
	workingDirectory string
	collectBuildInfo bool
	packedFilePath   string
	packageInfo      *npm.PackageInfo
	publishPath      string
	tarballProvided  bool
	artifactData     []specutils.FileInfo
}

type NpmPublishCommand struct {
	configFilePath string
	commandName    string
	*NpmPublishCommandArgs
}

func NewNpmPublishCommand() *NpmPublishCommand {
	return &NpmPublishCommand{NpmPublishCommandArgs: NewNpmPublishCommandArgs(), commandName: "rt_npm_publish"}
}

func NewNpmPublishCommandArgs() *NpmPublishCommandArgs {
	return &NpmPublishCommandArgs{}
}

func (npc *NpmPublishCommand) RtDetails() (*config.ArtifactoryDetails, error) {
	return npc.rtDetails, nil
}

func (npc *NpmPublishCommand) SetConfigFilePath(configFilePath string) *NpmPublishCommand {
	npc.configFilePath = configFilePath
	return npc
}

func (nic *NpmPublishCommand) SetArgs(args []string) *NpmPublishCommand {
	nic.NpmPublishCommandArgs.npmArgs = args
	return nic
}

func (npc *NpmPublishCommand) Run() error {
	if npc.configFilePath != "" {
		// Read config file.
		log.Debug("Preparing to read the config file", npc.configFilePath)
		vConfig, err := utils.ReadConfigFile(npc.configFilePath, utils.YAML)
		if err != nil {
			return err
		}
		// Extract resolution params.
		deployerParams, err := utils.GetRepoConfigByPrefix(npc.configFilePath, utils.ProjectConfigDeployerPrefix, vConfig)
		if err != nil {
			return err
		}
		_, filteredNpmArgs, buildConfiguration, err := utils.ExtractNpmOptionsFromArgs(npc.NpmPublishCommandArgs.npmArgs)
		RtDetails, err := deployerParams.RtDetails()
		if err != nil {
			return errorutils.CheckError(err)
		}
		npc.SetBuildConfiguration(buildConfiguration).SetRepo(deployerParams.TargetRepo()).SetNpmArgs(filteredNpmArgs).SetRtDetails(RtDetails)
	}
	return npc.run()
}

func (npc *NpmPublishCommand) run() error {
	log.Info("Running npm Publish")
	if err := npc.preparePrerequisites(); err != nil {
		return err
	}

	if !npc.tarballProvided {
		if err := npc.pack(); err != nil {
			return err
		}
	}

	if err := npc.deploy(); err != nil {
		if npc.tarballProvided {
			return err
		}
		// We should delete the tarball we created
		return deleteCreatedTarballAndError(npc.packedFilePath, err)
	}

	if !npc.tarballProvided {
		if err := deleteCreatedTarball(npc.packedFilePath); err != nil {
			return err
		}
	}

	if !npc.collectBuildInfo {
		log.Info("npm publish finished successfully.")
		return nil
	}

	if err := npc.saveArtifactData(); err != nil {
		return err
	}

	log.Info("npm publish finished successfully.")
	return nil
}

func (npc *NpmPublishCommand) CommandName() string {
	return npc.commandName
}

func (npc *NpmPublishCommand) preparePrerequisites() error {
	log.Debug("Preparing prerequisites.")
	npmExecPath, err := exec.LookPath("npm")
	if err != nil {
		return errorutils.CheckError(err)
	}

	if npmExecPath == "" {
		return errorutils.CheckError(errors.New("Could not find 'npm' executable"))
	}

	npc.executablePath = npmExecPath
	log.Debug("Using npm executable:", npc.executablePath)
	currentDir, err := os.Getwd()
	if err != nil {
		return errorutils.CheckError(err)
	}

	currentDir, err = filepath.Abs(currentDir)
	if err != nil {
		return errorutils.CheckError(err)
	}

	npc.workingDirectory = currentDir
	log.Debug("Working directory set to:", npc.workingDirectory)
	npc.collectBuildInfo = len(npc.buildConfiguration.BuildName) > 0 && len(npc.buildConfiguration.BuildNumber) > 0
	if err = npc.setPublishPath(); err != nil {
		return err
	}

	artDetails, err := npc.rtDetails.CreateArtAuthConfig()
	if err != nil {
		return err
	}

	if err = utils.CheckIfRepoExists(npc.repo, artDetails); err != nil {
		return err
	}

	return npc.setPackageInfo()
}

func (npc *NpmPublishCommand) pack() error {
	log.Debug("Creating npm package.")
	if err := npm.Pack(npc.npmArgs, npc.executablePath); err != nil {
		return err
	}

	npc.packedFilePath = filepath.Join(npc.workingDirectory, npc.packageInfo.GetExpectedPackedFileName())
	log.Debug("Created npm package at", npc.packedFilePath)
	return nil
}

func (npc *NpmPublishCommand) deploy() (err error) {
	log.Debug("Deploying npm package.")
	if err = npc.readPackageInfoFromTarball(); err != nil {
		return err
	}

	target := fmt.Sprintf("%s/%s", npc.repo, npc.packageInfo.GetDeployPath())
	artifactsFileInfo, err := npc.doDeploy(target, npc.rtDetails)
	if err != nil {
		return err
	}

	npc.artifactData = artifactsFileInfo
	return nil
}

func (npc *NpmPublishCommand) doDeploy(target string, artDetails *config.ArtifactoryDetails) (artifactsFileInfo []specutils.FileInfo, err error) {
	servicesManager, err := utils.CreateServiceManager(artDetails, false)
	if err != nil {
		return nil, err
	}
	up := services.UploadParams{}
	up.ArtifactoryCommonParams = &specutils.ArtifactoryCommonParams{Pattern: npc.packedFilePath, Target: target}
	if npc.collectBuildInfo {
		utils.SaveBuildGeneralDetails(npc.buildConfiguration.BuildName, npc.buildConfiguration.BuildNumber)
		props, err := utils.CreateBuildProperties(npc.buildConfiguration.BuildName, npc.buildConfiguration.BuildNumber)
		if err != nil {
			return nil, err
		}
		up.ArtifactoryCommonParams.Props = props
	}
	artifactsFileInfo, _, failed, err := servicesManager.UploadFiles(up)
	if err != nil {
		return nil, err
	}

	// We deploying only one Artifact which have to be deployed, in case of failure we should fail
	if failed > 0 {
		return nil, errorutils.CheckError(errors.New("Failed to upload the npm package to Artifactory. See Artifactory logs for more details."))
	}
	return artifactsFileInfo, nil
}

func (npc *NpmPublishCommand) saveArtifactData() error {
	log.Debug("Saving npm package artifact build info data.")
	var buildArtifacts []buildinfo.Artifact
	for _, artifact := range npc.artifactData {
		buildArtifacts = append(buildArtifacts, artifact.ToBuildArtifacts())
	}

	populateFunc := func(partial *buildinfo.Partial) {
		partial.Artifacts = buildArtifacts
		if npc.buildConfiguration.Module == "" {
			npc.buildConfiguration.Module = npc.packageInfo.BuildInfoModuleId()
		}
		partial.ModuleId = npc.buildConfiguration.Module
	}
	return utils.SavePartialBuildInfo(npc.buildConfiguration.BuildName, npc.buildConfiguration.BuildNumber, populateFunc)
}

func (npc *NpmPublishCommand) setPublishPath() error {
	log.Debug("Reading Package Json.")

	npc.publishPath = npc.workingDirectory
	if len(npc.npmArgs) > 0 && !strings.HasPrefix(strings.TrimSpace(npc.npmArgs[0]), "-") {
		path := strings.TrimSpace(npc.npmArgs[0])
		path = clientutils.ReplaceTildeWithUserHome(path)

		if filepath.IsAbs(path) {
			npc.publishPath = path
		} else {
			npc.publishPath = filepath.Join(npc.workingDirectory, path)
		}
	}
	return nil
}

func (npc *NpmPublishCommand) setPackageInfo() error {
	log.Debug("Setting Package Info.")
	fileInfo, err := os.Stat(npc.publishPath)
	if err != nil {
		return errorutils.CheckError(err)
	}

	if fileInfo.IsDir() {
		npc.packageInfo, err = npm.ReadPackageInfoFromPackageJson(npc.publishPath)
		return err
	}
	log.Debug("The provided path is not a directory, we assume this is a compressed npm package")
	npc.tarballProvided = true
	npc.packedFilePath = npc.publishPath
	return npc.readPackageInfoFromTarball()
}

func (npc *NpmPublishCommand) readPackageInfoFromTarball() error {
	log.Debug("Extracting info from npm package:", npc.packedFilePath)
	tarball, err := os.Open(npc.packedFilePath)
	if err != nil {
		return errorutils.CheckError(err)
	}
	defer tarball.Close()
	gZipReader, err := gzip.NewReader(tarball)
	if err != nil {
		return errorutils.CheckError(err)
	}

	tarReader := tar.NewReader(gZipReader)
	for {
		hdr, err := tarReader.Next()
		if err != nil {
			if err == io.EOF {
				return errorutils.CheckError(errors.New("Could not find 'package.json' in the compressed npm package: " + npc.packedFilePath))
			}
			return errorutils.CheckError(err)
		}
		if strings.HasSuffix(hdr.Name, "package.json") {
			packageJson, err := ioutil.ReadAll(tarReader)
			if err != nil {
				return errorutils.CheckError(err)
			}

			npc.packageInfo, err = npm.ReadPackageInfo(packageJson)
			return err
		}
	}
}

func deleteCreatedTarballAndError(packedFilePath string, currentError error) error {
	if err := deleteCreatedTarball(packedFilePath); err != nil {
		errorText := fmt.Sprintf("Two errors occurred: \n%s \n%s", currentError, err)
		return errorutils.CheckError(errors.New(errorText))
	}
	return currentError
}

func deleteCreatedTarball(packedFilePath string) error {
	if err := os.Remove(packedFilePath); err != nil {
		return errorutils.CheckError(err)
	}
	log.Debug("Successfully deleted the created npm package:", packedFilePath)
	return nil
}
<|endoftext|>


<commit_before>package main

import (
    "web"
    "strings"
    "godis"
    "fmt"
    "os"
    "url"
    "flag"
    "strconv"
    "time"
    "json"
    "http"
)

const(
    // special key in redis, that is our global counter
    COUNTER = "__counter__"
    HTTP = "http"
    ROLL = "https://www.youtube.com/watch?v=jRHmvy5eaG4"
)

var (
    redis *godis.Client
    config *Config
)

type KurzUrl struct{
    Key string
    ShortUrl string
    LongUrl string
    CreationDate int64
    Clicks int64
}

// Converts the KurzUrl to JSON.
func (k KurzUrl) Json()[]byte{
    b, _ := json.Marshal(k)
    return b
}

// Creates a new KurzUrl instance. The Given key, shorturl and longurl will
// be used. Clicks will be set to 0 and CreationDate to time.Nanoseconds()
func NewKurzUrl(key, shorturl, longurl string) *KurzUrl{
    kurl := new(KurzUrl)
    kurl.CreationDate = time.Nanoseconds()
    kurl.Key = key
    kurl.LongUrl = longurl
    kurl.ShortUrl = shorturl
    kurl.Clicks = 0
    return kurl
}

func info(ctx *web.Context, short string) {
    kurl, err :=  load(short)
    if err == nil{
        ctx.SetHeader("Content-Type", "application/json", true)
        ctx.Write(kurl.Json())
        ctx.WriteString("\n")
    } else{
        ctx.Redirect(http.StatusNotFound, ROLL)
    }
}
// function to resolve a shorturl and redirect
func resolve(ctx *web.Context, short string) {
    if strings.HasSuffix(short, "+"){
        info(ctx, strings.Replace(short, "+", "", 1))
        return
    }
    redirect, err := redis.Hget(short, "LongUrl")
    if err == nil {
        go redis.Hincrby(short, "Clicks", 1)
        ctx.Redirect(http.StatusMovedPermanently,
             redirect.String())
    } else {
        ctx.Redirect(http.StatusMovedPermanently,
            ROLL)
    }
}

// Determines if the string rawurl is a valid URL to be stored.
func isValidUrl(rawurl string) (u *url.URL, err os.Error){
    if len(rawurl) == 0{
        return nil, os.NewError("empty url")
    }
    // XXX this needs some love...
    if !strings.HasPrefix(rawurl, HTTP){
        rawurl = fmt.Sprintf("%s://%s", HTTP, rawurl)
    }
    return url.Parse(rawurl)
}

// stores a new KurzUrl for the given key, shorturl and longurl. Existing
// ones with the same url will be overwritten
func store(key, shorturl, longurl string)*KurzUrl{
    kurl := NewKurzUrl(key, shorturl, longurl)
    go redis.Hset(kurl.Key, "LongUrl", kurl.LongUrl)
    go redis.Hset(kurl.Key, "ShortUrl", kurl.ShortUrl)
    go redis.Hset(kurl.Key, "CreationDate", kurl.CreationDate)
    go redis.Hset(kurl.Key, "Clicks", kurl.Clicks)
    return kurl
}

// loads a KurzUrl instance for the given key. If the key is
// not found, os.Error is returned.
func load(key string) (kurl *KurzUrl, err os.Error){
    if ok, _ := redis.Hexists(key, "ShortUrl"); ok{
        kurl := new(KurzUrl)
        kurl.Key = key
        reply, _ := redis.Hmget(key, "LongUrl", "ShortUrl", "CreationDate", "Clicks")
        kurl.LongUrl, kurl.ShortUrl, kurl.CreationDate, kurl.Clicks =
            reply.Elems[0].Elem.String(), reply.Elems[1].Elem.String(),
            reply.Elems[2].Elem.Int64(), reply.Elems[3].Elem.Int64()
        return kurl, nil
    }
    return nil, os.NewError("unknown key: " + key )
}

// function to shorten and store a url
func shorten(ctx *web.Context, data string){
    host := config.GetStringDefault("hostname", "localhost")
    r, _ := ctx.Request.Params["url"]
    theUrl, err := isValidUrl(string(r))
    if err == nil{
        ctr, _ := redis.Incr(COUNTER)
        encoded := Encode(ctr)
        location := fmt.Sprintf("%s://%s/%s", HTTP, host, encoded)

        kurl := store(encoded, location, theUrl.Raw)

        ctx.SetHeader("Content-Type", "application/json", true)
        ctx.SetHeader("Location", location, true)
        ctx.StartResponse(http.StatusCreated)
        ctx.Write(kurl.Json())
        ctx.WriteString("\n")
    }else{
       ctx.Redirect(http.StatusNotFound, ROLL)
    }
}

func latest(ctx *web.Context, data string){
    howmany, err := strconv.Atoi64(data)
    if err != nil {
        howmany = 10
    }
    c, _ := redis.Get(COUNTER)

    last := c.Int64()
    upTo := (last - howmany)

    ctx.SetHeader("Content-Type", "application/json", true)
    ctx.WriteString("{ \"urls\" : [")
    for i := last; i > upTo && i > 0; i -= 1{
        kurl, err := load(Encode(i))
        if err == nil{
            ctx.Write(kurl.Json())
            if i != upTo + 1 {
                ctx.WriteString(",")
            }
        }
    }
    ctx.WriteString("] }")
    ctx.WriteString("\n")
}

// bootstraps the server
func bootstrap(path string) os.Error {
    config = NewConfig(path)
    config.Parse()

    host := config.GetStringDefault("redis.address", "tcp:localhost:6379")
    db := config.GetIntDefault("redis.database", 0)
    passwd := config.GetStringDefault("redis.password", "")

    redis = godis.New(host, db, passwd)

    web.Config.StaticDir = config.GetStringDefault("static-directory", "")

    web.Post("/shorten/(.*)", shorten)
    web.Get("/latest/(.*)", latest)
    web.Get("/info/(.*)", info)
    web.Get("/(.*)", resolve)

    return nil
}

// main function that starts everything
func main() {
    flag.Parse()
    cfgFile := flag.Arg(0)
    err := bootstrap(cfgFile)
    if err == nil {
                listen := config.GetStringDefault("listen", "0.0.0.0")
        port := config.GetStringDefault("port", "9999")
        web.Run(fmt.Sprintf("%s:%s", listen, port))
    }
}

<commit_msg>refactoring of regexes to have a faster and more stable routing within the app<commit_after>package main

import (
    "web"
    "strings"
    "godis"
    "fmt"
    "os"
    "url"
    "flag"
    "strconv"
    "time"
    "json"
    "http"
)

const(
    // special key in redis, that is our global counter
    COUNTER = "__counter__"
    HTTP = "http"
    ROLL = "https://www.youtube.com/watch?v=jRHmvy5eaG4"
)

var (
    redis *godis.Client
    config *Config
)

type KurzUrl struct{
    Key string
    ShortUrl string
    LongUrl string
    CreationDate int64
    Clicks int64
}

// Converts the KurzUrl to JSON.
func (k KurzUrl) Json()[]byte{
    b, _ := json.Marshal(k)
    return b
}

// Creates a new KurzUrl instance. The Given key, shorturl and longurl will
// be used. Clicks will be set to 0 and CreationDate to time.Nanoseconds()
func NewKurzUrl(key, shorturl, longurl string) *KurzUrl{
    kurl := new(KurzUrl)
    kurl.CreationDate = time.Nanoseconds()
    kurl.Key = key
    kurl.LongUrl = longurl
    kurl.ShortUrl = shorturl
    kurl.Clicks = 0
    return kurl
}

func info(ctx *web.Context, short string) {
    if strings.HasSuffix(short, "+"){
        short = strings.Replace(short, "+", "", 1)
    }

    kurl, err :=  load(short)
    if err == nil{
        ctx.SetHeader("Content-Type", "application/json", true)
        ctx.Write(kurl.Json())
        ctx.WriteString("\n")
    } else{
        ctx.Redirect(http.StatusNotFound, ROLL)
    }
}
// function to resolve a shorturl and redirect
func resolve(ctx *web.Context, short string) {
        redirect, err := redis.Hget(short, "LongUrl")
    if err == nil {
        go redis.Hincrby(short, "Clicks", 1)
        ctx.Redirect(http.StatusMovedPermanently,
             redirect.String())
    } else {
        ctx.Redirect(http.StatusMovedPermanently,
            ROLL)
    }
}

// Determines if the string rawurl is a valid URL to be stored.
func isValidUrl(rawurl string) (u *url.URL, err os.Error){
    if len(rawurl) == 0{
        return nil, os.NewError("empty url")
    }
    // XXX this needs some love...
    if !strings.HasPrefix(rawurl, HTTP){
        rawurl = fmt.Sprintf("%s://%s", HTTP, rawurl)
    }
    return url.Parse(rawurl)
}

// stores a new KurzUrl for the given key, shorturl and longurl. Existing
// ones with the same url will be overwritten
func store(key, shorturl, longurl string)*KurzUrl{
    kurl := NewKurzUrl(key, shorturl, longurl)
    go redis.Hset(kurl.Key, "LongUrl", kurl.LongUrl)
    go redis.Hset(kurl.Key, "ShortUrl", kurl.ShortUrl)
    go redis.Hset(kurl.Key, "CreationDate", kurl.CreationDate)
    go redis.Hset(kurl.Key, "Clicks", kurl.Clicks)
    return kurl
}

// loads a KurzUrl instance for the given key. If the key is
// not found, os.Error is returned.
func load(key string) (kurl *KurzUrl, err os.Error){
    if ok, _ := redis.Hexists(key, "ShortUrl"); ok{
        kurl := new(KurzUrl)
        kurl.Key = key
        reply, _ := redis.Hmget(key, "LongUrl", "ShortUrl", "CreationDate", "Clicks")
        kurl.LongUrl, kurl.ShortUrl, kurl.CreationDate, kurl.Clicks =
            reply.Elems[0].Elem.String(), reply.Elems[1].Elem.String(),
            reply.Elems[2].Elem.Int64(), reply.Elems[3].Elem.Int64()
        return kurl, nil
    }
    return nil, os.NewError("unknown key: " + key )
}

// function to shorten and store a url
func shorten(ctx *web.Context, data string){
    host := config.GetStringDefault("hostname", "localhost")
    r, _ := ctx.Request.Params["url"]
    theUrl, err := isValidUrl(string(r))
    if err == nil{
        ctr, _ := redis.Incr(COUNTER)
        encoded := Encode(ctr)
        location := fmt.Sprintf("%s://%s/%s", HTTP, host, encoded)

        kurl := store(encoded, location, theUrl.Raw)

        ctx.SetHeader("Content-Type", "application/json", true)
        ctx.SetHeader("Location", location, true)
        ctx.StartResponse(http.StatusCreated)
        ctx.Write(kurl.Json())
        ctx.WriteString("\n")
    }else{
       ctx.Redirect(http.StatusNotFound, ROLL)
    }
}

func latest(ctx *web.Context, data string){
    howmany, err := strconv.Atoi64(data)
    if err != nil {
        howmany = 10
    }
    c, _ := redis.Get(COUNTER)

    last := c.Int64()
    upTo := (last - howmany)

    ctx.SetHeader("Content-Type", "application/json", true)
    ctx.WriteString("{ \"urls\" : [")
    for i := last; i > upTo && i > 0; i -= 1{
        kurl, err := load(Encode(i))
        if err == nil{
            ctx.Write(kurl.Json())
            if i != upTo + 1 {
                ctx.WriteString(",")
            }
        }
    }
    ctx.WriteString("] }")
    ctx.WriteString("\n")
}

// bootstraps the server
func bootstrap(path string) os.Error {
    config = NewConfig(path)
    config.Parse()

    host := config.GetStringDefault("redis.address", "tcp:localhost:6379")
    db := config.GetIntDefault("redis.database", 0)
    passwd := config.GetStringDefault("redis.password", "")

    redis = godis.New(host, db, passwd)

    web.Config.StaticDir = config.GetStringDefault("static-directory", "")

    web.Post("/shorten/(.*)", shorten)

    web.Get("/([a-zA-Z0-9]*)", resolve)
    web.Get("/([a-zA-Z0-9]*)\\+", info)
    web.Get("/latest/([0-9]*)", latest)
    web.Get("/info/([a-zA-Z0-9]*)", info)

    return nil
}

// main function that starts everything
func main() {
    flag.Parse()
    cfgFile := flag.Arg(0)
    err := bootstrap(cfgFile)
    if err == nil {
                listen := config.GetStringDefault("listen", "0.0.0.0")
        port := config.GetStringDefault("port", "9999")
        web.Run(fmt.Sprintf("%s:%s", listen, port))
    }
}

<|endoftext|>


<commit_before>package azurerm

import (
	"fmt"
	"log"
	"regexp"

	"github.com/Azure/azure-sdk-for-go/arm/keyvault"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/helper/validation"
	"github.com/satori/uuid"
	"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

// As can be seen in the API definition, the Sku Family only supports the value
// `A` and is a required field
// https://github.com/Azure/azure-rest-api-specs/blob/master/arm-keyvault/2015-06-01/swagger/keyvault.json#L239
var armKeyVaultSkuFamily = "A"

func resourceArmKeyVault() *schema.Resource {
	return &schema.Resource{
		Create: resourceArmKeyVaultCreate,
		Read:   resourceArmKeyVaultRead,
		Update: resourceArmKeyVaultCreate,
		Delete: resourceArmKeyVaultDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

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

			"location": locationSchema(),

			"resource_group_name": resourceGroupNameSchema(),

			"sku": {
				Type:     schema.TypeSet,
				Required: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"name": {
							Type:     schema.TypeString,
							Required: true,
							ValidateFunc: validation.StringInSlice([]string{
								string(keyvault.Standard),
								string(keyvault.Premium),
							}, false),
						},
					},
				},
			},

			"vault_uri": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"tenant_id": {
				Type:         schema.TypeString,
				Required:     true,
				ValidateFunc: validateUUID,
			},

			"access_policy": {
				Type:     schema.TypeList,
				Optional: true,
				MinItems: 1,
				MaxItems: 16,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"tenant_id": {
							Type:         schema.TypeString,
							Required:     true,
							ValidateFunc: validateUUID,
						},
						"object_id": {
							Type:         schema.TypeString,
							Required:     true,
							ValidateFunc: validateUUID,
						},
						"application_id": {
							Type:         schema.TypeString,
							Optional:     true,
							ValidateFunc: validateUUID,
						},
						"certificate_permissions": {
							Type:     schema.TypeList,
							Optional: true,
							Elem: &schema.Schema{
								Type: schema.TypeString,
								ValidateFunc: validation.StringInSlice([]string{
									string(keyvault.All),
									string(keyvault.Create),
									string(keyvault.Delete),
									string(keyvault.Deleteissuers),
									string(keyvault.Get),
									string(keyvault.Getissuers),
									string(keyvault.Import),
									string(keyvault.List),
									string(keyvault.Listissuers),
									string(keyvault.Managecontacts),
									string(keyvault.Manageissuers),
									string(keyvault.Setissuers),
									string(keyvault.Update),
								}, true),
								DiffSuppressFunc: ignoreCaseDiffSuppressFunc,
							},
						},
						"key_permissions": {
							Type:     schema.TypeList,
							Required: true,
							Elem: &schema.Schema{
								Type: schema.TypeString,
								ValidateFunc: validation.StringInSlice([]string{
									string(keyvault.KeyPermissionsAll),
									string(keyvault.KeyPermissionsBackup),
									string(keyvault.KeyPermissionsCreate),
									string(keyvault.KeyPermissionsDecrypt),
									string(keyvault.KeyPermissionsDelete),
									string(keyvault.KeyPermissionsEncrypt),
									string(keyvault.KeyPermissionsGet),
									string(keyvault.KeyPermissionsImport),
									string(keyvault.KeyPermissionsList),
									string(keyvault.KeyPermissionsRestore),
									string(keyvault.KeyPermissionsSign),
									string(keyvault.KeyPermissionsUnwrapKey),
									string(keyvault.KeyPermissionsUpdate),
									string(keyvault.KeyPermissionsVerify),
									string(keyvault.KeyPermissionsWrapKey),
								}, true),
								DiffSuppressFunc: ignoreCaseDiffSuppressFunc,
							},
						},
						"secret_permissions": {
							Type:     schema.TypeList,
							Required: true,
							Elem: &schema.Schema{
								Type: schema.TypeString,
								ValidateFunc: validation.StringInSlice([]string{
									string(keyvault.SecretPermissionsAll),
									string(keyvault.SecretPermissionsDelete),
									string(keyvault.SecretPermissionsGet),
									string(keyvault.SecretPermissionsList),
									string(keyvault.SecretPermissionsSet),
								}, true),
								DiffSuppressFunc: ignoreCaseDiffSuppressFunc,
							},
						},
					},
				},
			},

			"enabled_for_deployment": {
				Type:     schema.TypeBool,
				Optional: true,
			},

			"enabled_for_disk_encryption": {
				Type:     schema.TypeBool,
				Optional: true,
			},

			"enabled_for_template_deployment": {
				Type:     schema.TypeBool,
				Optional: true,
			},

			"tags": tagsSchema(),
		},
	}
}

func resourceArmKeyVaultCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).keyVaultClient
	log.Printf("[INFO] preparing arguments for Azure ARM KeyVault creation.")

	name := d.Get("name").(string)
	location := d.Get("location").(string)
	resGroup := d.Get("resource_group_name").(string)
	tenantUUID := uuid.FromStringOrNil(d.Get("tenant_id").(string))
	enabledForDeployment := d.Get("enabled_for_deployment").(bool)
	enabledForDiskEncryption := d.Get("enabled_for_disk_encryption").(bool)
	enabledForTemplateDeployment := d.Get("enabled_for_template_deployment").(bool)
	tags := d.Get("tags").(map[string]interface{})

	parameters := keyvault.VaultCreateOrUpdateParameters{
		Location: &location,
		Properties: &keyvault.VaultProperties{
			TenantID:                     &tenantUUID,
			Sku:                          expandKeyVaultSku(d),
			AccessPolicies:               expandKeyVaultAccessPolicies(d),
			EnabledForDeployment:         &enabledForDeployment,
			EnabledForDiskEncryption:     &enabledForDiskEncryption,
			EnabledForTemplateDeployment: &enabledForTemplateDeployment,
		},
		Tags: expandTags(tags),
	}

	_, err := client.CreateOrUpdate(resGroup, name, parameters)
	if err != nil {
		return err
	}

	read, err := client.Get(resGroup, name)
	if err != nil {
		return err
	}
	if read.ID == nil {
		return fmt.Errorf("Cannot read KeyVault %s (resource group %s) ID", name, resGroup)
	}

	d.SetId(*read.ID)

	return resourceArmKeyVaultRead(d, meta)
}

func resourceArmKeyVaultRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).keyVaultClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}
	resGroup := id.ResourceGroup
	name := id.Path["vaults"]

	resp, err := client.Get(resGroup, name)
	if err != nil {
		if utils.ResponseWasNotFound(resp.Response) {
			d.SetId("")
			return nil
		}
		return fmt.Errorf("Error making Read request on Azure KeyVault %s: %+v", name, err)
	}

	d.Set("name", resp.Name)
	d.Set("resource_group_name", resGroup)
	d.Set("location", azureRMNormalizeLocation(*resp.Location))
	d.Set("tenant_id", resp.Properties.TenantID.String())
	d.Set("enabled_for_deployment", resp.Properties.EnabledForDeployment)
	d.Set("enabled_for_disk_encryption", resp.Properties.EnabledForDiskEncryption)
	d.Set("enabled_for_template_deployment", resp.Properties.EnabledForTemplateDeployment)
	d.Set("sku", flattenKeyVaultSku(resp.Properties.Sku))
	d.Set("access_policy", flattenKeyVaultAccessPolicies(resp.Properties.AccessPolicies))
	d.Set("vault_uri", resp.Properties.VaultURI)

	flattenAndSetTags(d, resp.Tags)

	return nil
}

func resourceArmKeyVaultDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).keyVaultClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}
	resGroup := id.ResourceGroup
	name := id.Path["vaults"]

	_, err = client.Delete(resGroup, name)

	return err
}

func expandKeyVaultSku(d *schema.ResourceData) *keyvault.Sku {
	skuSets := d.Get("sku").(*schema.Set).List()
	sku := skuSets[0].(map[string]interface{})

	return &keyvault.Sku{
		Family: &armKeyVaultSkuFamily,
		Name:   keyvault.SkuName(sku["name"].(string)),
	}
}

func expandKeyVaultAccessPolicies(d *schema.ResourceData) *[]keyvault.AccessPolicyEntry {
	policies := d.Get("access_policy").([]interface{})
	result := make([]keyvault.AccessPolicyEntry, 0, len(policies))

	for _, policySet := range policies {
		policyRaw := policySet.(map[string]interface{})

		certificatePermissionsRaw := policyRaw["certificate_permissions"].([]interface{})
		certificatePermissions := []keyvault.CertificatePermissions{}
		for _, permission := range certificatePermissionsRaw {
			certificatePermissions = append(certificatePermissions, keyvault.CertificatePermissions(permission.(string)))
		}

		keyPermissionsRaw := policyRaw["key_permissions"].([]interface{})
		keyPermissions := []keyvault.KeyPermissions{}
		for _, permission := range keyPermissionsRaw {
			keyPermissions = append(keyPermissions, keyvault.KeyPermissions(permission.(string)))
		}

		secretPermissionsRaw := policyRaw["secret_permissions"].([]interface{})
		secretPermissions := []keyvault.SecretPermissions{}
		for _, permission := range secretPermissionsRaw {
			secretPermissions = append(secretPermissions, keyvault.SecretPermissions(permission.(string)))
		}

		policy := keyvault.AccessPolicyEntry{
			Permissions: &keyvault.Permissions{
				Certificates: &certificatePermissions,
				Keys:         &keyPermissions,
				Secrets:      &secretPermissions,
			},
		}

		tenantUUID := uuid.FromStringOrNil(policyRaw["tenant_id"].(string))
		policy.TenantID = &tenantUUID
		objectUUID := policyRaw["object_id"].(string)
		policy.ObjectID = &objectUUID

		if v := policyRaw["application_id"]; v != "" {
			applicationUUID := uuid.FromStringOrNil(v.(string))
			policy.ApplicationID = &applicationUUID
		}

		result = append(result, policy)
	}

	return &result
}

func flattenKeyVaultSku(sku *keyvault.Sku) []interface{} {
	result := map[string]interface{}{
		"name": string(sku.Name),
	}

	return []interface{}{result}
}

func flattenKeyVaultAccessPolicies(policies *[]keyvault.AccessPolicyEntry) []interface{} {
	result := make([]interface{}, 0, len(*policies))

	for _, policy := range *policies {
		policyRaw := make(map[string]interface{})

		keyPermissionsRaw := make([]interface{}, 0, len(*policy.Permissions.Keys))
		for _, keyPermission := range *policy.Permissions.Keys {
			keyPermissionsRaw = append(keyPermissionsRaw, string(keyPermission))
		}

		secretPermissionsRaw := make([]interface{}, 0, len(*policy.Permissions.Secrets))
		for _, secretPermission := range *policy.Permissions.Secrets {
			secretPermissionsRaw = append(secretPermissionsRaw, string(secretPermission))
		}

		policyRaw["tenant_id"] = policy.TenantID.String()
		policyRaw["object_id"] = *policy.ObjectID
		if policy.ApplicationID != nil {
			policyRaw["application_id"] = policy.ApplicationID.String()
		}
		policyRaw["key_permissions"] = keyPermissionsRaw
		policyRaw["secret_permissions"] = secretPermissionsRaw

		if policy.Permissions.Certificates != nil {
			certificatePermissionsRaw := make([]interface{}, 0, len(*policy.Permissions.Certificates))
			for _, certificatePermission := range *policy.Permissions.Certificates {
				certificatePermissionsRaw = append(certificatePermissionsRaw, string(certificatePermission))
			}
			policyRaw["certificate_permissions"] = certificatePermissionsRaw
		}

		result = append(result, policyRaw)
	}

	return result
}

func validateKeyVaultName(v interface{}, k string) (ws []string, errors []error) {
	value := v.(string)
	if matched := regexp.MustCompile(`^[a-zA-Z0-9-]{3,24}$`).Match([]byte(value)); !matched {
		errors = append(errors, fmt.Errorf("%q may only contain alphanumeric characters and dashes and must be between 3-24 chars", k))
	}

	return
}
<commit_msg>Ensuring the Key Vault is available before completion<commit_after>package azurerm

import (
	"fmt"
	"log"
	"regexp"

	"time"

	"net"

	"github.com/Azure/azure-sdk-for-go/arm/keyvault"
	"github.com/hashicorp/go-getter/helper/url"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/helper/validation"
	"github.com/satori/uuid"
	"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

// As can be seen in the API definition, the Sku Family only supports the value
// `A` and is a required field
// https://github.com/Azure/azure-rest-api-specs/blob/master/arm-keyvault/2015-06-01/swagger/keyvault.json#L239
var armKeyVaultSkuFamily = "A"

func resourceArmKeyVault() *schema.Resource {
	return &schema.Resource{
		Create: resourceArmKeyVaultCreate,
		Read:   resourceArmKeyVaultRead,
		Update: resourceArmKeyVaultCreate,
		Delete: resourceArmKeyVaultDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

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

			"location": locationSchema(),

			"resource_group_name": resourceGroupNameSchema(),

			"sku": {
				Type:     schema.TypeSet,
				Required: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"name": {
							Type:     schema.TypeString,
							Required: true,
							ValidateFunc: validation.StringInSlice([]string{
								string(keyvault.Standard),
								string(keyvault.Premium),
							}, false),
						},
					},
				},
			},

			"vault_uri": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"tenant_id": {
				Type:         schema.TypeString,
				Required:     true,
				ValidateFunc: validateUUID,
			},

			"access_policy": {
				Type:     schema.TypeList,
				Optional: true,
				MinItems: 1,
				MaxItems: 16,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"tenant_id": {
							Type:         schema.TypeString,
							Required:     true,
							ValidateFunc: validateUUID,
						},
						"object_id": {
							Type:         schema.TypeString,
							Required:     true,
							ValidateFunc: validateUUID,
						},
						"application_id": {
							Type:         schema.TypeString,
							Optional:     true,
							ValidateFunc: validateUUID,
						},
						"certificate_permissions": {
							Type:     schema.TypeList,
							Optional: true,
							Elem: &schema.Schema{
								Type: schema.TypeString,
								ValidateFunc: validation.StringInSlice([]string{
									string(keyvault.All),
									string(keyvault.Create),
									string(keyvault.Delete),
									string(keyvault.Deleteissuers),
									string(keyvault.Get),
									string(keyvault.Getissuers),
									string(keyvault.Import),
									string(keyvault.List),
									string(keyvault.Listissuers),
									string(keyvault.Managecontacts),
									string(keyvault.Manageissuers),
									string(keyvault.Setissuers),
									string(keyvault.Update),
								}, true),
								DiffSuppressFunc: ignoreCaseDiffSuppressFunc,
							},
						},
						"key_permissions": {
							Type:     schema.TypeList,
							Required: true,
							Elem: &schema.Schema{
								Type: schema.TypeString,
								ValidateFunc: validation.StringInSlice([]string{
									string(keyvault.KeyPermissionsAll),
									string(keyvault.KeyPermissionsBackup),
									string(keyvault.KeyPermissionsCreate),
									string(keyvault.KeyPermissionsDecrypt),
									string(keyvault.KeyPermissionsDelete),
									string(keyvault.KeyPermissionsEncrypt),
									string(keyvault.KeyPermissionsGet),
									string(keyvault.KeyPermissionsImport),
									string(keyvault.KeyPermissionsList),
									string(keyvault.KeyPermissionsRestore),
									string(keyvault.KeyPermissionsSign),
									string(keyvault.KeyPermissionsUnwrapKey),
									string(keyvault.KeyPermissionsUpdate),
									string(keyvault.KeyPermissionsVerify),
									string(keyvault.KeyPermissionsWrapKey),
								}, true),
								DiffSuppressFunc: ignoreCaseDiffSuppressFunc,
							},
						},
						"secret_permissions": {
							Type:     schema.TypeList,
							Required: true,
							Elem: &schema.Schema{
								Type: schema.TypeString,
								ValidateFunc: validation.StringInSlice([]string{
									string(keyvault.SecretPermissionsAll),
									string(keyvault.SecretPermissionsDelete),
									string(keyvault.SecretPermissionsGet),
									string(keyvault.SecretPermissionsList),
									string(keyvault.SecretPermissionsSet),
								}, true),
								DiffSuppressFunc: ignoreCaseDiffSuppressFunc,
							},
						},
					},
				},
			},

			"enabled_for_deployment": {
				Type:     schema.TypeBool,
				Optional: true,
			},

			"enabled_for_disk_encryption": {
				Type:     schema.TypeBool,
				Optional: true,
			},

			"enabled_for_template_deployment": {
				Type:     schema.TypeBool,
				Optional: true,
			},

			"tags": tagsSchema(),
		},
	}
}

func resourceArmKeyVaultCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).keyVaultClient
	log.Printf("[INFO] preparing arguments for Azure ARM KeyVault creation.")

	name := d.Get("name").(string)
	location := d.Get("location").(string)
	resGroup := d.Get("resource_group_name").(string)
	tenantUUID := uuid.FromStringOrNil(d.Get("tenant_id").(string))
	enabledForDeployment := d.Get("enabled_for_deployment").(bool)
	enabledForDiskEncryption := d.Get("enabled_for_disk_encryption").(bool)
	enabledForTemplateDeployment := d.Get("enabled_for_template_deployment").(bool)
	tags := d.Get("tags").(map[string]interface{})

	parameters := keyvault.VaultCreateOrUpdateParameters{
		Location: &location,
		Properties: &keyvault.VaultProperties{
			TenantID:                     &tenantUUID,
			Sku:                          expandKeyVaultSku(d),
			AccessPolicies:               expandKeyVaultAccessPolicies(d),
			EnabledForDeployment:         &enabledForDeployment,
			EnabledForDiskEncryption:     &enabledForDiskEncryption,
			EnabledForTemplateDeployment: &enabledForTemplateDeployment,
		},
		Tags: expandTags(tags),
	}

	_, err := client.CreateOrUpdate(resGroup, name, parameters)
	if err != nil {
		return err
	}

	read, err := client.Get(resGroup, name)
	if err != nil {
		return err
	}
	if read.ID == nil {
		return fmt.Errorf("Cannot read KeyVault %s (resource group %s) ID", name, resGroup)
	}

	d.SetId(*read.ID)

	if d.IsNewResource() {
		if props := read.Properties; props != nil {
			if vault := props.VaultURI; vault != nil {
				err := resource.Retry(30*time.Second, checkKeyVaultDNSIsAvailable(*vault))
				if err != nil {
					return err
				}
			}
		}
	}

	return resourceArmKeyVaultRead(d, meta)
}

func resourceArmKeyVaultRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).keyVaultClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}
	resGroup := id.ResourceGroup
	name := id.Path["vaults"]

	resp, err := client.Get(resGroup, name)
	if err != nil {
		if utils.ResponseWasNotFound(resp.Response) {
			d.SetId("")
			return nil
		}
		return fmt.Errorf("Error making Read request on Azure KeyVault %s: %+v", name, err)
	}

	d.Set("name", resp.Name)
	d.Set("resource_group_name", resGroup)
	d.Set("location", azureRMNormalizeLocation(*resp.Location))
	d.Set("tenant_id", resp.Properties.TenantID.String())
	d.Set("enabled_for_deployment", resp.Properties.EnabledForDeployment)
	d.Set("enabled_for_disk_encryption", resp.Properties.EnabledForDiskEncryption)
	d.Set("enabled_for_template_deployment", resp.Properties.EnabledForTemplateDeployment)
	d.Set("sku", flattenKeyVaultSku(resp.Properties.Sku))
	d.Set("access_policy", flattenKeyVaultAccessPolicies(resp.Properties.AccessPolicies))
	d.Set("vault_uri", resp.Properties.VaultURI)

	flattenAndSetTags(d, resp.Tags)

	return nil
}

func resourceArmKeyVaultDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).keyVaultClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}
	resGroup := id.ResourceGroup
	name := id.Path["vaults"]

	_, err = client.Delete(resGroup, name)

	return err
}

func expandKeyVaultSku(d *schema.ResourceData) *keyvault.Sku {
	skuSets := d.Get("sku").(*schema.Set).List()
	sku := skuSets[0].(map[string]interface{})

	return &keyvault.Sku{
		Family: &armKeyVaultSkuFamily,
		Name:   keyvault.SkuName(sku["name"].(string)),
	}
}

func expandKeyVaultAccessPolicies(d *schema.ResourceData) *[]keyvault.AccessPolicyEntry {
	policies := d.Get("access_policy").([]interface{})
	result := make([]keyvault.AccessPolicyEntry, 0, len(policies))

	for _, policySet := range policies {
		policyRaw := policySet.(map[string]interface{})

		certificatePermissionsRaw := policyRaw["certificate_permissions"].([]interface{})
		certificatePermissions := []keyvault.CertificatePermissions{}
		for _, permission := range certificatePermissionsRaw {
			certificatePermissions = append(certificatePermissions, keyvault.CertificatePermissions(permission.(string)))
		}

		keyPermissionsRaw := policyRaw["key_permissions"].([]interface{})
		keyPermissions := []keyvault.KeyPermissions{}
		for _, permission := range keyPermissionsRaw {
			keyPermissions = append(keyPermissions, keyvault.KeyPermissions(permission.(string)))
		}

		secretPermissionsRaw := policyRaw["secret_permissions"].([]interface{})
		secretPermissions := []keyvault.SecretPermissions{}
		for _, permission := range secretPermissionsRaw {
			secretPermissions = append(secretPermissions, keyvault.SecretPermissions(permission.(string)))
		}

		policy := keyvault.AccessPolicyEntry{
			Permissions: &keyvault.Permissions{
				Certificates: &certificatePermissions,
				Keys:         &keyPermissions,
				Secrets:      &secretPermissions,
			},
		}

		tenantUUID := uuid.FromStringOrNil(policyRaw["tenant_id"].(string))
		policy.TenantID = &tenantUUID
		objectUUID := policyRaw["object_id"].(string)
		policy.ObjectID = &objectUUID

		if v := policyRaw["application_id"]; v != "" {
			applicationUUID := uuid.FromStringOrNil(v.(string))
			policy.ApplicationID = &applicationUUID
		}

		result = append(result, policy)
	}

	return &result
}

func flattenKeyVaultSku(sku *keyvault.Sku) []interface{} {
	result := map[string]interface{}{
		"name": string(sku.Name),
	}

	return []interface{}{result}
}

func flattenKeyVaultAccessPolicies(policies *[]keyvault.AccessPolicyEntry) []interface{} {
	result := make([]interface{}, 0, len(*policies))

	for _, policy := range *policies {
		policyRaw := make(map[string]interface{})

		keyPermissionsRaw := make([]interface{}, 0, len(*policy.Permissions.Keys))
		for _, keyPermission := range *policy.Permissions.Keys {
			keyPermissionsRaw = append(keyPermissionsRaw, string(keyPermission))
		}

		secretPermissionsRaw := make([]interface{}, 0, len(*policy.Permissions.Secrets))
		for _, secretPermission := range *policy.Permissions.Secrets {
			secretPermissionsRaw = append(secretPermissionsRaw, string(secretPermission))
		}

		policyRaw["tenant_id"] = policy.TenantID.String()
		policyRaw["object_id"] = *policy.ObjectID
		if policy.ApplicationID != nil {
			policyRaw["application_id"] = policy.ApplicationID.String()
		}
		policyRaw["key_permissions"] = keyPermissionsRaw
		policyRaw["secret_permissions"] = secretPermissionsRaw

		if policy.Permissions.Certificates != nil {
			certificatePermissionsRaw := make([]interface{}, 0, len(*policy.Permissions.Certificates))
			for _, certificatePermission := range *policy.Permissions.Certificates {
				certificatePermissionsRaw = append(certificatePermissionsRaw, string(certificatePermission))
			}
			policyRaw["certificate_permissions"] = certificatePermissionsRaw
		}

		result = append(result, policyRaw)
	}

	return result
}

func validateKeyVaultName(v interface{}, k string) (ws []string, errors []error) {
	value := v.(string)
	if matched := regexp.MustCompile(`^[a-zA-Z0-9-]{3,24}$`).Match([]byte(value)); !matched {
		errors = append(errors, fmt.Errorf("%q may only contain alphanumeric characters and dashes and must be between 3-24 chars", k))
	}

	return
}

func checkKeyVaultDNSIsAvailable(vaultUri string) func() *resource.RetryError {
	return func() *resource.RetryError {
		uri, err := url.Parse(vaultUri)
		if err != nil {
			return resource.NonRetryableError(err)
		}

		conn, err := net.Dial("tcp", fmt.Sprintf("%s:443", uri.Host))
		if err != nil {
			return resource.RetryableError(err)
		}

		_ = conn.Close()
		return nil
	}
}
<|endoftext|>