<commit_before>package docker

import (
	"context"
	"github.com/ViBiOh/docker-deploy/jsonHttp"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/network"
	"github.com/docker/docker/api/types/strslice"
	"gopkg.in/yaml.v2"
	"log"
	"net/http"
	"regexp"
	"strings"
)

const minMemory = 67108864
const maxMemory = 536870912
const defaultTag = `:latest`

var networkConfig = network.NetworkingConfig{
	EndpointsConfig: map[string]*network.EndpointSettings{
		`traefik`: &network.EndpointSettings{},
	},
}

var imageTag = regexp.MustCompile(`^\S*?:\S+$`)

type dockerComposeService struct {
	Image       string
	Command     string
	Environment map[string]string
	Labels      map[string]string
	ReadOnly    bool  `yaml:"read_only"`
	CPUShares   int64 `yaml:"cpu_shares"`
	MemoryLimit int64 `yaml:"mem_limit"`
}

type dockerCompose struct {
	Version  string
	Services map[string]dockerComposeService
}

func getConfig(service *dockerComposeService, loggedUser *user, appName string) *container.Config {
	environments := make([]string, len(service.Environment))
	for key, value := range service.Environment {
		environments = append(environments, key+`=`+value)
	}

	if service.Labels == nil {
		service.Labels = make(map[string]string)
	}

	service.Labels[ownerLabel] = loggedUser.username
	service.Labels[appLabel] = appName

	config := container.Config{
		Image:  service.Image,
		Labels: service.Labels,
		Env:    environments,
	}

	if service.Command != `` {
		config.Cmd = strslice.StrSlice([]string{service.Command})
	}

	return &config
}

func getHostConfig(service *dockerComposeService) *container.HostConfig {
	hostConfig := container.HostConfig{
		LogConfig: container.LogConfig{Type: `json-file`, Config: map[string]string{
			`max-size`: `50m`,
		}},
		RestartPolicy: container.RestartPolicy{Name: `on-failure`, MaximumRetryCount: 5},
		Resources: container.Resources{
			CPUShares: 128,
			Memory:    minMemory,
		},
		SecurityOpt: []string{`no-new-privileges`},
	}

	if service.ReadOnly {
		hostConfig.ReadonlyRootfs = service.ReadOnly
	}

	if service.CPUShares != 0 {
		hostConfig.Resources.CPUShares = service.CPUShares
	}

	if service.MemoryLimit != 0 {
		if service.MemoryLimit < maxMemory {
			hostConfig.Resources.Memory = service.MemoryLimit
		} else {
			hostConfig.Resources.Memory = maxMemory
		}
	}

	return &hostConfig
}

func createAppHandler(w http.ResponseWriter, loggedUser *user, appName []byte, composeFile []byte) {
	if len(appName) == 0 || len(composeFile) == 0 {
		http.Error(w, `An application name and a compose file are required`, http.StatusBadRequest)
		return
	}

	compose := dockerCompose{}
	if err := yaml.Unmarshal(composeFile, &compose); err != nil {
		errorHandler(w, err)
		return
	}

	appNameStr := string(appName)
	log.Print(loggedUser.username + ` deploys ` + appNameStr)

	ownerContainers, err := listContainers(loggedUser, &appNameStr)
	if err != nil {
		errorHandler(w, err)
		return
	}
	for _, container := range ownerContainers {
		log.Print(loggedUser.username + ` stops ` + strings.Join(container.Names, `, `))
		stopContainer(container.ID)
		log.Print(loggedUser.username + ` rm ` + strings.Join(container.Names, `, `))
		rmContainer(container.ID)
	}

	ids := make([]string, len(compose.Services))
	for serviceName, service := range compose.Services {
		image := service.Image
		if !imageTag.MatchString(image) {
			image = image + defaultTag
		}

		log.Print(loggedUser.username + ` starts pulling for ` + image)
		pull, err := docker.ImagePull(context.Background(), image, types.ImagePullOptions{})
		if err != nil {
			errorHandler(w, err)
			return
		}

		readBody(pull)
		log.Print(loggedUser.username + ` ends pulling for ` + image)

		serviceFullName := appNameStr + `_` + serviceName
		log.Print(loggedUser.username + ` starts ` + serviceFullName)
		id, err := docker.ContainerCreate(context.Background(), getConfig(&service, loggedUser, appNameStr), getHostConfig(&service), &networkConfig, serviceFullName)
		if err != nil {
			errorHandler(w, err)
			return
		}

		startContainer(id.ID)
		ids = append(ids, id.ID)
	}

	jsonHttp.ResponseJSON(w, results{ids})
}
<commit_msg>Adding deploy logic<commit_after>package docker

import (
	"context"
	"github.com/ViBiOh/docker-deploy/jsonHttp"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/network"
	"github.com/docker/docker/api/types/strslice"
	"gopkg.in/yaml.v2"
	"log"
	"net/http"
	"regexp"
	"strings"
)

const minMemory = 67108864
const maxMemory = 536870912
const defaultTag = `:latest`
const deploySuffix = `_deploy`

var networkConfig = network.NetworkingConfig{
	EndpointsConfig: map[string]*network.EndpointSettings{
		`traefik`: &network.EndpointSettings{},
	},
}

var imageTag = regexp.MustCompile(`^\S*?:\S+$`)

type dockerComposeService struct {
	Image       string
	Command     string
	Environment map[string]string
	Labels      map[string]string
	ReadOnly    bool  `yaml:"read_only"`
	CPUShares   int64 `yaml:"cpu_shares"`
	MemoryLimit int64 `yaml:"mem_limit"`
}

type dockerCompose struct {
	Version  string
	Services map[string]dockerComposeService
}

func getConfig(service *dockerComposeService, loggedUser *user, appName string) *container.Config {
	environments := make([]string, len(service.Environment))
	for key, value := range service.Environment {
		environments = append(environments, key+`=`+value)
	}

	if service.Labels == nil {
		service.Labels = make(map[string]string)
	}

	service.Labels[ownerLabel] = loggedUser.username
	service.Labels[appLabel] = appName

	config := container.Config{
		Image:  service.Image,
		Labels: service.Labels,
		Env:    environments,
	}

	if service.Command != `` {
		config.Cmd = strslice.StrSlice([]string{service.Command})
	}

	return &config
}

func getHostConfig(service *dockerComposeService) *container.HostConfig {
	hostConfig := container.HostConfig{
		LogConfig: container.LogConfig{Type: `json-file`, Config: map[string]string{
			`max-size`: `50m`,
		}},
		RestartPolicy: container.RestartPolicy{Name: `on-failure`, MaximumRetryCount: 5},
		Resources: container.Resources{
			CPUShares: 128,
			Memory:    minMemory,
		},
		SecurityOpt: []string{`no-new-privileges`},
	}

	if service.ReadOnly {
		hostConfig.ReadonlyRootfs = service.ReadOnly
	}

	if service.CPUShares != 0 {
		hostConfig.Resources.CPUShares = service.CPUShares
	}

	if service.MemoryLimit != 0 {
		if service.MemoryLimit < maxMemory {
			hostConfig.Resources.Memory = service.MemoryLimit
		} else {
			hostConfig.Resources.Memory = maxMemory
		}
	}

	return &hostConfig
}

func createAppHandler(w http.ResponseWriter, loggedUser *user, appName []byte, composeFile []byte) {
	if len(appName) == 0 || len(composeFile) == 0 {
		http.Error(w, `An application name and a compose file are required`, http.StatusBadRequest)
		return
	}

	compose := dockerCompose{}
	if err := yaml.Unmarshal(composeFile, &compose); err != nil {
		errorHandler(w, err)
		return
	}

	appNameStr := string(appName)
	log.Print(loggedUser.username + ` deploys ` + appNameStr)

	ownerContainers, err := listContainers(loggedUser, &appNameStr)
	if err != nil {
		errorHandler(w, err)
		return
	}

	ids := make(map[string]string)
	for serviceName, service := range compose.Services {
		image := service.Image
		if !imageTag.MatchString(image) {
			image = image + defaultTag
		}

		log.Print(loggedUser.username + ` starts pulling for ` + image)
		pull, err := docker.ImagePull(context.Background(), image, types.ImagePullOptions{})
		if err != nil {
			errorHandler(w, err)
			return
		}

		readBody(pull)
		log.Print(loggedUser.username + ` ends pulling for ` + image)

		serviceFullName := appNameStr + `_` + serviceName + deploySuffix
		log.Print(loggedUser.username + ` starts ` + serviceFullName)
		id, err := docker.ContainerCreate(context.Background(), getConfig(&service, loggedUser, appNameStr), getHostConfig(&service), &networkConfig, serviceFullName)
		if err != nil {
			errorHandler(w, err)
			return
		}

		startContainer(id.ID)
		ids[id.ID] = serviceFullName
	}

	for _, container := range ownerContainers {
		log.Print(loggedUser.username + ` stops ` + strings.Join(container.Names, `, `))
		stopContainer(container.ID)
		log.Print(loggedUser.username + ` rm ` + strings.Join(container.Names, `, `))
		rmContainer(container.ID)
	}

	for id, name := range ids {
		if err := docker.ContainerRename(context.Background(), id, strings.TrimSuffix(name, deploySuffix)); err != nil {
			errorHandler(w, err)
			return
		}
	}

	jsonHttp.ResponseJSON(w, results{ids})
}
<|endoftext|>


<commit_before>package awsrules

import (
	"fmt"
	"log"

	hcl "github.com/hashicorp/hcl/v2"
	"github.com/terraform-linters/tflint/tflint"
)

// AwsS3BucketInvalidACLRule checks the pattern is valid
type AwsS3BucketInvalidACLRule struct {
	resourceType  string
	attributeName string
	enum          []string
}

// NewAwsS3BucketInvalidACLRule returns new rule with default attributes
func NewAwsS3BucketInvalidACLRule() *AwsS3BucketInvalidACLRule {
	return &AwsS3BucketInvalidACLRule{
		resourceType:  "aws_s3_bucket",
		attributeName: "acl",
		enum: []string{
			"private",
			"public-read",
			"public-read-write",
			"aws-exec-read",
			"authenticated-read",
			"log-delivery-write",
			"bucket-owner-full-control",
		},
	}
}

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

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

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

// Link returns the rule reference link
func (r *AwsS3BucketInvalidACLRule) Link() string {
	return ""
}

// Check checks the pattern is valid
func (r *AwsS3BucketInvalidACLRule) Check(runner *tflint.Runner) error {
	log.Printf("[TRACE] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath())

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

		return runner.EnsureNoError(err, func() error {
			found := false
			for _, item := range r.enum {
				if item == val {
					found = true
				}
			}
			if !found {
				runner.EmitIssue(
					r,
					fmt.Sprintf(`"%s" is an invalid value as acl`, val),
					attribute.Expr.Range(),
				)
			}
			return nil
		})
	})
}
<commit_msg>Add bucket-owner-read to allowed S3 ACLs<commit_after>package awsrules

import (
	"fmt"
	"log"

	hcl "github.com/hashicorp/hcl/v2"
	"github.com/terraform-linters/tflint/tflint"
)

// AwsS3BucketInvalidACLRule checks the pattern is valid
type AwsS3BucketInvalidACLRule struct {
	resourceType  string
	attributeName string
	enum          []string
}

// NewAwsS3BucketInvalidACLRule returns new rule with default attributes
func NewAwsS3BucketInvalidACLRule() *AwsS3BucketInvalidACLRule {
	return &AwsS3BucketInvalidACLRule{
		resourceType:  "aws_s3_bucket",
		attributeName: "acl",
		enum: []string{
			"private",
			"public-read",
			"public-read-write",
			"aws-exec-read",
			"authenticated-read",
			"log-delivery-write",
			"bucket-owner-read",
			"bucket-owner-full-control",
		},
	}
}

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

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

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

// Link returns the rule reference link
func (r *AwsS3BucketInvalidACLRule) Link() string {
	return ""
}

// Check checks the pattern is valid
func (r *AwsS3BucketInvalidACLRule) Check(runner *tflint.Runner) error {
	log.Printf("[TRACE] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath())

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

		return runner.EnsureNoError(err, func() error {
			found := false
			for _, item := range r.enum {
				if item == val {
					found = true
				}
			}
			if !found {
				runner.EmitIssue(
					r,
					fmt.Sprintf(`"%s" is an invalid value as acl`, val),
					attribute.Expr.Range(),
				)
			}
			return nil
		})
	})
}
<|endoftext|>


<commit_before>package client

import (
	"fmt"
	"math"
	"strconv"
	"strings"
	"time"

	"github.com/keybase/client/go/flexibletable"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/chat1"
	"github.com/keybase/client/go/protocol/gregor1"
)

type conversationInfoListView []chat1.ConversationInfoLocal

func (v conversationInfoListView) show(g *libkb.GlobalContext) error {
	if len(v) == 0 {
		return nil
	}

	ui := g.UI.GetTerminalUI()
	w, _ := ui.TerminalSize()

	table := &flexibletable.Table{}
	for i, conv := range v {
		participants := strings.Split(conv.TlfName, ",")
		table.Insert(flexibletable.Row{
			flexibletable.Cell{
				Frame:     [2]string{"[", "]"},
				Alignment: flexibletable.Right,
				Content:   flexibletable.SingleCell{Item: strconv.Itoa(i + 1)},
			},
			flexibletable.Cell{
				Alignment: flexibletable.Left,
				Content:   flexibletable.MultiCell{Sep: ",", Items: participants},
			},
		})
	}
	if err := table.Render(ui.OutputWriter(), " ", w, []flexibletable.ColumnConstraint{
		5, flexibletable.ExpandableWrappable,
	}); err != nil {
		return fmt.Errorf("rendering conversation info list view error: %v\n", err)
	}

	return nil
}

type conversationListView []chat1.ConversationLocal

func (v conversationListView) show(g *libkb.GlobalContext, myUsername string, showDeviceName bool) error {
	if len(v) == 0 {
		return nil
	}

	ui := g.UI.GetTerminalUI()
	w, _ := ui.TerminalSize()

	table := &flexibletable.Table{}
	for i, conv := range v {

		if conv.Error != nil {
			table.Insert(flexibletable.Row{
				flexibletable.Cell{
					Frame:     [2]string{"[", "]"},
					Alignment: flexibletable.Right,
					Content:   flexibletable.SingleCell{Item: strconv.Itoa(i + 1)},
				},
				flexibletable.Cell{
					Alignment: flexibletable.Center,
					Content:   flexibletable.SingleCell{Item: ""},
				},
				flexibletable.Cell{
					Alignment: flexibletable.Left,
					Content:   flexibletable.SingleCell{Item: "???"},
				},
				flexibletable.Cell{
					Frame:     [2]string{"[", "]"},
					Alignment: flexibletable.Right,
					Content:   flexibletable.SingleCell{Item: "???"},
				},
				flexibletable.Cell{
					Alignment: flexibletable.Left,
					Content:   flexibletable.SingleCell{Item: *conv.Error},
				},
			})
			continue
		}

		participants := strings.Split(conv.Info.TlfName, ",")

		if len(participants) > 1 {
			var withoutMe []string
			for _, p := range participants {
				if p != myUsername {
					withoutMe = append(withoutMe, p)
				}
			}
			participants = withoutMe
		}

		unread := "*"
		// show the last TEXT message
		var msg *chat1.MessageFromServerOrError
		for _, m := range conv.MaxMessages {
			if m.Message != nil {
				if conv.ReaderInfo.ReadMsgid == m.Message.ServerHeader.MessageID {
					unread = ""
				}
				if m.Message.ServerHeader.MessageType == chat1.MessageType_TEXT {
					msg = &m
				}
			}
		}
		if msg == nil {
			// Skip conversations with no TEXT messages.
			g.Log.Debug("Skipped conversation with no TEXT: %v", conv.Info.Id)
			continue
		}

		mv, err := newMessageView(g, conv.Info.Id, *msg)
		if err != nil {
			g.Log.Error("Message render error: %s", err)
		}

		var authorAndTime string
		if showDeviceName {
			authorAndTime = mv.AuthorAndTimeWithDeviceName
		} else {
			authorAndTime = mv.AuthorAndTime
		}

		// This will show a blank link for convs whose last message cannot be displayed.
		body := ""
		if mv.Renderable {
			body = mv.Body
		}

		table.Insert(flexibletable.Row{
			flexibletable.Cell{
				Frame:     [2]string{"[", "]"},
				Alignment: flexibletable.Right,
				Content:   flexibletable.SingleCell{Item: strconv.Itoa(i + 1)},
			},
			flexibletable.Cell{
				Alignment: flexibletable.Center,
				Content:   flexibletable.SingleCell{Item: unread},
			},
			flexibletable.Cell{
				Alignment: flexibletable.Left,
				Content:   flexibletable.MultiCell{Sep: ",", Items: participants},
			},
			flexibletable.Cell{
				Frame:     [2]string{"[", "]"},
				Alignment: flexibletable.Right,
				Content:   flexibletable.SingleCell{Item: authorAndTime},
			},
			flexibletable.Cell{
				Alignment: flexibletable.Left,
				Content:   flexibletable.SingleCell{Item: body},
			},
		})
	}

	if err := table.Render(ui.OutputWriter(), " ", w, []flexibletable.ColumnConstraint{
		5, 1, flexibletable.ColumnConstraint(w / 4), flexibletable.ColumnConstraint(w / 4), flexibletable.Expandable,
	}); err != nil {
		return fmt.Errorf("rendering conversation list view error: %v\n", err)
	}

	return nil
}

type conversationView struct {
	conversation chat1.ConversationLocal
	messages     []chat1.MessageFromServerOrError
}

func (v conversationView) show(g *libkb.GlobalContext, showDeviceName bool) error {
	if len(v.messages) == 0 {
		return nil
	}

	ui := g.UI.GetTerminalUI()
	w, _ := ui.TerminalSize()

	headline, err := v.headline(g)
	if err != nil {
		return err
	}
	if headline != "" {
		g.UI.GetTerminalUI().Printf("headline: %s\n\n", headline)
	}

	table := &flexibletable.Table{}
	i := -1
	for _, m := range v.messages {
		mv, err := newMessageView(g, v.conversation.Info.Id, m)
		if err != nil {
			g.Log.Error("Message render error: %s", err)
		}

		if !mv.Renderable {
			continue
		}

		unread := ""
		if m.Message != nil &&
			v.conversation.ReaderInfo.ReadMsgid < m.Message.ServerHeader.MessageID {
			unread = "*"
		}

		var authorAndTime string
		if showDeviceName {
			authorAndTime = mv.AuthorAndTimeWithDeviceName
		} else {
			authorAndTime = mv.AuthorAndTime
		}

		i++
		table.Insert(flexibletable.Row{
			flexibletable.Cell{
				Frame:     [2]string{"[", "]"},
				Alignment: flexibletable.Right,
				Content:   flexibletable.SingleCell{Item: strconv.Itoa(i + 1)},
			},
			flexibletable.Cell{
				Alignment: flexibletable.Center,
				Content:   flexibletable.SingleCell{Item: unread},
			},
			flexibletable.Cell{
				Frame:     [2]string{"[", "]"},
				Alignment: flexibletable.Right,
				Content:   flexibletable.SingleCell{Item: authorAndTime},
			},
			flexibletable.Cell{
				Alignment: flexibletable.Left,
				Content:   flexibletable.SingleCell{Item: mv.Body},
			},
		})
	}
	if err := table.Render(ui.OutputWriter(), " ", w, []flexibletable.ColumnConstraint{
		5, 1, flexibletable.ColumnConstraint(w / 4), flexibletable.ExpandableWrappable,
	}); err != nil {
		return fmt.Errorf("rendering conversation view error: %v\n", err)
	}

	return nil
}

// Read the headline off the HEADLINE message in MaxMessages.
// Returns "" when there is no headline set.
func (v conversationView) headline(g *libkb.GlobalContext) (string, error) {
	for _, m := range v.conversation.MaxMessages {
		if m.Message == nil {
			continue
		}
		version, err := m.Message.MessagePlaintext.Version()
		if err != nil {
			continue
		}
		switch version {
		case chat1.MessagePlaintextVersion_V1:
			body := m.Message.MessagePlaintext.V1().MessageBody
			typ, err := body.MessageType()
			if err != nil {
				continue
			}
			switch typ {
			case chat1.MessageType_HEADLINE:
				return body.Headline().Headline, nil
			default:
				continue
			}
		default:
			continue
		}
	}

	return "", nil
}

const deletedTextCLI = "[deleted]"

// Everything you need to show a message.
// Takes into account superseding edits and deletions.
type messageView struct {
	MessageID chat1.MessageID
	// Whether to show this message. Show texts, but not edits or deletes.
	Renderable                  bool
	AuthorAndTime               string
	AuthorAndTimeWithDeviceName string
	Body                        string

	// Used internally for supersedeers
	messageType chat1.MessageType
}

// newMessageView extracts from a message the parts for display
// It may fetch the superseding message. So that for example a TEXT message will show its EDIT text.
func newMessageView(g *libkb.GlobalContext, conversationID chat1.ConversationID, m chat1.MessageFromServerOrError) (messageView, error) {
	mv := messageView{}

	if m.Message == nil {
		if m.UnboxingError != nil {
			return mv, fmt.Errorf(fmt.Sprintf("<%s>", *m.UnboxingError))
		}
		return mv, fmt.Errorf("unexpected data")
	}

	mv.MessageID = m.Message.ServerHeader.MessageID

	// Check what message supersedes this one.
	var mvsup *messageView
	supersededBy := m.Message.ServerHeader.SupersededBy
	if supersededBy != 0 {
		msup, err := fetchOneMessage(g, conversationID, supersededBy)
		if err != nil {
			return mv, err
		}
		mvsupInner, err := newMessageView(g, conversationID, msup)
		if err != nil {
			return mv, err
		}
		mvsup = &mvsupInner
	}

	t := gregor1.FromTime(m.Message.ServerHeader.Ctime)
	mv.AuthorAndTime = fmt.Sprintf("%s %s",
		m.Message.SenderUsername, shortDurationFromNow(t))
	mv.AuthorAndTimeWithDeviceName = fmt.Sprintf("%s <%s> %s",
		m.Message.SenderUsername, m.Message.SenderDeviceName, shortDurationFromNow(t))

	version, err := m.Message.MessagePlaintext.Version()
	if err != nil {
		g.Log.Warning("MessagePlaintext version error: %s", err)
		return mv, err
	}
	switch version {
	case chat1.MessagePlaintextVersion_V1:
		plaintext := m.Message.MessagePlaintext.V1()
		body := plaintext.MessageBody
		typ, err := plaintext.MessageBody.MessageType()
		mv.messageType = typ
		if err != nil {
			return mv, err
		}
		switch typ {
		case chat1.MessageType_NONE:
			// NONE is what you get when a message has been deleted.
			mv.Renderable = true
			if mvsup != nil {
				switch mvsup.messageType {
				case chat1.MessageType_EDIT:
					// Use the edited body
					mv.Body = mvsup.Body
				case chat1.MessageType_DELETE:
					mv.Body = deletedTextCLI
				default:
					// Some unknown supersedeer type
				}
			}
		case chat1.MessageType_TEXT:
			mv.Renderable = true
			mv.Body = body.Text().Body
			if mvsup != nil {
				switch mvsup.messageType {
				case chat1.MessageType_EDIT:
					mv.Body = mvsup.Body
				case chat1.MessageType_DELETE:
					// This is unlikely because deleted messages are usually NONE
					mv.Body = deletedTextCLI
				default:
					// Some unknown supersedeer type
				}
			}
		case chat1.MessageType_ATTACHMENT:
			mv.Renderable = true
			// TODO: will fix this in CORE-3899
			mv.Body = fmt.Sprintf("{Attachment} | Caption: <unimplemented>")
			if mvsup != nil {
				switch mvsup.messageType {
				case chat1.MessageType_EDIT:
					// Editing attachments is not supported, ignore the edit
				case chat1.MessageType_DELETE:
					mv.Body = deletedTextCLI
				default:
					// Some unknown supersedeer type
				}
			}
		case chat1.MessageType_EDIT:
			mv.Renderable = false
			// Return the edit body for display in the original
			mv.Body = fmt.Sprintf("%v [edited]", body.Edit().Body)
		case chat1.MessageType_DELETE:
			mv.Renderable = false
		case chat1.MessageType_METADATA:
			mv.Renderable = false
		case chat1.MessageType_TLFNAME:
			mv.Renderable = false
		default:
			return mv, fmt.Errorf(fmt.Sprintf("unsupported MessageType: %s", typ.String()))
		}
	default:
		return mv, fmt.Errorf(fmt.Sprintf("MessagePlaintext version error: %s", err))
	}
	return mv, nil
}

func shortDurationFromNow(t time.Time) string {
	d := time.Since(t)

	num := d.Hours() / 24
	if num > 1 {
		return strconv.Itoa(int(math.Ceil(num))) + "d"
	}

	num = d.Hours()
	if num > 1 {
		return strconv.Itoa(int(math.Ceil(num))) + "h"
	}

	num = d.Minutes()
	if num > 1 {
		return strconv.Itoa(int(math.Ceil(num))) + "m"
	}

	num = d.Seconds()
	return strconv.Itoa(int(math.Ceil(num))) + "s"
}
<commit_msg>quick fix for kbc list (#4581)<commit_after>package client

import (
	"fmt"
	"math"
	"strconv"
	"strings"
	"time"

	"github.com/keybase/client/go/flexibletable"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/chat1"
	"github.com/keybase/client/go/protocol/gregor1"
)

type conversationInfoListView []chat1.ConversationInfoLocal

func (v conversationInfoListView) show(g *libkb.GlobalContext) error {
	if len(v) == 0 {
		return nil
	}

	ui := g.UI.GetTerminalUI()
	w, _ := ui.TerminalSize()

	table := &flexibletable.Table{}
	for i, conv := range v {
		participants := strings.Split(conv.TlfName, ",")
		table.Insert(flexibletable.Row{
			flexibletable.Cell{
				Frame:     [2]string{"[", "]"},
				Alignment: flexibletable.Right,
				Content:   flexibletable.SingleCell{Item: strconv.Itoa(i + 1)},
			},
			flexibletable.Cell{
				Alignment: flexibletable.Left,
				Content:   flexibletable.MultiCell{Sep: ",", Items: participants},
			},
		})
	}
	if err := table.Render(ui.OutputWriter(), " ", w, []flexibletable.ColumnConstraint{
		5, flexibletable.ExpandableWrappable,
	}); err != nil {
		return fmt.Errorf("rendering conversation info list view error: %v\n", err)
	}

	return nil
}

type conversationListView []chat1.ConversationLocal

func (v conversationListView) show(g *libkb.GlobalContext, myUsername string, showDeviceName bool) error {
	if len(v) == 0 {
		return nil
	}

	ui := g.UI.GetTerminalUI()
	w, _ := ui.TerminalSize()

	table := &flexibletable.Table{}
	for i, conv := range v {

		if conv.Error != nil {
			table.Insert(flexibletable.Row{
				flexibletable.Cell{
					Frame:     [2]string{"[", "]"},
					Alignment: flexibletable.Right,
					Content:   flexibletable.SingleCell{Item: strconv.Itoa(i + 1)},
				},
				flexibletable.Cell{
					Alignment: flexibletable.Center,
					Content:   flexibletable.SingleCell{Item: ""},
				},
				flexibletable.Cell{
					Alignment: flexibletable.Left,
					Content:   flexibletable.SingleCell{Item: "???"},
				},
				flexibletable.Cell{
					Frame:     [2]string{"[", "]"},
					Alignment: flexibletable.Right,
					Content:   flexibletable.SingleCell{Item: "???"},
				},
				flexibletable.Cell{
					Alignment: flexibletable.Left,
					Content:   flexibletable.SingleCell{Item: *conv.Error},
				},
			})
			continue
		}

		participants := strings.Split(conv.Info.TlfName, ",")

		if len(participants) > 1 {
			var withoutMe []string
			for _, p := range participants {
				if p != myUsername {
					withoutMe = append(withoutMe, p)
				}
			}
			participants = withoutMe
		}

		unread := "*"
		// show the last TEXT message
		var msg *chat1.MessageFromServerOrError
		for _, m := range conv.MaxMessages {
			if m.Message != nil {
				if conv.ReaderInfo.ReadMsgid == m.Message.ServerHeader.MessageID {
					unread = ""
				}
				if m.Message.ServerHeader.MessageType == chat1.MessageType_TEXT {
					mCopy := m
					msg = &mCopy
				}
			}
		}
		if msg == nil {
			// Skip conversations with no TEXT messages.
			g.Log.Debug("Skipped conversation with no TEXT: %v", conv.Info.Id)
			continue
		}

		mv, err := newMessageView(g, conv.Info.Id, *msg)
		if err != nil {
			g.Log.Error("Message render error: %s", err)
		}

		var authorAndTime string
		if showDeviceName {
			authorAndTime = mv.AuthorAndTimeWithDeviceName
		} else {
			authorAndTime = mv.AuthorAndTime
		}

		// This will show a blank link for convs whose last message cannot be displayed.
		body := ""
		if mv.Renderable {
			body = mv.Body
		}

		table.Insert(flexibletable.Row{
			flexibletable.Cell{
				Frame:     [2]string{"[", "]"},
				Alignment: flexibletable.Right,
				Content:   flexibletable.SingleCell{Item: strconv.Itoa(i + 1)},
			},
			flexibletable.Cell{
				Alignment: flexibletable.Center,
				Content:   flexibletable.SingleCell{Item: unread},
			},
			flexibletable.Cell{
				Alignment: flexibletable.Left,
				Content:   flexibletable.MultiCell{Sep: ",", Items: participants},
			},
			flexibletable.Cell{
				Frame:     [2]string{"[", "]"},
				Alignment: flexibletable.Right,
				Content:   flexibletable.SingleCell{Item: authorAndTime},
			},
			flexibletable.Cell{
				Alignment: flexibletable.Left,
				Content:   flexibletable.SingleCell{Item: body},
			},
		})
	}

	if err := table.Render(ui.OutputWriter(), " ", w, []flexibletable.ColumnConstraint{
		5, 1, flexibletable.ColumnConstraint(w / 4), flexibletable.ColumnConstraint(w / 4), flexibletable.Expandable,
	}); err != nil {
		return fmt.Errorf("rendering conversation list view error: %v\n", err)
	}

	return nil
}

type conversationView struct {
	conversation chat1.ConversationLocal
	messages     []chat1.MessageFromServerOrError
}

func (v conversationView) show(g *libkb.GlobalContext, showDeviceName bool) error {
	if len(v.messages) == 0 {
		return nil
	}

	ui := g.UI.GetTerminalUI()
	w, _ := ui.TerminalSize()

	headline, err := v.headline(g)
	if err != nil {
		return err
	}
	if headline != "" {
		g.UI.GetTerminalUI().Printf("headline: %s\n\n", headline)
	}

	table := &flexibletable.Table{}
	i := -1
	for _, m := range v.messages {
		mv, err := newMessageView(g, v.conversation.Info.Id, m)
		if err != nil {
			g.Log.Error("Message render error: %s", err)
		}

		if !mv.Renderable {
			continue
		}

		unread := ""
		if m.Message != nil &&
			v.conversation.ReaderInfo.ReadMsgid < m.Message.ServerHeader.MessageID {
			unread = "*"
		}

		var authorAndTime string
		if showDeviceName {
			authorAndTime = mv.AuthorAndTimeWithDeviceName
		} else {
			authorAndTime = mv.AuthorAndTime
		}

		i++
		table.Insert(flexibletable.Row{
			flexibletable.Cell{
				Frame:     [2]string{"[", "]"},
				Alignment: flexibletable.Right,
				Content:   flexibletable.SingleCell{Item: strconv.Itoa(i + 1)},
			},
			flexibletable.Cell{
				Alignment: flexibletable.Center,
				Content:   flexibletable.SingleCell{Item: unread},
			},
			flexibletable.Cell{
				Frame:     [2]string{"[", "]"},
				Alignment: flexibletable.Right,
				Content:   flexibletable.SingleCell{Item: authorAndTime},
			},
			flexibletable.Cell{
				Alignment: flexibletable.Left,
				Content:   flexibletable.SingleCell{Item: mv.Body},
			},
		})
	}
	if err := table.Render(ui.OutputWriter(), " ", w, []flexibletable.ColumnConstraint{
		5, 1, flexibletable.ColumnConstraint(w / 4), flexibletable.ExpandableWrappable,
	}); err != nil {
		return fmt.Errorf("rendering conversation view error: %v\n", err)
	}

	return nil
}

// Read the headline off the HEADLINE message in MaxMessages.
// Returns "" when there is no headline set.
func (v conversationView) headline(g *libkb.GlobalContext) (string, error) {
	for _, m := range v.conversation.MaxMessages {
		if m.Message == nil {
			continue
		}
		version, err := m.Message.MessagePlaintext.Version()
		if err != nil {
			continue
		}
		switch version {
		case chat1.MessagePlaintextVersion_V1:
			body := m.Message.MessagePlaintext.V1().MessageBody
			typ, err := body.MessageType()
			if err != nil {
				continue
			}
			switch typ {
			case chat1.MessageType_HEADLINE:
				return body.Headline().Headline, nil
			default:
				continue
			}
		default:
			continue
		}
	}

	return "", nil
}

const deletedTextCLI = "[deleted]"

// Everything you need to show a message.
// Takes into account superseding edits and deletions.
type messageView struct {
	MessageID chat1.MessageID
	// Whether to show this message. Show texts, but not edits or deletes.
	Renderable                  bool
	AuthorAndTime               string
	AuthorAndTimeWithDeviceName string
	Body                        string

	// Used internally for supersedeers
	messageType chat1.MessageType
}

// newMessageView extracts from a message the parts for display
// It may fetch the superseding message. So that for example a TEXT message will show its EDIT text.
func newMessageView(g *libkb.GlobalContext, conversationID chat1.ConversationID, m chat1.MessageFromServerOrError) (messageView, error) {
	mv := messageView{}

	if m.Message == nil {
		if m.UnboxingError != nil {
			return mv, fmt.Errorf(fmt.Sprintf("<%s>", *m.UnboxingError))
		}
		return mv, fmt.Errorf("unexpected data")
	}

	mv.MessageID = m.Message.ServerHeader.MessageID

	// Check what message supersedes this one.
	var mvsup *messageView
	supersededBy := m.Message.ServerHeader.SupersededBy
	if supersededBy != 0 {
		msup, err := fetchOneMessage(g, conversationID, supersededBy)
		if err != nil {
			return mv, err
		}
		mvsupInner, err := newMessageView(g, conversationID, msup)
		if err != nil {
			return mv, err
		}
		mvsup = &mvsupInner
	}

	t := gregor1.FromTime(m.Message.ServerHeader.Ctime)
	mv.AuthorAndTime = fmt.Sprintf("%s %s",
		m.Message.SenderUsername, shortDurationFromNow(t))
	mv.AuthorAndTimeWithDeviceName = fmt.Sprintf("%s <%s> %s",
		m.Message.SenderUsername, m.Message.SenderDeviceName, shortDurationFromNow(t))

	version, err := m.Message.MessagePlaintext.Version()
	if err != nil {
		g.Log.Warning("MessagePlaintext version error: %s", err)
		return mv, err
	}
	switch version {
	case chat1.MessagePlaintextVersion_V1:
		plaintext := m.Message.MessagePlaintext.V1()
		body := plaintext.MessageBody
		typ, err := plaintext.MessageBody.MessageType()
		mv.messageType = typ
		if err != nil {
			return mv, err
		}
		switch typ {
		case chat1.MessageType_NONE:
			// NONE is what you get when a message has been deleted.
			mv.Renderable = true
			if mvsup != nil {
				switch mvsup.messageType {
				case chat1.MessageType_EDIT:
					// Use the edited body
					mv.Body = mvsup.Body
				case chat1.MessageType_DELETE:
					mv.Body = deletedTextCLI
				default:
					// Some unknown supersedeer type
				}
			}
		case chat1.MessageType_TEXT:
			mv.Renderable = true
			mv.Body = body.Text().Body
			if mvsup != nil {
				switch mvsup.messageType {
				case chat1.MessageType_EDIT:
					mv.Body = mvsup.Body
				case chat1.MessageType_DELETE:
					// This is unlikely because deleted messages are usually NONE
					mv.Body = deletedTextCLI
				default:
					// Some unknown supersedeer type
				}
			}
		case chat1.MessageType_ATTACHMENT:
			mv.Renderable = true
			// TODO: will fix this in CORE-3899
			mv.Body = fmt.Sprintf("{Attachment} | Caption: <unimplemented>")
			if mvsup != nil {
				switch mvsup.messageType {
				case chat1.MessageType_EDIT:
					// Editing attachments is not supported, ignore the edit
				case chat1.MessageType_DELETE:
					mv.Body = deletedTextCLI
				default:
					// Some unknown supersedeer type
				}
			}
		case chat1.MessageType_EDIT:
			mv.Renderable = false
			// Return the edit body for display in the original
			mv.Body = fmt.Sprintf("%v [edited]", body.Edit().Body)
		case chat1.MessageType_DELETE:
			mv.Renderable = false
		case chat1.MessageType_METADATA:
			mv.Renderable = false
		case chat1.MessageType_TLFNAME:
			mv.Renderable = false
		default:
			return mv, fmt.Errorf(fmt.Sprintf("unsupported MessageType: %s", typ.String()))
		}
	default:
		return mv, fmt.Errorf(fmt.Sprintf("MessagePlaintext version error: %s", err))
	}
	return mv, nil
}

func shortDurationFromNow(t time.Time) string {
	d := time.Since(t)

	num := d.Hours() / 24
	if num > 1 {
		return strconv.Itoa(int(math.Ceil(num))) + "d"
	}

	num = d.Hours()
	if num > 1 {
		return strconv.Itoa(int(math.Ceil(num))) + "h"
	}

	num = d.Minutes()
	if num > 1 {
		return strconv.Itoa(int(math.Ceil(num))) + "m"
	}

	num = d.Seconds()
	return strconv.Itoa(int(math.Ceil(num))) + "s"
}
<|endoftext|>


<commit_before>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gcexportdata_test

import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"go/types"
	"log"
	"os"
	"path/filepath"

	"golang.org/x/tools/go/gcexportdata"
)

// ExampleRead uses gcexportdata.Read to load type information for the
// "fmt" package from the fmt.a file produced by the gc compiler.
func ExampleRead() {
	// Find the export data file.
	filename, path := gcexportdata.Find("fmt", "")
	if filename == "" {
		log.Fatalf("can't find export data for fmt")
	}
	fmt.Printf("Package path:       %s\n", path)
	fmt.Printf("Export data:        %s\n", filepath.Base(filename))

	// Open and read the file.
	f, err := os.Open(filename)
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()
	r, err := gcexportdata.NewReader(f)
	if err != nil {
		log.Fatalf("reading export data %s: %v", filename, err)
	}

	// Decode the export data.
	fset := token.NewFileSet()
	imports := make(map[string]*types.Package)
	pkg, err := gcexportdata.Read(r, fset, imports, path)
	if err != nil {
		log.Fatal(err)
	}

	// Print package information.
	fmt.Printf("Package members:    %s...\n", pkg.Scope().Names()[:5])
	println := pkg.Scope().Lookup("Println")
	posn := fset.Position(println.Pos())
	posn.Line = 123 // make example deterministic
	fmt.Printf("Println type:       %s\n", println.Type())
	fmt.Printf("Println location:   %s\n", slashify(posn))

	// Output:
	//
	// Package path:       fmt
	// Export data:        fmt.a
	// Package members:    [Errorf Formatter Fprint Fprintf Fprintln]...
	// Println type:       func(a ...interface{}) (n int, err error)
	// Println location:   $GOROOT/src/fmt/print.go:123:1
}

// ExampleNewImporter demonstrates usage of NewImporter to provide type
// information for dependencies when type-checking Go source code.
func ExampleNewImporter() {
	const src = `package twopi

import "math"

const TwoPi = 2 * math.Pi
`
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, "twopi.go", src, 0)
	if err != nil {
		log.Fatal(err)
	}

	packages := make(map[string]*types.Package)
	imp := gcexportdata.NewImporter(fset, packages)
	conf := types.Config{Importer: imp}
	pkg, err := conf.Check("twopi", fset, []*ast.File{f}, nil)
	if err != nil {
		log.Fatal(err)
	}

	// object from imported package
	pi := packages["math"].Scope().Lookup("Pi")
	fmt.Printf("const %s.%s %s = %s // %s\n",
		pi.Pkg().Path(),
		pi.Name(),
		pi.Type(),
		pi.(*types.Const).Val(),
		slashify(fset.Position(pi.Pos())))

	// object in source package
	twopi := pkg.Scope().Lookup("TwoPi")
	fmt.Printf("const %s %s = %s // %s\n",
		twopi.Name(),
		twopi.Type(),
		twopi.(*types.Const).Val(),
		slashify(fset.Position(twopi.Pos())))

	// Output:
	//
	// const math.Pi untyped float = 3.14159 // $GOROOT/src/math/const.go:11:1
	// const TwoPi untyped float = 6.28319 // twopi.go:5:7
}

func slashify(posn token.Position) token.Position {
	posn.Filename = filepath.ToSlash(posn.Filename) // for MS Windows portability
	return posn
}
<commit_msg>go/gcexportdata: suppress example_test.go on Go 1.6<commit_after>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build go1.7

package gcexportdata_test

import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"go/types"
	"log"
	"os"
	"path/filepath"

	"golang.org/x/tools/go/gcexportdata"
)

// ExampleRead uses gcexportdata.Read to load type information for the
// "fmt" package from the fmt.a file produced by the gc compiler.
func ExampleRead() {
	// Find the export data file.
	filename, path := gcexportdata.Find("fmt", "")
	if filename == "" {
		log.Fatalf("can't find export data for fmt")
	}
	fmt.Printf("Package path:       %s\n", path)
	fmt.Printf("Export data:        %s\n", filepath.Base(filename))

	// Open and read the file.
	f, err := os.Open(filename)
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()
	r, err := gcexportdata.NewReader(f)
	if err != nil {
		log.Fatalf("reading export data %s: %v", filename, err)
	}

	// Decode the export data.
	fset := token.NewFileSet()
	imports := make(map[string]*types.Package)
	pkg, err := gcexportdata.Read(r, fset, imports, path)
	if err != nil {
		log.Fatal(err)
	}

	// Print package information.
	fmt.Printf("Package members:    %s...\n", pkg.Scope().Names()[:5])
	println := pkg.Scope().Lookup("Println")
	posn := fset.Position(println.Pos())
	posn.Line = 123 // make example deterministic
	fmt.Printf("Println type:       %s\n", println.Type())
	fmt.Printf("Println location:   %s\n", slashify(posn))

	// Output:
	//
	// Package path:       fmt
	// Export data:        fmt.a
	// Package members:    [Errorf Formatter Fprint Fprintf Fprintln]...
	// Println type:       func(a ...interface{}) (n int, err error)
	// Println location:   $GOROOT/src/fmt/print.go:123:1
}

// ExampleNewImporter demonstrates usage of NewImporter to provide type
// information for dependencies when type-checking Go source code.
func ExampleNewImporter() {
	const src = `package twopi

import "math"

const TwoPi = 2 * math.Pi
`
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, "twopi.go", src, 0)
	if err != nil {
		log.Fatal(err)
	}

	packages := make(map[string]*types.Package)
	imp := gcexportdata.NewImporter(fset, packages)
	conf := types.Config{Importer: imp}
	pkg, err := conf.Check("twopi", fset, []*ast.File{f}, nil)
	if err != nil {
		log.Fatal(err)
	}

	// object from imported package
	pi := packages["math"].Scope().Lookup("Pi")
	fmt.Printf("const %s.%s %s = %s // %s\n",
		pi.Pkg().Path(),
		pi.Name(),
		pi.Type(),
		pi.(*types.Const).Val(),
		slashify(fset.Position(pi.Pos())))

	// object in source package
	twopi := pkg.Scope().Lookup("TwoPi")
	fmt.Printf("const %s %s = %s // %s\n",
		twopi.Name(),
		twopi.Type(),
		twopi.(*types.Const).Val(),
		slashify(fset.Position(twopi.Pos())))

	// Output:
	//
	// const math.Pi untyped float = 3.14159 // $GOROOT/src/math/const.go:11:1
	// const TwoPi untyped float = 6.28319 // twopi.go:5:7
}

func slashify(posn token.Position) token.Position {
	posn.Filename = filepath.ToSlash(posn.Filename) // for MS Windows portability
	return posn
}
<|endoftext|>


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

// +build darwin

package libkb

import (
	"encoding/base64"
	keychain "github.com/keybase/go-keychain"
)

type KeychainSecretStore struct {
	context     SecretStoreContext
	accountName string
}

var _ SecretStore = KeychainSecretStore{}

func (k KeychainSecretStore) serviceName() string {
	return k.context.GetStoredSecretServiceName()
}

func (k KeychainSecretStore) StoreSecret(secret []byte) (err error) {
	encodedSecret := base64.StdEncoding.EncodeToString(secret)
	item := keychain.NewGenericPassword(k.serviceName(), k.accountName, "", []byte(encodedSecret), k.accessGroup())
	item.SetSynchronizable(k.synchronizable())
	item.SetAccessible(k.accessible())
	keychain.DeleteItem(item)
	return keychain.AddItem(item)
}

func (k KeychainSecretStore) RetrieveSecret() ([]byte, error) {
	encodedSecret, err := keychain.GetGenericPassword(k.serviceName(), k.accountName, "", "")
	if err != nil {
		return nil, err
	}

	if len(encodedSecret) == 0 {
		return nil, SecretStoreError{Msg: "no key found for " + k.accountName}
	}

	secret, err := base64.StdEncoding.DecodeString(string(encodedSecret))

	if err != nil {
		return nil, err
	}

	return secret, nil
}

func (k KeychainSecretStore) ClearSecret() (err error) {
	query := keychain.NewGenericPassword(k.serviceName(), k.accountName, "", nil, "")
	query.SetMatchLimit(keychain.MatchLimitAll)
	return keychain.DeleteItem(query)
}

func NewSecretStore(context SecretStoreContext, username NormalizedUsername) SecretStore {
	return KeychainSecretStore{
		context:     context,
		accountName: username.String(),
	}
}

func HasSecretStore() bool {
	return true
}

func GetUsersWithStoredSecrets(c SecretStoreContext) ([]string, error) {
	return keychain.GetAccountsForService(c.GetStoredSecretServiceName())
}

func GetTerminalPrompt() string {
	return "Store your key in Apple's local keychain?"
}
<commit_msg>Fix secret store test<commit_after>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

// +build darwin

package libkb

import (
	"encoding/base64"

	keychain "github.com/keybase/go-keychain"
)

type KeychainSecretStore struct {
	context     SecretStoreContext
	accountName string
}

var _ SecretStore = KeychainSecretStore{}

func (k KeychainSecretStore) serviceName() string {
	return k.context.GetStoredSecretServiceName()
}

func (k KeychainSecretStore) StoreSecret(secret []byte) (err error) {
	encodedSecret := base64.StdEncoding.EncodeToString(secret)
	item := keychain.NewGenericPassword(k.serviceName(), k.accountName, "", []byte(encodedSecret), k.accessGroup())
	item.SetSynchronizable(k.synchronizable())
	item.SetAccessible(k.accessible())
	keychain.DeleteItem(item)
	return keychain.AddItem(item)
}

func (k KeychainSecretStore) RetrieveSecret() ([]byte, error) {
	encodedSecret, err := keychain.GetGenericPassword(k.serviceName(), k.accountName, "", "")
	if err != nil {
		return nil, err
	}

	if len(encodedSecret) == 0 {
		return nil, SecretStoreError{Msg: "no key found for " + k.accountName}
	}

	secret, err := base64.StdEncoding.DecodeString(string(encodedSecret))

	if err != nil {
		return nil, err
	}

	return secret, nil
}

func (k KeychainSecretStore) ClearSecret() error {
	query := keychain.NewGenericPassword(k.serviceName(), k.accountName, "", nil, "")
	query.SetMatchLimit(keychain.MatchLimitAll)
	err := keychain.DeleteItem(query)
	if err == keychain.ErrorItemNotFound {
		return nil
	}
	return err
}

func NewSecretStore(context SecretStoreContext, username NormalizedUsername) SecretStore {
	return KeychainSecretStore{
		context:     context,
		accountName: username.String(),
	}
}

func HasSecretStore() bool {
	return true
}

func GetUsersWithStoredSecrets(c SecretStoreContext) ([]string, error) {
	return keychain.GetAccountsForService(c.GetStoredSecretServiceName())
}

func GetTerminalPrompt() string {
	return "Store your key in Apple's local keychain?"
}
<|endoftext|>


<commit_before>package main

import (
	"koding/db/mongodb/modelhelper"
	"koding/tools/config"
	"socialapi/workers/helper"
	"time"

	kiteConfig "github.com/koding/kite/config"

	"github.com/crowdmob/goamz/aws"
	"github.com/koding/kite"
	"github.com/koding/redis"
)

var (
	conf = config.MustConfig("")
	port = conf.Vmwatcher.Port

	AWS_KEY    = conf.Vmwatcher.AwsKey
	AWS_SECRET = conf.Vmwatcher.AwsSecret

	// This secret key is here because this worker will be bypassed from the
	// token authentication in kloud.
	KloudSecretKey = conf.Vmwatcher.KloudSecretKey
	KloudAddr      = conf.Vmwatcher.KloudAddr

	KiteClient *kite.Client

	redisClient  *redis.RedisSession
	redisStorage *RedisStorage

	Log = helper.CreateLogger(WorkerName, false)
)

func init() {
	Log.Info("Starting %s", WorkerName)

	// initialize mongo
	modelhelper.Initialize(conf.Mongo)

	// initialize redis
	var err error
	redisClient, err = redis.NewRedisSession(&redis.RedisConf{Server: conf.Redis})
	if err != nil {
		Log.Fatal(err.Error())
	}

	redisStorage = &RedisStorage{Client: redisClient}

	storage = redisStorage

	// store exempt usernames
	for _, metric := range metricsToSave {
		err = storage.ExemptSave(metric.GetName(), ExemptUsers)
		if err != nil {
			Log.Fatal(err.Error())
		}
	}

	Log.Info("Saved: %v users as exempt", len(ExemptUsers))

	// initialize cloudwatch api client
	// arguments are: key, secret, token, expiration
	auth, err = aws.GetAuth(AWS_KEY, AWS_SECRET, "", startingWeek)
	if err != nil {
		Log.Fatal(err.Error())
	}

	// create new kite
	k := kite.New(WorkerName, WorkerVersion)
	config, err := kiteConfig.Get()
	if err != nil {
		Log.Fatal(err.Error())
	}

	// set skeleton config
	k.Config = config

	// create a new connection to the cloud
	KiteClient := k.NewClient(KloudAddr)
	KiteClient.Auth = &kite.Auth{
		Type: "kloudctl",
		Key:  KloudSecretKey,
	}

	// dial the kloud address
	if err := KiteClient.DialTimeout(time.Second * 10); err != nil {
		Log.Fatal("%s. Is kloud/kontrol running?", err.Error())
	}
}
<commit_msg>vmwatcher: extract initializing klient, saving exempt users to own<commit_after>package main

import (
	"koding/db/mongodb/modelhelper"
	"koding/tools/config"
	"socialapi/workers/helper"
	"time"

	kiteConfig "github.com/koding/kite/config"

	"github.com/crowdmob/goamz/aws"
	"github.com/koding/kite"
	"github.com/koding/redis"
)

var (
	conf = config.MustConfig("")
	port = conf.Vmwatcher.Port

	AWS_KEY    = conf.Vmwatcher.AwsKey
	AWS_SECRET = conf.Vmwatcher.AwsSecret

	// This secret key is here because this worker will be bypassed from the
	// token authentication in kloud.
	KloudSecretKey = conf.Vmwatcher.KloudSecretKey
	KloudAddr      = conf.Vmwatcher.KloudAddr

	KiteClient *kite.Client

	redisClient  *redis.RedisSession
	redisStorage *RedisStorage

	Log = helper.CreateLogger(WorkerName, false)
)

func init() {
	Log.Info("Starting %s", WorkerName)

	// initialize mongo
	modelhelper.Initialize(conf.Mongo)

	// initialize redis
	var err error
	redisClient, err = redis.NewRedisSession(&redis.RedisConf{Server: conf.Redis})
	if err != nil {
		Log.Fatal(err.Error())
	}

	redisStorage = &RedisStorage{Client: redisClient}
	storage = redisStorage

	saveExemptUsers()
	initializeKlient()
}

func saveExemptUsers() {
	for _, metric := range metricsToSave {
		err := storage.ExemptSave(metric.GetName(), ExemptUsers)
		if err != nil {
			Log.Fatal(err.Error())
		}
	}

	Log.Info("Saved: %v users as exempt", len(ExemptUsers))
}

func initializeKlient() {
	var err error

	// initialize cloudwatch api client
	// arguments are: key, secret, token, expiration
	auth, err = aws.GetAuth(AWS_KEY, AWS_SECRET, "", startingWeek)
	if err != nil {
		Log.Fatal(err.Error())
	}

	// create new kite
	k := kite.New(WorkerName, WorkerVersion)
	config, err := kiteConfig.Get()
	if err != nil {
		Log.Fatal(err.Error())
	}

	// set skeleton config
	k.Config = config

	// create a new connection to the cloud
	KiteClient := k.NewClient(KloudAddr)
	KiteClient.Auth = &kite.Auth{
		Type: "kloudctl",
		Key:  KloudSecretKey,
	}

	// dial the kloud address
	if err := KiteClient.DialTimeout(time.Second * 10); err != nil {
		Log.Fatal("%s. Is kloud/kontrol running?", err.Error())
	}
}
<|endoftext|>


<commit_before>package core

import "fmt"

type ListType struct {
	first *Thunk
	rest  *Thunk
}

var (
	emptyList = ListType{nil, nil}
	EmptyList = Normal(emptyList)
)

func NewList(ts ...*Thunk) *Thunk {
	l := Normal(emptyList)

	for i := len(ts) - 1; i >= 0; i-- {
		l = Normal(cons(ts[i], l))
	}

	return l
}

func (l ListType) equal(e equalable) Object {
	ll := e.(ListType)

	if l == emptyList || ll == emptyList {
		return rawBool(l == ll)
	}

	for _, t := range []*Thunk{
		// Don't evaluate these parallely for short circuit behavior.
		PApp(Equal, l.first, ll.first),
		PApp(Equal, l.rest, ll.rest),
	} {
		o := t.Eval()
		b, ok := o.(BoolType)

		if !ok {
			return notBoolError(o)
		} else if !b {
			return False
		}
	}

	return True
}

var Prepend = NewLazyFunction(
	NewSignature(
		[]string{}, []OptionalArgument{}, "elemsAndList",
		[]string{}, []OptionalArgument{}, "",
	),
	func(ts ...*Thunk) Object {
		o := ts[0].Eval()
		l, ok := o.(ListType)

		if !ok {
			panic(fmt.Sprintf("Rest arguments must be a list. %v", o))
		}

		ts, err := l.ToThunks()

		if err != nil {
			return err
		} else if len(ts) == 0 {
			return NumArgsError("prepend", "> 0")
		}

		last := len(ts) - 1
		t := ts[last]

		for i := last - 1; i >= 0; i-- {
			t = Normal(cons(ts[i], t))
		}

		return t
	})

func cons(t1, t2 *Thunk) ListType {
	return ListType{t1, t2}
}

var First = NewStrictFunction(
	NewSignature(
		[]string{"list"}, []OptionalArgument{}, "",
		[]string{}, []OptionalArgument{}, "",
	),
	func(os ...Object) Object {
		if len(os) != 1 {
			return NumArgsError("first", "1")
		}

		o := os[0]
		l, ok := o.(ListType)

		if !ok {
			return notListError(o)
		} else if l == emptyList {
			return emptyListError()
		}

		return l.first
	})

var Rest = NewStrictFunction(
	NewSignature(
		[]string{"list"}, []OptionalArgument{}, "",
		[]string{}, []OptionalArgument{}, "",
	),
	func(os ...Object) Object {
		if len(os) != 1 {
			return NumArgsError("rest", "1")
		}

		o := os[0]
		l, ok := o.(ListType)

		if !ok {
			return notListError(o)
		} else if l == emptyList {
			return emptyListError()
		}

		return l.rest
	})

var appendFuncSignature = NewSignature(
	[]string{"list", "elem"}, []OptionalArgument{}, "",
	[]string{}, []OptionalArgument{}, "",
)

var Append = NewLazyFunction(appendFuncSignature, appendFunc)

func appendFunc(ts ...*Thunk) Object {
	o := ts[0].Eval()
	l, ok := o.(ListType)

	if !ok {
		return notListError(o)
	}

	if l == emptyList {
		return NewList(ts[1])
	}

	return cons(
		l.first,
		PApp(NewLazyFunction(appendFuncSignature, appendFunc), l.rest, ts[1]),
	)
}

func notListError(o Object) *Thunk {
	return TypeError(o, "List")
}

func emptyListError() *Thunk {
	return ValueError("The list is empty. You cannot apply rest.")
}

func (l ListType) merge(ts ...*Thunk) Object {
	if l == emptyList {
		return PApp(Merge, ts...)
	}

	return cons(l.first, PApp(Merge, append([]*Thunk{l.rest}, ts...)...))
}

// ordered

func (l ListType) less(ord ordered) bool {
	ll := ord.(ListType)

	if ll == emptyList {
		return false
	} else if l == emptyList {
		return true
	}

	// Compare firsts

	o1 := l.first.Eval()
	o2 := ll.first.Eval()

	if less(o1, o2) {
		return true
	} else if less(o2, o1) {
		return false
	}

	// Compare rests

	return less(l.rest.Eval(), ll.rest.Eval())
}

func (l ListType) ToThunks() ([]*Thunk, *Thunk) {
	ts := make([]*Thunk, 0)

	for l != emptyList {
		ts = append(ts, l.first)

		o := l.rest.Eval()
		var ok bool
		l, ok = o.(ListType)

		if !ok {
			return nil, notListError(o)
		}
	}

	return ts, nil
}

func (l ListType) ToObjects() ([]Object, *Thunk) {
	ts, err := l.ToThunks()

	if err != nil {
		return nil, err
	}

	os := make([]Object, len(ts))

	for _, t := range ts {
		go t.Eval()
	}

	for i, t := range ts {
		os[i] = t.Eval()
	}

	return os, nil
}
<commit_msg>Fix typo<commit_after>package core

import "fmt"

type ListType struct {
	first *Thunk
	rest  *Thunk
}

var (
	emptyList = ListType{nil, nil}
	EmptyList = Normal(emptyList)
)

func NewList(ts ...*Thunk) *Thunk {
	l := Normal(emptyList)

	for i := len(ts) - 1; i >= 0; i-- {
		l = Normal(cons(ts[i], l))
	}

	return l
}

func (l ListType) equal(e equalable) Object {
	ll := e.(ListType)

	if l == emptyList || ll == emptyList {
		return rawBool(l == ll)
	}

	for _, t := range []*Thunk{
		// Don't evaluate these parallelly for short circuit behavior.
		PApp(Equal, l.first, ll.first),
		PApp(Equal, l.rest, ll.rest),
	} {
		o := t.Eval()
		b, ok := o.(BoolType)

		if !ok {
			return notBoolError(o)
		} else if !b {
			return False
		}
	}

	return True
}

var Prepend = NewLazyFunction(
	NewSignature(
		[]string{}, []OptionalArgument{}, "elemsAndList",
		[]string{}, []OptionalArgument{}, "",
	),
	func(ts ...*Thunk) Object {
		o := ts[0].Eval()
		l, ok := o.(ListType)

		if !ok {
			panic(fmt.Sprintf("Rest arguments must be a list. %v", o))
		}

		ts, err := l.ToThunks()

		if err != nil {
			return err
		} else if len(ts) == 0 {
			return NumArgsError("prepend", "> 0")
		}

		last := len(ts) - 1
		t := ts[last]

		for i := last - 1; i >= 0; i-- {
			t = Normal(cons(ts[i], t))
		}

		return t
	})

func cons(t1, t2 *Thunk) ListType {
	return ListType{t1, t2}
}

var First = NewStrictFunction(
	NewSignature(
		[]string{"list"}, []OptionalArgument{}, "",
		[]string{}, []OptionalArgument{}, "",
	),
	func(os ...Object) Object {
		if len(os) != 1 {
			return NumArgsError("first", "1")
		}

		o := os[0]
		l, ok := o.(ListType)

		if !ok {
			return notListError(o)
		} else if l == emptyList {
			return emptyListError()
		}

		return l.first
	})

var Rest = NewStrictFunction(
	NewSignature(
		[]string{"list"}, []OptionalArgument{}, "",
		[]string{}, []OptionalArgument{}, "",
	),
	func(os ...Object) Object {
		if len(os) != 1 {
			return NumArgsError("rest", "1")
		}

		o := os[0]
		l, ok := o.(ListType)

		if !ok {
			return notListError(o)
		} else if l == emptyList {
			return emptyListError()
		}

		return l.rest
	})

var appendFuncSignature = NewSignature(
	[]string{"list", "elem"}, []OptionalArgument{}, "",
	[]string{}, []OptionalArgument{}, "",
)

var Append = NewLazyFunction(appendFuncSignature, appendFunc)

func appendFunc(ts ...*Thunk) Object {
	o := ts[0].Eval()
	l, ok := o.(ListType)

	if !ok {
		return notListError(o)
	}

	if l == emptyList {
		return NewList(ts[1])
	}

	return cons(
		l.first,
		PApp(NewLazyFunction(appendFuncSignature, appendFunc), l.rest, ts[1]),
	)
}

func notListError(o Object) *Thunk {
	return TypeError(o, "List")
}

func emptyListError() *Thunk {
	return ValueError("The list is empty. You cannot apply rest.")
}

func (l ListType) merge(ts ...*Thunk) Object {
	if l == emptyList {
		return PApp(Merge, ts...)
	}

	return cons(l.first, PApp(Merge, append([]*Thunk{l.rest}, ts...)...))
}

// ordered

func (l ListType) less(ord ordered) bool {
	ll := ord.(ListType)

	if ll == emptyList {
		return false
	} else if l == emptyList {
		return true
	}

	// Compare firsts

	o1 := l.first.Eval()
	o2 := ll.first.Eval()

	if less(o1, o2) {
		return true
	} else if less(o2, o1) {
		return false
	}

	// Compare rests

	return less(l.rest.Eval(), ll.rest.Eval())
}

func (l ListType) ToThunks() ([]*Thunk, *Thunk) {
	ts := make([]*Thunk, 0)

	for l != emptyList {
		ts = append(ts, l.first)

		o := l.rest.Eval()
		var ok bool
		l, ok = o.(ListType)

		if !ok {
			return nil, notListError(o)
		}
	}

	return ts, nil
}

func (l ListType) ToObjects() ([]Object, *Thunk) {
	ts, err := l.ToThunks()

	if err != nil {
		return nil, err
	}

	os := make([]Object, len(ts))

	for _, t := range ts {
		go t.Eval()
	}

	for i, t := range ts {
		os[i] = t.Eval()
	}

	return os, nil
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net/http"

	"gopkg.in/mgo.v2"
)

// Period hold the information of an activity
type Period struct {
	Type string `json:"type"` // pomodoro or rest
}

type Periods []Period

// createPeriod handler lets you create a period obect.
//
func createPeriod(w http.ResponseWriter, r *http.Request) {

	if r.Method != "POST" {
		data := struct {
			Status           int    `json:"status"`
			DeveloperMessage string `json:"developerMessage"`
			UserMessage      string `json:"userMessage"`
		}{
			Status:           400,
			DeveloperMessage: "createPeriod only POST requests are supported for this route.",
			UserMessage:      "Oops, something went wrong, we are unable to save your data right now.",
		}

		log.Println("sending response")
		if err := renderJson(w, data); err != nil {
			log.Println(err)
		}
		return
	}

	var strType string

	if strType = r.FormValue("type"); len(strType) == 0 {
		log.Println("empty type")
		data := struct {
			Status           int    `json:"status"`
			DeveloperMessage string `json:"developerMessage"`
			UserMessage      string `json:"userMessage"`
		}{
			Status:           400,
			DeveloperMessage: "createPeriod had empty type parameter, unable to create period.",
			UserMessage:      "Oops, something went wrong, we are unable to save your data right now.",
		}

		log.Println("sending response")
		if err := renderJson(w, data); err != nil {
			log.Println(err)
		}
		return
	} else {
		if strType != "pomodoro" && strType != "rest" {
			log.Println("empty type")
			data := struct {
				Status           int    `json:"status"`
				DeveloperMessage string `json:"developerMessage"`
				UserMessage      string `json:"userMessage"`
			}{
				Status:           400,
				DeveloperMessage: "createPeriod has wrong type, unable to create period.",
				UserMessage:      "Oops, something went wrong, we are unable to save your data right now.",
			}

			log.Println("sending response")
			if err := renderJson(w, data); err != nil {
				log.Println(err)
			}
			return
		}
	}

	var uri string
	uri = getMongoURI()

	log.Println("uri found: ", uri)

	var err error
	var session *mgo.Session

	log.Println("start dial")
	if session, err = mgo.Dial(uri); err != nil {
		panic(err)
	}
	log.Println("dial done")

	defer session.Close()
	log.Println("setting session mode")
	session.SetMode(mgo.Monotonic, true)

	log.Println("trying to get pomotime database")
	collection := session.DB("").C("period")

	log.Println("start insert to period entity")
	var p Period
	p = Period{strType}

	if err = collection.Insert(&p); err != nil {
		log.Fatal(err)
	}

	data := struct {
		Status           int    `json:"status"`
		DeveloperMessage string `json:"developerMessage"`
		UserMessage      string `json:"userMessage"`
	}{
		Status:           200,
		DeveloperMessage: "app correctly stored period in database.",
		UserMessage:      "your data was stored correctly.",
	}

	log.Println("sending response")
	if err := renderJson(w, data); err != nil {
		log.Println(err)
	}
}

// getPeriods handler returns a list of periods.
//
func getPeriods(w http.ResponseWriter, r *http.Request) {

	if r.Method != "GET" {
		data := struct {
			Status           int    `json:"status"`
			DeveloperMessage string `json:"developerMessage"`
			UserMessage      string `json:"userMessage"`
		}{
			Status:           400,
			DeveloperMessage: "getPeriods: only GET requests are supported for this route.",
			UserMessage:      "Oops, something went wrong, we are unable to get your data right now.",
		}

		log.Println("sending response")
		if err := renderJson(w, data); err != nil {
			log.Println(err)
		}
		return
	}

	var uri string
	uri = getMongoURI()

	log.Println("uri found: ", uri)

	var err error
	var session *mgo.Session

	log.Println("start dial")
	if session, err = mgo.Dial(uri); err != nil {
		panic(err)
	}
	log.Println("dial done")

	defer session.Close()
	log.Println("setting session mode")
	session.SetMode(mgo.Monotonic, true)

	log.Println("trying database")
	collection := session.DB("").C("period")

	var results []Period

	log.Println("start search for all period objects")
	if err = collection.Find(nil).All(&results); err != nil {
		log.Fatal(err)
	}

	data := struct {
		Status           int     `json:"status"`
		DeveloperMessage string  `json:"developerMessage"`
		UserMessage      string  `json:"userMessage"`
		Periods          Periods `json:"periods"`
	}{
		Status:           200,
		DeveloperMessage: "returning all periods from database.",
		UserMessage:      "",
		Periods:          results,
	}

	log.Println("sending response")
	if err := renderJson(w, data); err != nil {
		log.Println(err)
	}
}
<commit_msg>write http header when something goes wrong<commit_after>package main

import (
	"log"
	"net/http"

	"gopkg.in/mgo.v2"
)

// Period hold the information of an activity
type Period struct {
	Type string `json:"type"` // pomodoro or rest
}

type Periods []Period

// createPeriod handler lets you create a period obect.
//
func createPeriod(w http.ResponseWriter, r *http.Request) {

	if r.Method != "POST" {
		data := struct {
			Status           int    `json:"status"`
			DeveloperMessage string `json:"developerMessage"`
			UserMessage      string `json:"userMessage"`
		}{
			Status:           400,
			DeveloperMessage: "createPeriod only POST requests are supported for this route.",
			UserMessage:      "Oops, something went wrong, we are unable to save your data right now.",
		}
		w.WriteHeader(http.StatusBadRequest)

		log.Println("sending response")

		if err := renderJson(w, data); err != nil {
			log.Println(err)
		}
		return
	}

	var strType string

	if strType = r.FormValue("type"); len(strType) == 0 {
		log.Println("empty type")
		data := struct {
			Status           int    `json:"status"`
			DeveloperMessage string `json:"developerMessage"`
			UserMessage      string `json:"userMessage"`
		}{
			Status:           400,
			DeveloperMessage: "createPeriod had empty type parameter, unable to create period.",
			UserMessage:      "Oops, something went wrong, we are unable to save your data right now.",
		}
		w.WriteHeader(http.StatusBadRequest)
		log.Println("sending response")
		if err := renderJson(w, data); err != nil {
			log.Println(err)
		}
		return
	} else {
		if strType != "pomodoro" && strType != "rest" {
			log.Println("empty type")
			data := struct {
				Status           int    `json:"status"`
				DeveloperMessage string `json:"developerMessage"`
				UserMessage      string `json:"userMessage"`
			}{
				Status:           400,
				DeveloperMessage: "createPeriod has wrong type, unable to create period.",
				UserMessage:      "Oops, something went wrong, we are unable to save your data right now.",
			}
			w.WriteHeader(http.StatusBadRequest)
			log.Println("sending response")
			if err := renderJson(w, data); err != nil {
				log.Println(err)
			}
			return
		}
	}

	var uri string
	uri = getMongoURI()

	log.Println("uri found: ", uri)

	var err error
	var session *mgo.Session

	log.Println("start dial")
	if session, err = mgo.Dial(uri); err != nil {
		panic(err)
	}
	log.Println("dial done")

	defer session.Close()
	log.Println("setting session mode")
	session.SetMode(mgo.Monotonic, true)

	log.Println("trying to get pomotime database")
	collection := session.DB("").C("period")

	log.Println("start insert to period entity")
	var p Period
	p = Period{strType}

	if err = collection.Insert(&p); err != nil {
		log.Fatal(err)
	}

	data := struct {
		Status           int    `json:"status"`
		DeveloperMessage string `json:"developerMessage"`
		UserMessage      string `json:"userMessage"`
	}{
		Status:           200,
		DeveloperMessage: "app correctly stored period in database.",
		UserMessage:      "your data was stored correctly.",
	}

	log.Println("sending response")
	if err := renderJson(w, data); err != nil {
		log.Println(err)
	}
}

// getPeriods handler returns a list of periods.
//
func getPeriods(w http.ResponseWriter, r *http.Request) {

	if r.Method != "GET" {
		data := struct {
			Status           int    `json:"status"`
			DeveloperMessage string `json:"developerMessage"`
			UserMessage      string `json:"userMessage"`
		}{
			Status:           400,
			DeveloperMessage: "getPeriods: only GET requests are supported for this route.",
			UserMessage:      "Oops, something went wrong, we are unable to get your data right now.",
		}
		w.WriteHeader(http.StatusBadRequest)
		log.Println("sending response")
		if err := renderJson(w, data); err != nil {
			log.Println(err)
		}
		return
	}

	var uri string
	uri = getMongoURI()

	log.Println("uri found: ", uri)

	var err error
	var session *mgo.Session

	log.Println("start dial")
	if session, err = mgo.Dial(uri); err != nil {
		panic(err)
	}
	log.Println("dial done")

	defer session.Close()
	log.Println("setting session mode")
	session.SetMode(mgo.Monotonic, true)

	log.Println("trying database")
	collection := session.DB("").C("period")

	var results []Period

	log.Println("start search for all period objects")
	if err = collection.Find(nil).All(&results); err != nil {
		log.Fatal(err)
	}

	data := struct {
		Status           int     `json:"status"`
		DeveloperMessage string  `json:"developerMessage"`
		UserMessage      string  `json:"userMessage"`
		Periods          Periods `json:"periods"`
	}{
		Status:           200,
		DeveloperMessage: "returning all periods from database.",
		UserMessage:      "",
		Periods:          results,
	}

	log.Println("sending response")
	if err := renderJson(w, data); err != nil {
		log.Println(err)
	}
}
<|endoftext|>


<commit_before>package interceptor

import (
	"bytes"
	"encoding/json"
	"testing"

	"github.com/namely/mjolnir/logger"

	"golang.org/x/net/context"
	"google.golang.org/grpc"

	"github.com/sirupsen/logrus"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

// LogLine is only used to parse log lines from interceptors making it
// easier to test
type logLine struct {
	Msg       string      `json:"msg"`
	RequestID string      `json:"request_id"`
	Duration  json.Number `json:"core.duration,Number"`
}

func TestLoggerInterceptor(t *testing.T) {
	i := New()
	l := logrus.New()
	l.Formatter = &logrus.JSONFormatter{}
	buf := new(bytes.Buffer)
	l.Out = buf

	i.Use(Logger(l))
	middleware := i.Middleware()
	ctx := context.TODO()
	info := &grpc.UnaryServerInfo{FullMethod: "/package.service/method"}
	final := func(ctx context.Context, in interface{}) (interface{}, error) {
		e := logger.FromContext(ctx)
		e.Info("from handler")
		return nil, nil
	}

	middleware(ctx, nil, info, final)

	decoder := json.NewDecoder(buf)

	var firstLine logLine
	require.NoError(t, decoder.Decode(&firstLine))
	assert.Equal(t, "from handler", firstLine.Msg)
	assert.NotEmpty(t, firstLine.RequestID)

	var secondLine logLine
	require.NoError(t, decoder.Decode(&secondLine))
	assert.Equal(t, "finished rpc", secondLine.Msg)
	assert.NotEmpty(t, secondLine.RequestID)
	assert.NotEmpty(t, secondLine.Duration)
}
<commit_msg>Fix tests<commit_after>package interceptor

import (
	"bytes"
	"encoding/json"
	"testing"

	"github.com/namely/mjolnir/logger"

	"golang.org/x/net/context"
	"google.golang.org/grpc"

	"github.com/sirupsen/logrus"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

// LogLine is only used to parse log lines from interceptors making it
// easier to test
type logLine struct {
	Msg       string      `json:"msg"`
	RequestID string      `json:"request_id"`
	Duration  json.Number `json:"core.duration,Number"`
}

func TestLoggerInterceptor(t *testing.T) {
	i := New()
	l := logrus.New()
	l.Formatter = &logrus.JSONFormatter{}
	buf := new(bytes.Buffer)
	l.Out = buf

	i.Use(Logger(l))
	middleware := i.Middleware()
	ctx := context.TODO()
	info := &grpc.UnaryServerInfo{FullMethod: "/package.service/method"}
	final := func(ctx context.Context, in interface{}) (interface{}, error) {
		e := logger.FromContext(ctx)
		e.Info("from handler")
		return nil, nil
	}

	middleware(ctx, nil, info, final)

	decoder := json.NewDecoder(buf)

	var firstLine logLine
	require.NoError(t, decoder.Decode(&firstLine))
	assert.Equal(t, "from handler", firstLine.Msg)
	assert.NotEmpty(t, firstLine.RequestID)
}
<|endoftext|>


<commit_before>package client

import (
	"testing"
)

func TestBuild(t *testing.T) {
	if client := build("id", "secret", "refresh"); client == nil {
		t.Errorf("did not return client")
	}
}
<commit_msg>Unshadow package name.<commit_after>package client

import (
	"testing"
)

func TestBuild(t *testing.T) {
	if cli := build("id", "secret", "refresh"); cli == nil {
		t.Errorf("did not return client")
	}
}
<|endoftext|>


<commit_before>package gcp

import (
	"context"
	"io"
	"strings"
	"time"

	"golang.org/x/oauth2/jwt"

	"cloud.google.com/go/storage"

	"github.com/cloudfoundry-incubator/bits-service"
	"github.com/cloudfoundry-incubator/bits-service/blobstores/validate"
	"github.com/cloudfoundry-incubator/bits-service/config"
	"github.com/cloudfoundry-incubator/bits-service/logger"
	"github.com/cloudfoundry-incubator/bits-service/util"
	"github.com/pkg/errors"
	"google.golang.org/api/iterator"
	"google.golang.org/api/option"
)

type Blobstore struct {
	client    *storage.Client
	jwtConfig *jwt.Config
	bucket    string
}

func NewBlobstore(config config.GCPBlobstoreConfig) *Blobstore {
	validate.NotEmpty(config.Bucket)
	validate.NotEmpty(config.Email)
	validate.NotEmpty(config.PrivateKey)
	validate.NotEmpty(config.PrivateKeyID)
	validate.NotEmpty(config.TokenURL)

	ctx := context.TODO()

	jwtConfig := &jwt.Config{
		Email:        config.Email,
		PrivateKey:   []byte(config.PrivateKey),
		PrivateKeyID: config.PrivateKeyID,
		Scopes:       []string{storage.ScopeFullControl},
		TokenURL:     config.TokenURL,
	}
	client, err := storage.NewClient(ctx, option.WithTokenSource(jwtConfig.TokenSource(ctx)))
	if err != nil {
		panic(err)
	}
	return &Blobstore{
		client:    client,
		bucket:    config.Bucket,
		jwtConfig: jwtConfig,
	}
}

func (blobstore *Blobstore) Exists(path string) (bool, error) {
	_, e := blobstore.client.Bucket(blobstore.bucket).Object(path).NewReader(context.TODO())

	if e != nil {
		e = blobstore.handleError(e, "Failed to check for %v/%v", blobstore.bucket, path)
		if _, ok := e.(*bitsgo.NotFoundError); ok {
			return false, nil
		}
		return false, e
	}
	return true, nil
}

func (blobstore *Blobstore) HeadOrRedirectAsGet(path string) (redirectLocation string, err error) {
	return storage.SignedURL(blobstore.bucket, path, &storage.SignedURLOptions{
		GoogleAccessID: blobstore.jwtConfig.Email,
		PrivateKey:     blobstore.jwtConfig.PrivateKey,
		Method:         "GET",
		Expires:        time.Now().Add(time.Hour),
	})
}

func (blobstore *Blobstore) Get(path string) (body io.ReadCloser, err error) {
	logger.Log.Debugw("Get from GCP", "bucket", blobstore.bucket, "path", path)
	reader, e := blobstore.client.Bucket(blobstore.bucket).Object(path).NewReader(context.TODO())
	if e != nil {
		return nil, blobstore.handleError(e, "Path %v", path)
	}
	return reader, nil
}

func (blobstore *Blobstore) GetOrRedirect(path string) (body io.ReadCloser, redirectLocation string, err error) {
	signedUrl, e := blobstore.HeadOrRedirectAsGet(path)
	return nil, signedUrl, e
}

func (blobstore *Blobstore) Put(path string, src io.ReadSeeker) error {
	logger.Log.Debugw("Put to GCP", "bucket", blobstore.bucket, "path", path)
	if e := blobstore.bucketExists(); e != nil {
		return e
	}
	writer := blobstore.client.Bucket(blobstore.bucket).Object(path).NewWriter(context.TODO())
	var safeCloser util.SafeCloser
	defer safeCloser.Close(writer)

	_, e := io.Copy(writer, src)
	if e != nil {
		return errors.Wrapf(e, "Path %v", path)
	}

	e = safeCloser.Close(writer)
	if e != nil {
		return errors.Wrapf(e, "Path %v", path)
	}
	return nil
}

func (blobstore *Blobstore) Copy(src, dest string) error {
	logger.Log.Debugw("Copy in GCP", "bucket", blobstore.bucket, "src", src, "dest", dest)
	_, e := blobstore.client.Bucket(blobstore.bucket).Object(dest).CopierFrom(blobstore.client.Bucket(blobstore.bucket).Object(src)).Run(context.TODO())
	if e != nil {
		return blobstore.handleError(e, "Error while trying to copy src %v to dest %v in bucket %v", src, dest, blobstore.bucket)
	}
	return nil
}

func (blobstore *Blobstore) Delete(path string) error {
	e := blobstore.client.Bucket(blobstore.bucket).Object(path).Delete(context.TODO())
	if e != nil {
		return blobstore.handleError(e, "Path %v", path)
	}
	return nil
}

func (blobstore *Blobstore) DeleteDir(prefix string) error {
	deletionErrs := []error{}
	it := blobstore.client.Bucket(blobstore.bucket).Objects(context.TODO(), &storage.Query{Prefix: prefix})
	for {
		attrs, e := it.Next()
		if e == iterator.Done {
			break
		}
		if e != nil {
			return errors.Wrapf(e, "Prefix %v", prefix)
		}
		e = blobstore.Delete(attrs.Name)
		if e != nil {
			if _, isNotFoundError := e.(*bitsgo.NotFoundError); !isNotFoundError {
				deletionErrs = append(deletionErrs, e)
			}
		}
	}
	if len(deletionErrs) != 0 {
		return errors.Errorf("Prefix %v, errors from deleting: %v", prefix, deletionErrs)
	}
	return nil
}

func (blobstore *Blobstore) Sign(resource string, method string, expirationTime time.Time) (signedURL string) {
	if strings.ToLower(method) != "get" && method != "put" {
		panic("The only supported methods are 'put' and 'get'")
	}
	signedURL, e := storage.SignedURL(blobstore.bucket, resource, &storage.SignedURLOptions{
		GoogleAccessID: blobstore.jwtConfig.Email,
		PrivateKey:     blobstore.jwtConfig.PrivateKey,
		Method:         strings.ToUpper(method),
		Expires:        expirationTime,
	})
	if e != nil {
		panic(e)
	}
	logger.Log.Debugw("Signed URL", "verb", method, "signed-url", signedURL)
	return
}

func (blobstore *Blobstore) handleError(e error, context string, args ...interface{}) error {
	if e == storage.ErrObjectNotExist {
		e := blobstore.bucketExists()
		if e != nil {
			return e
		}
		return bitsgo.NewNotFoundError()
	}
	return errors.Wrapf(e, context, args...)
}

func (blobstore *Blobstore) bucketExists() error {
	_, e := blobstore.client.Bucket(blobstore.bucket).Attrs(context.TODO())
	if e != nil {
		return errors.Wrapf(e, "Error while checking for bucket existence. Bucket '%v'", blobstore.bucket)
	}
	return nil
}
<commit_msg>Introduce 10s timeout on GCP deletes<commit_after>package gcp

import (
	"context"
	"io"
	"strings"
	"time"

	"golang.org/x/oauth2/jwt"

	"cloud.google.com/go/storage"

	"github.com/cloudfoundry-incubator/bits-service"
	"github.com/cloudfoundry-incubator/bits-service/blobstores/validate"
	"github.com/cloudfoundry-incubator/bits-service/config"
	"github.com/cloudfoundry-incubator/bits-service/logger"
	"github.com/cloudfoundry-incubator/bits-service/util"
	"github.com/pkg/errors"
	"google.golang.org/api/iterator"
	"google.golang.org/api/option"
)

type Blobstore struct {
	client    *storage.Client
	jwtConfig *jwt.Config
	bucket    string
}

func NewBlobstore(config config.GCPBlobstoreConfig) *Blobstore {
	validate.NotEmpty(config.Bucket)
	validate.NotEmpty(config.Email)
	validate.NotEmpty(config.PrivateKey)
	validate.NotEmpty(config.PrivateKeyID)
	validate.NotEmpty(config.TokenURL)

	ctx := context.TODO()

	jwtConfig := &jwt.Config{
		Email:        config.Email,
		PrivateKey:   []byte(config.PrivateKey),
		PrivateKeyID: config.PrivateKeyID,
		Scopes:       []string{storage.ScopeFullControl},
		TokenURL:     config.TokenURL,
	}
	client, err := storage.NewClient(ctx, option.WithTokenSource(jwtConfig.TokenSource(ctx)))
	if err != nil {
		panic(err)
	}
	return &Blobstore{
		client:    client,
		bucket:    config.Bucket,
		jwtConfig: jwtConfig,
	}
}

func (blobstore *Blobstore) Exists(path string) (bool, error) {
	_, e := blobstore.client.Bucket(blobstore.bucket).Object(path).NewReader(context.TODO())

	if e != nil {
		e = blobstore.handleError(e, "Failed to check for %v/%v", blobstore.bucket, path)
		if _, ok := e.(*bitsgo.NotFoundError); ok {
			return false, nil
		}
		return false, e
	}
	return true, nil
}

func (blobstore *Blobstore) HeadOrRedirectAsGet(path string) (redirectLocation string, err error) {
	return storage.SignedURL(blobstore.bucket, path, &storage.SignedURLOptions{
		GoogleAccessID: blobstore.jwtConfig.Email,
		PrivateKey:     blobstore.jwtConfig.PrivateKey,
		Method:         "GET",
		Expires:        time.Now().Add(time.Hour),
	})
}

func (blobstore *Blobstore) Get(path string) (body io.ReadCloser, err error) {
	logger.Log.Debugw("Get from GCP", "bucket", blobstore.bucket, "path", path)
	reader, e := blobstore.client.Bucket(blobstore.bucket).Object(path).NewReader(context.TODO())
	if e != nil {
		return nil, blobstore.handleError(e, "Path %v", path)
	}
	return reader, nil
}

func (blobstore *Blobstore) GetOrRedirect(path string) (body io.ReadCloser, redirectLocation string, err error) {
	signedUrl, e := blobstore.HeadOrRedirectAsGet(path)
	return nil, signedUrl, e
}

func (blobstore *Blobstore) Put(path string, src io.ReadSeeker) error {
	logger.Log.Debugw("Put to GCP", "bucket", blobstore.bucket, "path", path)
	if e := blobstore.bucketExists(); e != nil {
		return e
	}
	writer := blobstore.client.Bucket(blobstore.bucket).Object(path).NewWriter(context.TODO())
	var safeCloser util.SafeCloser
	defer safeCloser.Close(writer)

	_, e := io.Copy(writer, src)
	if e != nil {
		return errors.Wrapf(e, "Path %v", path)
	}

	e = safeCloser.Close(writer)
	if e != nil {
		return errors.Wrapf(e, "Path %v", path)
	}
	return nil
}

func (blobstore *Blobstore) Copy(src, dest string) error {
	logger.Log.Debugw("Copy in GCP", "bucket", blobstore.bucket, "src", src, "dest", dest)
	_, e := blobstore.client.Bucket(blobstore.bucket).Object(dest).CopierFrom(blobstore.client.Bucket(blobstore.bucket).Object(src)).Run(context.TODO())
	if e != nil {
		return blobstore.handleError(e, "Error while trying to copy src %v to dest %v in bucket %v", src, dest, blobstore.bucket)
	}
	return nil
}

func (blobstore *Blobstore) Delete(path string) error {
	ctx, cancel := context.WithTimeout(context.TODO(), 10*time.Second)
	defer cancel()

	e := blobstore.client.Bucket(blobstore.bucket).Object(path).Delete(ctx)
	if e != nil {
		return blobstore.handleError(e, "Path %v", path)
	}
	return nil
}

func (blobstore *Blobstore) DeleteDir(prefix string) error {
	deletionErrs := []error{}
	it := blobstore.client.Bucket(blobstore.bucket).Objects(context.TODO(), &storage.Query{Prefix: prefix})
	for {
		attrs, e := it.Next()
		if e == iterator.Done {
			break
		}
		if e != nil {
			return errors.Wrapf(e, "Prefix %v", prefix)
		}
		e = blobstore.Delete(attrs.Name)
		if e != nil {
			if _, isNotFoundError := e.(*bitsgo.NotFoundError); !isNotFoundError {
				deletionErrs = append(deletionErrs, e)
			}
		}
	}
	if len(deletionErrs) != 0 {
		return errors.Errorf("Prefix %v, errors from deleting: %v", prefix, deletionErrs)
	}
	return nil
}

func (blobstore *Blobstore) Sign(resource string, method string, expirationTime time.Time) (signedURL string) {
	if strings.ToLower(method) != "get" && method != "put" {
		panic("The only supported methods are 'put' and 'get'")
	}
	signedURL, e := storage.SignedURL(blobstore.bucket, resource, &storage.SignedURLOptions{
		GoogleAccessID: blobstore.jwtConfig.Email,
		PrivateKey:     blobstore.jwtConfig.PrivateKey,
		Method:         strings.ToUpper(method),
		Expires:        expirationTime,
	})
	if e != nil {
		panic(e)
	}
	logger.Log.Debugw("Signed URL", "verb", method, "signed-url", signedURL)
	return
}

func (blobstore *Blobstore) handleError(e error, context string, args ...interface{}) error {
	if e == storage.ErrObjectNotExist {
		e := blobstore.bucketExists()
		if e != nil {
			return e
		}
		return bitsgo.NewNotFoundError()
	}
	return errors.Wrapf(e, context, args...)
}

func (blobstore *Blobstore) bucketExists() error {
	_, e := blobstore.client.Bucket(blobstore.bucket).Attrs(context.TODO())
	if e != nil {
		return errors.Wrapf(e, "Error while checking for bucket existence. Bucket '%v'", blobstore.bucket)
	}
	return nil
}
<|endoftext|>


<commit_before>// +build integration

/*
http://www.apache.org/licenses/LICENSE-2.0.txt

Copyright 2015 Intel Corporation

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

	http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package hana

import (
	"bytes"
	"encoding/gob"
	"errors"
	"testing"
	"time"

	"github.com/intelsdi-x/snap/control/plugin"
	"github.com/intelsdi-x/snap/core"
	"github.com/intelsdi-x/snap/core/ctypes"

	. "github.com/smartystreets/goconvey/convey"
)

func TestHANAPublish(t *testing.T) {
	var buf bytes.Buffer
	metrics := []plugin.MetricType{
		*plugin.NewMetricType(core.NewNamespace("test_string"), time.Now(), nil, "", "example_string"),
		*plugin.NewMetricType(core.NewNamespace("test_int"), time.Now(), nil, "", 1),
		*plugin.NewMetricType(core.NewNamespace("test_string_slice"), time.Now(), nil, "", []string{"str1", "str2"}),
		*plugin.NewMetricType(core.NewNamespace("test_string_slice"), time.Now(), nil, "", []int{1, 2}),
		*plugin.NewMetricType(core.NewNamespace("test_uint8"), time.Now(), nil, "", uint8(1)),
	}
	config := make(map[string]ctypes.ConfigValue)
	enc := gob.NewEncoder(&buf)
	enc.Encode(metrics)

	Convey("TestHANAPublish", t, func() {
		config["username"] = ctypes.ConfigValueStr{Value: "root"}
		config["password"] = ctypes.ConfigValueStr{Value: "root"}
		config["database"] = ctypes.ConfigValueStr{Value: "SNAP_TEST"}
		config["host"] = ctypes.ConfigValueStr{Value: "localhost"}
		config["port"] = ctypes.ConfigValueStr{Value: "1433"}
		config["table name"] = ctypes.ConfigValueStr{Value: "info"}
		sp := NewHANAPublisher()
		cp, _ := sp.GetConfigPolicy()
		cfg, _ := cp.Get([]string{""}).Process(config)
		err := sp.Publish("", buf.Bytes(), *cfg)
		Convey("So not passing in a content type should result in an error", func() {
			So(err, ShouldResemble, errors.New("Unknown content type ''"))
		})
		err = sp.Publish(plugin.SnapGOBContentType, buf.Bytes(), *cfg)
		Convey("So publishing metrics should not result in an error", func() {
			So(err, ShouldBeNil)
		})
	})
}
<commit_msg>fix for #11<commit_after>// +build integration

/*
http://www.apache.org/licenses/LICENSE-2.0.txt

Copyright 2015 Intel Corporation

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

	http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package hana

import (
	"bytes"
	"encoding/gob"
	"errors"
	"testing"
	"time"

	"github.com/intelsdi-x/snap/control/plugin"
	"github.com/intelsdi-x/snap/core"
	"github.com/intelsdi-x/snap/core/ctypes"

	. "github.com/smartystreets/goconvey/convey"
)

func TestHANAPublish(t *testing.T) {
	var buf bytes.Buffer
	metrics := []plugin.MetricType{
		*plugin.NewMetricType(core.NewNamespace("test_string"), time.Now(), nil, "", "example_string"),
		*plugin.NewMetricType(core.NewNamespace("test_int"), time.Now(), nil, "", 1),
		*plugin.NewMetricType(core.NewNamespace("test_string_slice"), time.Now(), nil, "", []string{"str1", "str2"}),
		*plugin.NewMetricType(core.NewNamespace("test_string_slice"), time.Now(), nil, "", []int{1, 2}),
		*plugin.NewMetricType(core.NewNamespace("test_uint8"), time.Now(), nil, "", uint8(1)),
	}
	config := make(map[string]ctypes.ConfigValue)
	enc := gob.NewEncoder(&buf)
	enc.Encode(metrics)

	Convey("TestHANAPublish", t, func() {
		config["username"] = ctypes.ConfigValueStr{Value: "root"}
		config["password"] = ctypes.ConfigValueStr{Value: "root"}
		config["database"] = ctypes.ConfigValueStr{Value: "SNAP_TEST"}
		config["host"] = ctypes.ConfigValueStr{Value: "localhost"}
		config["port"] = ctypes.ConfigValueStr{Value: "1433"}
		config["tablename"] = ctypes.ConfigValueStr{Value: "info"}
		sp := NewHANAPublisher()
		cp, _ := sp.GetConfigPolicy()
		cfg, _ := cp.Get([]string{""}).Process(config)
		err := sp.Publish("", buf.Bytes(), *cfg)
		Convey("So not passing in a content type should result in an error", func() {
			So(err, ShouldResemble, errors.New("Unknown content type ''"))
		})
		err = sp.Publish(plugin.SnapGOBContentType, buf.Bytes(), *cfg)
		Convey("So publishing metrics should not result in an error", func() {
			So(err, ShouldBeNil)
		})
	})
}
<|endoftext|>


<commit_before>package filter

import (
	"github.com/pa001024/MoeCron/source"
	"github.com/pa001024/MoeCron/util"
	"net/url"
	"regexp"
	"strings"
)

type FilterMoegirlwiki struct { // 萌娘百科
	IFilter
	Filter

	WikiUrl string `json:"wiki_url"`
}

var (
	rep_mw_round1 = regexp.MustCompile(
		`^[\s\S]+?\s==? ?(?:基本介绍|简介|簡介|.{2,4}设定|.{2,4}介绍) ?==\n|` + // 去除第一个区块前的所有内容 替换为空 如果没有任何区块则不会替换
			`{{(?:Bd|lang[-\|].+?)\|(.+?)}}|` + // 替换生日/lang为明文 $1
			// `{{.+}}|{{[^{]+?}}|` + // 去除所有{{}}标签 - 因为Go的正则不支持平衡组(也就.NET支持了)已经换成util.RemoveBlock()
			`{\|[\s\S]+?\|}|` + // 去除所有{||}标签
			`\[\[(\s+[^\|]+?)[\s\S]+?\]\]|` + // 替换[[明文|词条名]]词条链接为明文 即$2
			`\[\[([^\[]+?)\]\]|` + // 替换[[明文]]词条链接为明文 $3
			`<s>.+?</s>|` + // 去除所有<s></s>标签
			`<ref.*?>.+?</ref>|` + // 去除所有<ref></ref>标签
			`<\w+>(.+?)</\w+>` + // 替换所有HTML标签为明文 即$4
			``)
	rep_mw_round2 = regexp.MustCompile(
		`(?:\n|^).{1,12}[：:].+|` + // 去除说明体文字 如 姓名: xxx  `\n(?:本名|姓名|身高|机体|声优|种别|种类|萌点|年龄)[：:].+` +
			`''+(.+?)''+|` + // 替换粗体为明文 即$1
			`(?:\n|^)\|.+|` + // 去除表格
			`== (?:基本信息|登场作品|人物档案|人物信息|外部链接) ==[\s\S]+?(==|$)|` + // 去除无用区块 $2
			`==+? ?.+? ?==+|` + // 去除标题
			`[\*;] ?|` + // 去除列表
			`\[\[(\s+[^\|]+?)[\s\S]+?\]\]|` + // 替换[[明文|词条名]]词条链接为明文 即$3
			`\[\[([^\[]+?)\]\]|` + // 替换[[明文]]词条链接为明文 $4
			`<[A-z/].+?>` + // 去除HTML标签如
<references />
			``)
	rep_mw_round3 = regexp.MustCompile(
		`===+ (?:基本资料) ===+[\s\S]+?(==|$)|` + // 去除无用小区块 $1
			`(\n)\n+|` + // 去除连续两个以上的换行符 $2
			`^\s+|` + // 去除开头空白
			`（待补完）|` + // 去除（待补完）
			`[^\S\n]\s+` + // 去除两个以上的空白符 行文中分词的单个空格不会被替换 中文空格不会被替换
			``)
	flp_mw = regexp.MustCompile(`R18`)

	// {{[\s\S]+?}}|\[\[[\s\S]+?\]\]|'''(.+?)'''|== (.+?) ==|<references />|\s+
)

func (this *FilterMoegirlwiki) FilterContent(src string) (dst string) {
	dst = rep_mw_round1.ReplaceAllString(src, "$1$2$3$4")
	dst = util.RemoveBlock(dst, "{{", "}}")
	dst = rep_mw_round2.ReplaceAllString(dst, "$1$2$3$4")
	dst = rep_mw_round3.ReplaceAllString(dst, "$1$2")
	return dst
}

func (this *FilterMoegirlwiki) Process(src []*source.FeedInfo) (dst []*source.FeedInfo) {
	dst = make([]*source.FeedInfo, 0, 10)
	for _, v := range src {
		if !flp_mw.MatchString(v.Title) && !flp_mw.MatchString(v.Content) {
			nv := *v
			nv.Content = this.FilterContent(nv.Content)
			nv.Link = this.WikiUrl + url.QueryEscape(strings.Replace(nv.Title, " ", "_", 0)) // TODO: 可能不工作
			dst = append(dst, &nv)
		}
	}
	return
}
<commit_msg>Fix FilterMoegirlwiki {{Bd|1xxx|}}<commit_after>package filter

import (
	"github.com/pa001024/MoeCron/source"
	"github.com/pa001024/MoeCron/util"
	"net/url"
	"regexp"
	"strings"
)

type FilterMoegirlwiki struct { // 萌娘百科
	IFilter
	Filter

	WikiUrl string `json:"wiki_url"`
}

var (
	rep_mw_round1 = regexp.MustCompile(
		`^[\s\S]+?\s==? ?(?:基本介绍|简介|簡介|.{2,4}设定|.{2,4}介绍) ?==\n|` + // 去除第一个区块前的所有内容 替换为空 如果没有任何区块则不会替换
			`{{(?:[Bb][Dd]|[Ll]ang[-\|].+?)\|(.+?)}}|` + // 替换生日/lang为明文 $1
			// `{{.+}}|{{[^{]+?}}|` + // 去除所有{{}}标签 - 因为Go的正则不支持平衡组(也就.NET支持了)已经换成util.RemoveBlock()
			`{\|[\s\S]+?\|}|` + // 去除所有{||}标签
			`\[\[(\s+[^\|]+?)[\s\S]+?\]\]|` + // 替换[[明文|词条名]]词条链接为明文 即$2
			`\[\[([^\[]+?)\]\]|` + // 替换[[明文]]词条链接为明文 $3
			`<s>.+?</s>|` + // 去除所有<s></s>标签
			`<ref.*?>.+?</ref>|` + // 去除所有<ref></ref>标签
			`<\w+>(.+?)</\w+>` + // 替换所有HTML标签为明文 即$4
			``)
	rep_mw_round2 = regexp.MustCompile(
		`(?:\n|^).{1,12}[：:].+|` + // 去除说明体文字 如 姓名: xxx  `\n(?:本名|姓名|身高|机体|声优|种别|种类|萌点|年龄)[：:].+` +
			`''+(.+?)''+|` + // 替换粗体为明文 即$1
			`(?:\n|^)\|.+|` + // 去除表格
			`== (?:基本信息|登场作品|人物档案|人物信息|外部链接) ==[\s\S]+?(==|$)|` + // 去除无用区块 $2
			`==+? ?.+? ?==+|` + // 去除标题
			`[\*;] ?|` + // 去除列表
			`\[\[(\s+[^\|]+?)[\s\S]+?\]\]|` + // 替换[[明文|词条名]]词条链接为明文 即$3
			`\[\[([^\[]+?)\]\]|` + // 替换[[明文]]词条链接为明文 $4
			`<[A-z/].+?>` + // 去除HTML标签如
<references />
			``)
	rep_mw_round3 = regexp.MustCompile(
		`===+ (?:基本资料) ===+[\s\S]+?(==|$)|` + // 去除无用小区块 $1
			`(\n)\n+|` + // 去除连续两个以上的换行符 $2
			`^\s+|` + // 去除开头空白
			`（待补完）|` + // 去除（待补完）
			`[^\S\n]\s+` + // 去除两个以上的空白符 行文中分词的单个空格不会被替换 中文空格不会被替换
			``)
	flp_mw = regexp.MustCompile(`R18`)

	// {{[\s\S]+?}}|\[\[[\s\S]+?\]\]|'''(.+?)'''|== (.+?) ==|<references />|\s+
)

func (this *FilterMoegirlwiki) FilterContent(src string) (dst string) {
	dst = rep_mw_round1.ReplaceAllString(src, "$1$2$3$4")
	dst = util.RemoveBlock(dst, "{{", "}}")
	dst = rep_mw_round2.ReplaceAllString(dst, "$1$2$3$4")
	dst = rep_mw_round3.ReplaceAllString(dst, "$1$2")
	return dst
}

func (this *FilterMoegirlwiki) Process(src []*source.FeedInfo) (dst []*source.FeedInfo) {
	dst = make([]*source.FeedInfo, 0, 10)
	for _, v := range src {
		if !flp_mw.MatchString(v.Title) && !flp_mw.MatchString(v.Content) {
			nv := *v
			nv.Content = this.FilterContent(nv.Content)
			nv.Link = this.WikiUrl + url.QueryEscape(strings.Replace(nv.Title, " ", "_", 0)) // TODO: 可能不工作
			dst = append(dst, &nv)
		}
	}
	return
}
<|endoftext|>


<commit_before>package logging

import (
	"github.com/hhkbp2/testify/require"
	"os"
	"strings"
	"testing"
)

var (
	testRotateMaxBytes    = uint64(5 * 1000) // 5k bytes
	testRotateBackupCount = uint32(1)
)

func checkFileSize(t *testing.T, filename string) {
	fileInfo, err := os.Stat(filename)
	require.Nil(t, err)
	require.True(t, fileInfo.Size() > 0)
	require.True(t, uint64(fileInfo.Size()) <= testRotateMaxBytes)
}

func removeFile(t *testing.T, filename string) {
	err := os.Remove(filename)
	require.Nil(t, err)
}

func TestRotatingFileHandler_TruncateWithBackup(t *testing.T) {
	defer Shutdown()
	handler, err := NewRotatingFileHandler(
		testFileName, testFileMode, testRotateMaxBytes, testRotateBackupCount)
	require.Nil(t, err)
	logger := GetLogger("rfile1")
	logger.AddHandler(handler)
	// every message is 99 byte, and \n
	message := strings.Repeat("abcdefghij", 9) + "rstuvwxyz"
	size := uint64(len(message) + 1)
	total := testRotateMaxBytes * (uint64(testRotateBackupCount) + 2) / size
	for i := uint64(0); i < total; i++ {
		logger.Errorf(message)
	}
	logger.RemoveHandler(handler)
	handler.Close()
	checkFileSize(t, testFileName)
	checkFileSize(t, testFileName+".1")
	removeFile(t, testFileName)
	removeFile(t, testFileName+".1")
}

func TestRotatingFileHandler_AppendWithoutBackup(t *testing.T) {
	defer Shutdown()
	// clean up the existing log file
	if FileExists(testFileName) {
		require.Nil(t, os.Remove(testFileName))
	}
	backupCount := uint32(0)
	handler, err := NewRotatingFileHandler(
		testFileName, os.O_APPEND, testRotateMaxBytes, backupCount)
	require.Nil(t, err)
	logger := GetLogger("rfile2")
	logger.AddHandler(handler)
	message := strings.Repeat("abcdefghij", 9) + "rstuvwxyz"
	size := uint64(len(message) + 1)
	totalSize := testRotateMaxBytes * (uint64(testRotateBackupCount) + 2)
	times := totalSize / size
	for i := uint64(0); i < times; i++ {
		logger.Errorf(message)
	}
	logger.RemoveHandler(handler)
	handler.Close()
	fileInfo, err := os.Stat(testFileName)
	require.Nil(t, err)
	require.True(t, uint64(fileInfo.Size()) > testRotateMaxBytes)
	require.Equal(t, totalSize, uint64(fileInfo.Size()))
	removeFile(t, testFileName)
}
<commit_msg>add benchmark test for rotating file handler<commit_after>package logging

import (
	"github.com/hhkbp2/testify/require"
	"os"
	"strings"
	"testing"
)

var (
	testRotateMaxBytes    = uint64(5 * 1000) // 5k bytes
	testRotateBackupCount = uint32(1)
)

func checkFileSize(t *testing.T, filename string) {
	fileInfo, err := os.Stat(filename)
	require.Nil(t, err)
	require.True(t, fileInfo.Size() > 0)
	require.True(t, uint64(fileInfo.Size()) <= testRotateMaxBytes)
}

func removeFile(t *testing.T, filename string) {
	err := os.Remove(filename)
	require.Nil(t, err)
}

func TestRotatingFileHandler_TruncateWithBackup(t *testing.T) {
	defer Shutdown()
	handler, err := NewRotatingFileHandler(
		testFileName, testFileMode, testRotateMaxBytes, testRotateBackupCount)
	require.Nil(t, err)
	logger := GetLogger("rfile1")
	logger.AddHandler(handler)
	// every message is 99 byte, and \n
	message := strings.Repeat("abcdefghij", 9) + "rstuvwxyz"
	size := uint64(len(message) + 1)
	total := testRotateMaxBytes * (uint64(testRotateBackupCount) + 2) / size
	for i := uint64(0); i < total; i++ {
		logger.Errorf(message)
	}
	logger.RemoveHandler(handler)
	handler.Close()
	checkFileSize(t, testFileName)
	checkFileSize(t, testFileName+".1")
	removeFile(t, testFileName)
	removeFile(t, testFileName+".1")
}

func TestRotatingFileHandler_AppendWithoutBackup(t *testing.T) {
	defer Shutdown()
	// clean up the existing log file
	if FileExists(testFileName) {
		require.Nil(t, os.Remove(testFileName))
	}
	backupCount := uint32(0)
	handler, err := NewRotatingFileHandler(
		testFileName, os.O_APPEND, testRotateMaxBytes, backupCount)
	require.Nil(t, err)
	logger := GetLogger("rfile2")
	logger.AddHandler(handler)
	message := strings.Repeat("abcdefghij", 9) + "rstuvwxyz"
	size := uint64(len(message) + 1)
	totalSize := testRotateMaxBytes * (uint64(testRotateBackupCount) + 2)
	times := totalSize / size
	for i := uint64(0); i < times; i++ {
		logger.Errorf(message)
	}
	logger.RemoveHandler(handler)
	handler.Close()
	fileInfo, err := os.Stat(testFileName)
	require.Nil(t, err)
	require.True(t, uint64(fileInfo.Size()) > testRotateMaxBytes)
	require.Equal(t, totalSize, uint64(fileInfo.Size()))
	removeFile(t, testFileName)
}

func BenchmarkRotatingFileHandler(b *testing.B) {
	b.StopTimer()
	defer Shutdown()
	if FileExists(testFileName) {
		os.Remove(testFileName)
	}
	rotateMaxBytes := uint64(1024 * 1024 * 1024 * 1) // 1G
	backupCount := uint32(0)
	handler, err := NewRotatingFileHandler(
		testFileName, os.O_APPEND, rotateMaxBytes, backupCount)
	if err != nil {
		panic("fail to get handler")
	}
	logger := GetLogger("rfileBen")
	logger.AddHandler(handler)
	message := strings.Repeat("abcdefghij", 10)
	b.StartTimer()
	for i := 0; i < b.N; i++ {
		logger.Errorf(message)
	}
}
<|endoftext|>