<commit_before>package main

import (
	"context"
	"path"

	"github.com/spf13/cobra"

	"github.com/restic/restic/internal/debug"
	"github.com/restic/restic/internal/errors"
	"github.com/restic/restic/internal/repository"
	"github.com/restic/restic/internal/restic"
)

var cmdRewrite = &cobra.Command{
	Use:   "rewrite [f] [all|snapshotID ...]",
	Short: "Modify existing snapshots by deleting files",
	Long: `
The "rewrite" command excludes files from existing snapshots.

By default 'rewrite' will create new snapshot that will contains same data as
source snapshot except excluded data. All metadata (time, host, tags) will be preserved.
Special tag 'rewrite' will be added to new snapshot to distinguish it from source
(unless --inplace is used)

If --inplace option is used, old snapshot will be removed from repository.

Snapshots to rewrite are specified using --host, --tag, --path or by providing list of snapshotID.
Alternatively it's possible to use special 'all' snapshot that will match all snapshots

Please note, that this command only modifies snapshot objects. In order to delete
data from repository use 'prune' command

EXIT STATUS
===========

Exit status is 0 if the command was successful, and non-zero if there was any error.
`,
	DisableAutoGenTag: true,
	RunE: func(cmd *cobra.Command, args []string) error {
		return runRewrite(rewriteOptions, globalOptions, args)
	},
}

// RewriteOptions collects all options for the ls command.
type RewriteOptions struct {
	// TagOptions bundles all options for the 'tag' command.
	Hosts   []string
	Paths   []string
	Tags    restic.TagLists
	Inplace bool
	DryRun  bool

	// Exclude options
	Excludes            []string
	InsensitiveExcludes []string
	ExcludeFiles        []string
}

var rewriteOptions RewriteOptions

func init() {
	cmdRoot.AddCommand(cmdRewrite)

	f := cmdRewrite.Flags()
	f.StringArrayVarP(&rewriteOptions.Hosts, "host", "H", nil, "only consider snapshots for this `host`, when no snapshot ID is given (can be specified multiple times)")
	f.Var(&rewriteOptions.Tags, "tag", "only consider snapshots which include this `taglist`, when no snapshot-ID is given")
	f.StringArrayVar(&rewriteOptions.Paths, "path", nil, "only consider snapshots which include this (absolute) `path`, when no snapshot-ID is given")
	f.BoolVarP(&rewriteOptions.Inplace, "inplace", "", false, "replace existing snapshots")
	f.BoolVarP(&rewriteOptions.DryRun, "dry-run", "n", false, "do not do anything, just print what would be done")

	// Excludes
	f.StringArrayVarP(&rewriteOptions.Excludes, "exclude", "e", nil, "exclude a `pattern` (can be specified multiple times)")
	f.StringArrayVar(&rewriteOptions.InsensitiveExcludes, "iexclude", nil, "same as --exclude `pattern` but ignores the casing of filenames")
	f.StringArrayVar(&rewriteOptions.ExcludeFiles, "exclude-file", nil, "read exclude patterns from a `file` (can be specified multiple times)")
}

type saveTreeFunction = func(*restic.Tree) (restic.ID, error)

func filterNode(ctx context.Context, repo restic.Repository, nodepath string, nodeID restic.ID, checkExclude RejectByNameFunc, saveTreeFunc saveTreeFunction) (newNodeID restic.ID, err error) {
	curTree, err := repo.LoadTree(ctx, nodeID)
	if err != nil {
		return nodeID, err
	}

	debug.Log("filterNode: %s, nodeId: %s\n", nodepath, nodeID.Str())

	changed := false
	newTree := restic.NewTree()
	for _, node := range curTree.Nodes {
		path := path.Join(nodepath, node.Name)
		if !checkExclude(path) {
			if node.Subtree == nil {
				newTree.Insert(node)
				continue
			}
			newNode := node
			newID, err := filterNode(ctx, repo, path, *node.Subtree, checkExclude, saveTreeFunc)
			if err != nil {
				return nodeID, err
			}
			if newID == *node.Subtree {
				newTree.Insert(node)
			} else {
				changed = true
				newNode.Subtree = new(restic.ID)
				*newNode.Subtree = newID
				newTree.Insert(newNode)
			}
		} else {
			Verbosef("excluding %s\n", path)
			changed = true
		}
	}

	if changed {
		// Save new tree
		newTreeID, err := saveTreeFunc(newTree)
		debug.Log("filterNode: save new tree for %s as %v\n", nodepath, newTreeID)
		return newTreeID, err
	}

	return nodeID, nil
}

func collectRejectFuncsForRewrite(opts RewriteOptions) (fs []RejectByNameFunc, err error) {
	//TODO: merge with cmd_backup

	// add patterns from file
	if len(opts.ExcludeFiles) > 0 {
		excludes, err := readExcludePatternsFromFiles(opts.ExcludeFiles)
		if err != nil {
			return nil, err
		}
		opts.Excludes = append(opts.Excludes, excludes...)
	}

	if len(opts.InsensitiveExcludes) > 0 {
		fs = append(fs, rejectByInsensitivePattern(opts.InsensitiveExcludes))
	}

	if len(opts.Excludes) > 0 {
		fs = append(fs, rejectByPattern(opts.Excludes))
	}

	return fs, nil
}

func rewriteSnapshot(ctx context.Context, repo *repository.Repository, sn *restic.Snapshot, opts RewriteOptions, gopts GlobalOptions) (bool, error) {
	if sn.Tree == nil {
		return false, errors.Errorf("snapshot %v has nil tree", sn.ID().Str())
	}

	var saveTreeFunc saveTreeFunction
	if !opts.DryRun {
		saveTreeFunc = func(tree *restic.Tree) (restic.ID, error) {
			return repo.SaveTree(ctx, tree)
		}
	} else {
		saveTreeFunc = func(tree *restic.Tree) (restic.ID, error) {
			return restic.ID{0}, nil
		}
	}

	rejectByNameFuncs, err := collectRejectFuncsForRewrite(opts)
	if err != nil {
		return false, err
	}

	checkExclude := func(nodepath string) bool {
		for _, reject := range rejectByNameFuncs {
			if reject(nodepath) {
				return true
			}
		}
		return false
	}

	filteredTree, err := filterNode(ctx, repo, "/", *sn.Tree, checkExclude, saveTreeFunc)

	if err != nil {
		return false, err
	}

	if filteredTree == *sn.Tree {
		debug.Log("Snapshot not touched\n")
		return false, nil
	}

	debug.Log("Snapshot modified\n")
	if opts.DryRun {
		Printf("Will modify snapshot: %s\n", sn.String())
		return true, nil
	}

	err = repo.Flush(ctx)
	if err != nil {
		return false, err
	}
	err = repo.SaveIndex(ctx)
	if err != nil {
		return false, err
	}

	// Retain the original snapshot id over all tag changes.
	if sn.Original == nil {
		sn.Original = sn.ID()
	}
	*sn.Tree = filteredTree

	if !opts.Inplace {
		sn.AddTags([]string{"rewrite"})
	}

	// Save the new snapshot.
	id, err := repo.SaveJSONUnpacked(ctx, restic.SnapshotFile, sn)
	if err != nil {
		return false, err
	}
	err = repo.Flush(ctx)
	if err != nil {
		return true, err
	}

	if opts.Inplace {
		h := restic.Handle{Type: restic.SnapshotFile, Name: sn.ID().String()}
		if err = repo.Backend().Remove(ctx, h); err != nil {
			return false, err
		}

		debug.Log("old snapshot %v removed", sn.ID())
	}
	Printf("new snapshot saved as %v\n", id)
	return true, nil
}

func runRewrite(opts RewriteOptions, gopts GlobalOptions, args []string) error {

	if len(opts.Hosts) == 0 && len(opts.Tags) == 0 && len(opts.Paths) == 0 && len(args) == 0 {
		return errors.Fatal("no snapshots provided")
	}

	if len(opts.ExcludeFiles) == 0 && len(opts.Excludes) == 0 && len(opts.InsensitiveExcludes) == 0 {
		return errors.Fatal("Nothing to do: no excludes provided")
	}

	if len(args) == 1 && args[0] == "all" {
		args = []string{}
	}

	repo, err := OpenRepository(gopts)
	if err != nil {
		return err
	}

	if !gopts.NoLock && !opts.DryRun {
		Verbosef("create exclusive lock for repository\n")
		lock, err := lockRepoExclusive(repo)
		defer unlockRepo(lock)
		if err != nil {
			return err
		}
	}

	if err = repo.LoadIndex(gopts.ctx); err != nil {
		return err
	}

	ctx, cancel := context.WithCancel(gopts.ctx)
	defer cancel()

	changedCount := 0
	for sn := range FindFilteredSnapshots(ctx, repo, opts.Hosts, opts.Tags, opts.Paths, args) {
		Verbosef("Checking snapshot %s\n", sn.String())
		changed, err := rewriteSnapshot(ctx, repo, sn, opts, gopts)
		if err != nil {
			Warnf("unable to rewrite snapshot ID %q, ignoring: %v\n", sn.ID(), err)
			continue
		}
		if changed {
			changedCount++
		}
	}

	if changedCount == 0 {
		Verbosef("no snapshots modified\n")
	} else {
		if !opts.DryRun {
			Verbosef("modified %v snapshots\n", changedCount)
		} else {
			Verbosef("dry run. %v snapshots affected\n", changedCount)
		}
	}

	return nil
}
<commit_msg>rewrite: fix compilation<commit_after>package main

import (
	"context"
	"path"

	"github.com/spf13/cobra"

	"github.com/restic/restic/internal/backend"
	"github.com/restic/restic/internal/debug"
	"github.com/restic/restic/internal/errors"
	"github.com/restic/restic/internal/repository"
	"github.com/restic/restic/internal/restic"
)

var cmdRewrite = &cobra.Command{
	Use:   "rewrite [f] [all|snapshotID ...]",
	Short: "Modify existing snapshots by deleting files",
	Long: `
The "rewrite" command excludes files from existing snapshots.

By default 'rewrite' will create new snapshot that will contains same data as
source snapshot except excluded data. All metadata (time, host, tags) will be preserved.
Special tag 'rewrite' will be added to new snapshot to distinguish it from source
(unless --inplace is used)

If --inplace option is used, old snapshot will be removed from repository.

Snapshots to rewrite are specified using --host, --tag, --path or by providing list of snapshotID.
Alternatively it's possible to use special 'all' snapshot that will match all snapshots

Please note, that this command only modifies snapshot objects. In order to delete
data from repository use 'prune' command

EXIT STATUS
===========

Exit status is 0 if the command was successful, and non-zero if there was any error.
`,
	DisableAutoGenTag: true,
	RunE: func(cmd *cobra.Command, args []string) error {
		return runRewrite(cmd.Context(), rewriteOptions, globalOptions, args)
	},
}

// RewriteOptions collects all options for the ls command.
type RewriteOptions struct {
	// TagOptions bundles all options for the 'tag' command.
	Hosts   []string
	Paths   []string
	Tags    restic.TagLists
	Inplace bool
	DryRun  bool

	// Exclude options
	Excludes            []string
	InsensitiveExcludes []string
	ExcludeFiles        []string
}

var rewriteOptions RewriteOptions

func init() {
	cmdRoot.AddCommand(cmdRewrite)

	f := cmdRewrite.Flags()
	f.StringArrayVarP(&rewriteOptions.Hosts, "host", "H", nil, "only consider snapshots for this `host`, when no snapshot ID is given (can be specified multiple times)")
	f.Var(&rewriteOptions.Tags, "tag", "only consider snapshots which include this `taglist`, when no snapshot-ID is given")
	f.StringArrayVar(&rewriteOptions.Paths, "path", nil, "only consider snapshots which include this (absolute) `path`, when no snapshot-ID is given")
	f.BoolVarP(&rewriteOptions.Inplace, "inplace", "", false, "replace existing snapshots")
	f.BoolVarP(&rewriteOptions.DryRun, "dry-run", "n", false, "do not do anything, just print what would be done")

	// Excludes
	f.StringArrayVarP(&rewriteOptions.Excludes, "exclude", "e", nil, "exclude a `pattern` (can be specified multiple times)")
	f.StringArrayVar(&rewriteOptions.InsensitiveExcludes, "iexclude", nil, "same as --exclude `pattern` but ignores the casing of filenames")
	f.StringArrayVar(&rewriteOptions.ExcludeFiles, "exclude-file", nil, "read exclude patterns from a `file` (can be specified multiple times)")
}

type saveTreeFunction = func(*restic.Tree) (restic.ID, error)

func filterNode(ctx context.Context, repo restic.Repository, nodepath string, nodeID restic.ID, checkExclude RejectByNameFunc, saveTreeFunc saveTreeFunction) (newNodeID restic.ID, err error) {
	curTree, err := restic.LoadTree(ctx, repo, nodeID)
	if err != nil {
		return nodeID, err
	}

	debug.Log("filterNode: %s, nodeId: %s\n", nodepath, nodeID.Str())

	changed := false
	newTree := restic.NewTree(len(curTree.Nodes))
	for _, node := range curTree.Nodes {
		path := path.Join(nodepath, node.Name)
		if !checkExclude(path) {
			if node.Subtree == nil {
				newTree.Insert(node)
				continue
			}
			newNode := node
			newID, err := filterNode(ctx, repo, path, *node.Subtree, checkExclude, saveTreeFunc)
			if err != nil {
				return nodeID, err
			}
			if newID == *node.Subtree {
				newTree.Insert(node)
			} else {
				changed = true
				newNode.Subtree = new(restic.ID)
				*newNode.Subtree = newID
				newTree.Insert(newNode)
			}
		} else {
			Verbosef("excluding %s\n", path)
			changed = true
		}
	}

	if changed {
		// Save new tree
		newTreeID, err := saveTreeFunc(newTree)
		debug.Log("filterNode: save new tree for %s as %v\n", nodepath, newTreeID)
		return newTreeID, err
	}

	return nodeID, nil
}

func collectRejectFuncsForRewrite(opts RewriteOptions) (fs []RejectByNameFunc, err error) {
	//TODO: merge with cmd_backup

	// add patterns from file
	if len(opts.ExcludeFiles) > 0 {
		excludes, err := readExcludePatternsFromFiles(opts.ExcludeFiles)
		if err != nil {
			return nil, err
		}
		opts.Excludes = append(opts.Excludes, excludes...)
	}

	if len(opts.InsensitiveExcludes) > 0 {
		fs = append(fs, rejectByInsensitivePattern(opts.InsensitiveExcludes))
	}

	if len(opts.Excludes) > 0 {
		fs = append(fs, rejectByPattern(opts.Excludes))
	}

	return fs, nil
}

func rewriteSnapshot(ctx context.Context, repo *repository.Repository, sn *restic.Snapshot, opts RewriteOptions, gopts GlobalOptions) (bool, error) {
	if sn.Tree == nil {
		return false, errors.Errorf("snapshot %v has nil tree", sn.ID().Str())
	}

	var saveTreeFunc saveTreeFunction
	if !opts.DryRun {
		saveTreeFunc = func(tree *restic.Tree) (restic.ID, error) {
			return restic.SaveTree(ctx, repo, tree)
		}
	} else {
		saveTreeFunc = func(tree *restic.Tree) (restic.ID, error) {
			return restic.ID{0}, nil
		}
	}

	rejectByNameFuncs, err := collectRejectFuncsForRewrite(opts)
	if err != nil {
		return false, err
	}

	checkExclude := func(nodepath string) bool {
		for _, reject := range rejectByNameFuncs {
			if reject(nodepath) {
				return true
			}
		}
		return false
	}

	filteredTree, err := filterNode(ctx, repo, "/", *sn.Tree, checkExclude, saveTreeFunc)

	if err != nil {
		return false, err
	}

	if filteredTree == *sn.Tree {
		debug.Log("Snapshot not touched\n")
		return false, nil
	}

	debug.Log("Snapshot modified\n")
	if opts.DryRun {
		Printf("Will modify snapshot: %s\n", sn.String())
		return true, nil
	}

	err = repo.Flush(ctx)
	if err != nil {
		return false, err
	}

	// Retain the original snapshot id over all tag changes.
	if sn.Original == nil {
		sn.Original = sn.ID()
	}
	*sn.Tree = filteredTree

	if !opts.Inplace {
		sn.AddTags([]string{"rewrite"})
	}

	// Save the new snapshot.
	id, err := restic.SaveSnapshot(ctx, repo, sn)
	if err != nil {
		return false, err
	}
	err = repo.Flush(ctx)
	if err != nil {
		return true, err
	}

	if opts.Inplace {
		h := restic.Handle{Type: restic.SnapshotFile, Name: sn.ID().String()}
		if err = repo.Backend().Remove(ctx, h); err != nil {
			return false, err
		}

		debug.Log("old snapshot %v removed", sn.ID())
	}
	Printf("new snapshot saved as %v\n", id)
	return true, nil
}

func runRewrite(ctx context.Context, opts RewriteOptions, gopts GlobalOptions, args []string) error {

	if len(opts.Hosts) == 0 && len(opts.Tags) == 0 && len(opts.Paths) == 0 && len(args) == 0 {
		return errors.Fatal("no snapshots provided")
	}

	if len(opts.ExcludeFiles) == 0 && len(opts.Excludes) == 0 && len(opts.InsensitiveExcludes) == 0 {
		return errors.Fatal("Nothing to do: no excludes provided")
	}

	if len(args) == 1 && args[0] == "all" {
		args = []string{}
	}

	repo, err := OpenRepository(ctx, gopts)
	if err != nil {
		return err
	}

	if !gopts.NoLock && !opts.DryRun {
		Verbosef("create exclusive lock for repository\n")
		var lock *restic.Lock
		lock, ctx, err = lockRepoExclusive(ctx, repo)
		defer unlockRepo(lock)
		if err != nil {
			return err
		}
	}

	snapshotLister, err := backend.MemorizeList(ctx, repo.Backend(), restic.SnapshotFile)
	if err != nil {
		return err
	}

	if err = repo.LoadIndex(ctx); err != nil {
		return err
	}

	changedCount := 0
	for sn := range FindFilteredSnapshots(ctx, snapshotLister, repo, opts.Hosts, opts.Tags, opts.Paths, args) {
		Verbosef("Checking snapshot %s\n", sn.String())
		changed, err := rewriteSnapshot(ctx, repo, sn, opts, gopts)
		if err != nil {
			Warnf("unable to rewrite snapshot ID %q, ignoring: %v\n", sn.ID(), err)
			continue
		}
		if changed {
			changedCount++
		}
	}

	if changedCount == 0 {
		Verbosef("no snapshots modified\n")
	} else {
		if !opts.DryRun {
			Verbosef("modified %v snapshots\n", changedCount)
		} else {
			Verbosef("dry run. %v snapshots affected\n", changedCount)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package pubsub

import (
	"bytes"
	"encoding/gob"
	"fmt"
	"time"

	"cloud.google.com/go/pubsub"
	"golang.org/x/net/context"

	"github.com/skypies/adsb"
)

// {{{ NewClient

func NewClient(ctx context.Context, projectName string) *pubsub.Client {
	client, err := pubsub.NewClient(ctx, projectName)
	if err != nil {
		panic(fmt.Sprintf("pubsub.NewClient failed: %v", err))
	}

	return client
}

// }}}

// {{{ DeleteSub, CreateSub, PurgeSub

func DeleteSub (ctx context.Context, client *pubsub.Client, subscription string) error {
	return client.Subscription(subscription).Delete(ctx)
}
func CreateSub (ctx context.Context, client *pubsub.Client, subscription, topicId string) error {
	topic := client.Topic(topicId)
	cfg := pubsub.SubscriptionConfig{Topic:topic, AckDeadline: 10*time.Second}
	_,err := client.CreateSubscription(ctx, subscription, cfg)//topic, 10*time.Second, nil)
	return err
}

func RecreateSub(ctx context.Context, client *pubsub.Client, subscription, topic string) error {
	if err := DeleteSub(ctx, client, subscription); err != nil {
		return err
	}
	return CreateSub(ctx, client, subscription, topic)
}

// }}}
// {{{ Setup

func Setup (ctx context.Context, client *pubsub.Client, inTopic, inSub string) error {
	if exists,err := client.Topic(inTopic).Exists(ctx); err != nil {
		return err
	} else if !exists {
		if _,err := client.CreateTopic(ctx,inTopic); err != nil { return err }
	}

	if exists,err := client.Subscription(inSub).Exists(ctx); err != nil {
		return err
	} else if !exists {
		if err := CreateSub (ctx, client, inSub, inTopic); err != nil {
			return err
		}
	}
	return nil
}

// }}}

// {{{ PackPubsubMessage

func PackPubsubMessage(msgs []*adsb.CompositeMsg, receiverName string) (*pubsub.Message, error) {
	for i,_ := range msgs {
		msgs[i].ReceiverName = receiverName // Claim this message, for upstream fame & glory
	}

	var buf bytes.Buffer
	if err := gob.NewEncoder(&buf).Encode(msgs); err != nil {
		return nil, err
	}

	return &pubsub.Message{
		Data: buf.Bytes(),
	}, nil
}

// }}}
// {{{ UnpackPubsubMessage

func UnpackPubsubMessage(msg *pubsub.Message) ([]*adsb.CompositeMsg, error) {
	contents := []*adsb.CompositeMsg{}

	buf := bytes.NewBuffer(msg.Data)
	if err := gob.NewDecoder(buf).Decode(&contents); err != nil {
		return nil, fmt.Errorf("UnpackPubsubMsg: %v\n", err)
	}
	return contents, nil

}

// }}}

// https://godoc.org/cloud.google.com/go/pubsub
// {{{ PublishMsgs

// This function runs in its own goroutine, so as not to hold up reading new messages
func PublishMsgs(ctx context.Context, client *pubsub.Client, topic,receiverName string, msgs []*adsb.CompositeMsg) error {
	m,err := PackPubsubMessage(msgs, receiverName)
	if err != nil { return err }

	_,err = client.Topic(topic).Publish(ctx, m).Get()

/*
	if err != nil {
		//log.Errorf(c, "pubsub.Publish failed: %v", err)
	} else {
		//log.Infof(c, "Published a message with a message id: %s\n", msgIDs[0])
	}
*/

	return err
}

// }}}

// {{{ -------------------------={ E N D }=----------------------------------

// Local variables:
// folded-file: t
// end:

// }}}
<commit_msg>Vendoring fixups<commit_after>package pubsub

import (
	"bytes"
	"encoding/gob"
	"fmt"
	"time"

	"cloud.google.com/go/pubsub"
	"golang.org/x/net/context"

	"github.com/skypies/adsb"
)

// {{{ NewClient

func NewClient(ctx context.Context, projectName string) *pubsub.Client {
	client, err := pubsub.NewClient(ctx, projectName)
	if err != nil {
		panic(fmt.Sprintf("pubsub.NewClient failed: %v", err))
	}

	return client
}

// }}}

// {{{ DeleteSub, CreateSub, PurgeSub

func DeleteSub (ctx context.Context, client *pubsub.Client, subscription string) error {
	return client.Subscription(subscription).Delete(ctx)
}
func CreateSub (ctx context.Context, client *pubsub.Client, subscription, topicId string) error {
	topic := client.Topic(topicId)
	cfg := pubsub.SubscriptionConfig{Topic:topic, AckDeadline: 10*time.Second}
	_,err := client.CreateSubscription(ctx, subscription, cfg)//topic, 10*time.Second, nil)
	return err
}

func RecreateSub(ctx context.Context, client *pubsub.Client, subscription, topic string) error {
	if err := DeleteSub(ctx, client, subscription); err != nil {
		return err
	}
	return CreateSub(ctx, client, subscription, topic)
}

// }}}
// {{{ Setup

func Setup (ctx context.Context, client *pubsub.Client, inTopic, inSub string) error {
	if exists,err := client.Topic(inTopic).Exists(ctx); err != nil {
		return err
	} else if !exists {
		if _,err := client.CreateTopic(ctx,inTopic); err != nil { return err }
	}

	if exists,err := client.Subscription(inSub).Exists(ctx); err != nil {
		return err
	} else if !exists {
		if err := CreateSub (ctx, client, inSub, inTopic); err != nil {
			return err
		}
	}
	return nil
}

// }}}

// {{{ PackPubsubMessage

func PackPubsubMessage(msgs []*adsb.CompositeMsg, receiverName string) (*pubsub.Message, error) {
	for i,_ := range msgs {
		msgs[i].ReceiverName = receiverName // Claim this message, for upstream fame & glory
	}

	var buf bytes.Buffer
	if err := gob.NewEncoder(&buf).Encode(msgs); err != nil {
		return nil, err
	}

	return &pubsub.Message{
		Data: buf.Bytes(),
	}, nil
}

// }}}
// {{{ UnpackPubsubMessage

func UnpackPubsubMessage(msg *pubsub.Message) ([]*adsb.CompositeMsg, error) {
	contents := []*adsb.CompositeMsg{}

	buf := bytes.NewBuffer(msg.Data)
	if err := gob.NewDecoder(buf).Decode(&contents); err != nil {
		return nil, fmt.Errorf("UnpackPubsubMsg: %v\n", err)
	}
	return contents, nil

}

// }}}

// https://godoc.org/cloud.google.com/go/pubsub
// {{{ PublishMsgs

// This function runs in its own goroutine, so as not to hold up reading new messages
func PublishMsgs(ctx context.Context, client *pubsub.Client, topic,receiverName string, msgs []*adsb.CompositeMsg) error {
	m,err := PackPubsubMessage(msgs, receiverName)
	if err != nil { return err }

	_,err = client.Topic(topic).Publish(ctx, m).Get(ctx)

/*
	if err != nil {
		//log.Errorf(c, "pubsub.Publish failed: %v", err)
	} else {
		//log.Infof(c, "Published a message with a message id: %s\n", msgIDs[0])
	}
*/

	return err
}

// }}}

// {{{ -------------------------={ E N D }=----------------------------------

// Local variables:
// folded-file: t
// end:

// }}}
<|endoftext|>


<commit_before>// Copyright (c) 2018 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package codegen

import (
	"fmt"
	"path"
	"path/filepath"
	"sync"

	"encoding/json"
	"github.com/pkg/errors"
)

const clientInterface = "Client"

// helper struct to pull out the fixture config
type moduleConfig struct {
	Config *config `json:"config"`
}

// config is the struct corresponding to the config field in client-config.json
type config struct {
	CustomImportPath string   `json:"customImportPath"`
	Fixture          *Fixture `json:"fixture"`
}

// Fixture specifies client fixture import path and all scenarios
type Fixture struct {
	// ImportPath is the package where the user-defined Fixture global variable is contained.
	// The Fixture object defines, for a given client, the standardized list of fixture scenarios for that client
	ImportPath string `json:"importPath"`
	// Scenarios is a map from zanzibar's exposed method name to a list of user-defined fixture scenarios for a client
	Scenarios map[string][]string `json:"scenarios"`
}

// Validate the fixture configuration
func (f *Fixture) Validate(methods map[string]interface{}) error {
	if f.ImportPath == "" {
		return errors.New("fixture importPath is empty")
	}
	for m := range f.Scenarios {
		if _, ok := methods[m]; !ok {
			return errors.Errorf("%q is not a valid method", m)
		}
	}
	return nil
}

// ClientMockGenHook returns a PostGenHook to generate client mocks
func ClientMockGenHook(h *PackageHelper, t *Template) (PostGenHook, error) {
	bin, err := NewMockgenBin(h, t)
	if err != nil {
		return nil, errors.Wrap(err, "error building mockgen binary")
	}

	return func(instances map[string][]*ModuleInstance) error {
		fmt.Println("Generating client mocks:")
		mockCount := len(instances["client"])
		files := make(map[string][]byte)
		ec := make(chan error, mockCount)
		var wg sync.WaitGroup
		wg.Add(mockCount)
		for i, instance := range instances["client"] {
			go func(instance *ModuleInstance, i int) {
				defer wg.Done()

				var mc moduleConfig
				if err := json.Unmarshal(instance.JSONFileRaw, &mc); err != nil {
					ec <- errors.Wrapf(
						err,
						"error parsing client-config.json for client %q",
						instance.InstanceName,
					)
					return
				}

				buildDir := h.CodeGenTargetPath()
				genDir := filepath.Join(buildDir, instance.Directory, "mock-client")

				importPath := instance.PackageInfo.GeneratedPackagePath
				if instance.ClassType == "custom" {
					importPath = mc.Config.CustomImportPath
					if importPath == "" {
						ec <- errors.Errorf("custom client %q must have customImportPath", instance.ClassName)
						return
					}
				}

				// generate mock client
				mock, err := bin.GenMock(importPath, "clientmock", clientInterface)
				if err != nil {
					ec <- errors.Wrapf(
						err,
						"error generating mocks for client %q",
						instance.InstanceName,
					)
					return
				}
				files[filepath.Join(genDir, "mock_client.go")] = mock

				// generate fixture types and augmented mock client
				f := mc.Config.Fixture
				if f != nil && f.Scenarios != nil {
					types, augMock, err := bin.AugmentMockWithFixture(importPath, f, clientInterface)
					if err != nil {
						ec <- errors.Wrapf(
							err,
							"error generating mock client with fixtures for client %q",
							instance.InstanceName,
						)
						return
					}

					files[filepath.Join(genDir, "types.go")] = types
					files[filepath.Join(genDir, "mock_client_with_fixture.go")] = augMock
				}

				fmt.Printf(
					genFormattor,
					"mock",
					instance.ClassName,
					instance.InstanceName,
					path.Join(path.Base(buildDir), instance.Directory, "mock-client"),
					i+1, mockCount,
				)
			}(instance, i)
		}
		wg.Wait()

		select {
		case err := <-ec:
			return err
		default:
		}

		for p, data := range files {
			if err := writeAndFormat(p, data); err != nil {
				return err
			}
		}
		return nil
	}, nil
}

// ServiceMockGenHook returns a PostGenHook to generate service mocks
func ServiceMockGenHook(h *PackageHelper, t *Template) PostGenHook {
	return func(instances map[string][]*ModuleInstance) error {
		fmt.Println("Generating service mocks:")
		mockCount := len(instances["service"])
		files := make(map[string][]byte)
		ec := make(chan error, mockCount)
		var wg sync.WaitGroup
		wg.Add(mockCount)
		for i, instance := range instances["service"] {
			go func(instance *ModuleInstance, i int) {
				defer wg.Done()

				buildDir := h.CodeGenTargetPath()
				genDir := filepath.Join(buildDir, instance.Directory, "mock-service")

				mockInit, err := generateMockInitializer(instance, h, t)
				if err != nil {
					ec <- errors.Wrapf(
						err,
						"Error generating service mock_init.go for %s",
						instance.InstanceName,
					)
					return
				}
				files[filepath.Join(genDir, "mock_init.go")] = mockInit

				mockService, err := t.ExecTemplate("service_mock.tmpl", instance, h)
				if err != nil {
					ec <- errors.Wrapf(
						err,
						"Error generating service mock_service.go for %s",
						instance.InstanceName,
					)
					return
				}
				files[filepath.Join(genDir, "mock_service.go")] = mockService

				fmt.Printf(
					genFormattor,
					"mock",
					instance.ClassName,
					instance.InstanceName,
					path.Join(path.Base(buildDir), instance.Directory, "mock-service"),
					i+1, mockCount,
				)
			}(instance, i)
		}
		wg.Wait()

		select {
		case err := <-ec:
			return err
		default:
		}

		for p, data := range files {
			if err := writeAndFormat(p, data); err != nil {
				return err
			}
		}
		return nil
	}
}

// generateMockInitializer generates code to initialize modules with leaf nodes being mocks
func generateMockInitializer(instance *ModuleInstance, h *PackageHelper, t *Template) ([]byte, error) {
	leafWithFixture := map[string]string{}
	for _, leaf := range instance.RecursiveDependencies["client"] {
		var mc moduleConfig
		if err := json.Unmarshal(leaf.JSONFileRaw, &mc); err != nil {
			return nil, errors.Wrapf(
				err,
				"error parsing client-config.json for client %q",
				instance.InstanceName,
			)
		}
		if mc.Config != nil && mc.Config.Fixture != nil {
			leafWithFixture[leaf.InstanceName] = mc.Config.Fixture.ImportPath
		}
	}
	data := map[string]interface{}{
		"Instance":        instance,
		"LeafWithFixture": leafWithFixture,
	}
	return t.ExecTemplate("module_mock_initializer.tmpl", data, h)
}

// writeAndFormat writes the data to given file path, creates path if it does not exist and formats the file
func writeAndFormat(path string, data []byte) error {
	if err := writeFile(path, data); err != nil {
		return errors.Wrapf(
			err,
			"Error writing to file %q",
			path,
		)
	}
	if err := FormatGoFile(path); err != nil {
		return err
	}
	return nil
}
<commit_msg>Fix lint error<commit_after>// Copyright (c) 2018 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package codegen

import (
	"fmt"
	"path"
	"path/filepath"
	"sync"

	"encoding/json"
	"github.com/pkg/errors"
)

const clientInterface = "Client"

// helper struct to pull out the fixture config
type moduleConfig struct {
	Config *config `json:"config"`
}

// config is the struct corresponding to the config field in client-config.json
type config struct {
	CustomImportPath string   `json:"customImportPath"`
	Fixture          *Fixture `json:"fixture"`
}

// Fixture specifies client fixture import path and all scenarios
type Fixture struct {
	// ImportPath is the package where the user-defined Fixture global variable is contained.
	// The Fixture object defines, for a given client, the standardized list of fixture scenarios for that client
	ImportPath string `json:"importPath"`
	// Scenarios is a map from zanzibar's exposed method name to a list of user-defined fixture scenarios for a client
	Scenarios map[string][]string `json:"scenarios"`
}

// Validate the fixture configuration
func (f *Fixture) Validate(methods map[string]interface{}) error {
	if f.ImportPath == "" {
		return errors.New("fixture importPath is empty")
	}
	for m := range f.Scenarios {
		if _, ok := methods[m]; !ok {
			return errors.Errorf("%q is not a valid method", m)
		}
	}
	return nil
}

// ClientMockGenHook returns a PostGenHook to generate client mocks
func ClientMockGenHook(h *PackageHelper, t *Template) (PostGenHook, error) {
	bin, err := NewMockgenBin(h, t)
	if err != nil {
		return nil, errors.Wrap(err, "error building mockgen binary")
	}

	return func(instances map[string][]*ModuleInstance) error {
		fmt.Println("Generating client mocks:")
		mockCount := len(instances["client"])
		files := make(map[string][]byte)
		ec := make(chan error, mockCount)
		var wg sync.WaitGroup
		wg.Add(mockCount)
		for i, instance := range instances["client"] {
			go func(instance *ModuleInstance, i int) {
				defer wg.Done()

				var mc moduleConfig
				if err := json.Unmarshal(instance.JSONFileRaw, &mc); err != nil {
					ec <- errors.Wrapf(
						err,
						"error parsing client-config.json for client %q",
						instance.InstanceName,
					)
					return
				}

				buildDir := h.CodeGenTargetPath()
				genDir := filepath.Join(buildDir, instance.Directory, "mock-client")

				importPath := instance.PackageInfo.GeneratedPackagePath
				if instance.ClassType == "custom" {
					importPath = mc.Config.CustomImportPath
					if importPath == "" {
						ec <- errors.Errorf("custom client %q must have customImportPath", instance.ClassName)
						return
					}
				}

				// generate mock client
				mock, err := bin.GenMock(importPath, "clientmock", clientInterface)
				if err != nil {
					ec <- errors.Wrapf(
						err,
						"error generating mocks for client %q",
						instance.InstanceName,
					)
					return
				}
				files[filepath.Join(genDir, "mock_client.go")] = mock

				// generate fixture types and augmented mock client
				f := mc.Config.Fixture
				if f != nil && f.Scenarios != nil {
					types, augMock, err := bin.AugmentMockWithFixture(importPath, f, clientInterface)
					if err != nil {
						ec <- errors.Wrapf(
							err,
							"error generating mock client with fixtures for client %q",
							instance.InstanceName,
						)
						return
					}

					files[filepath.Join(genDir, "types.go")] = types
					files[filepath.Join(genDir, "mock_client_with_fixture.go")] = augMock
				}

				fmt.Printf(
					genFormattor,
					"mock",
					instance.ClassName,
					instance.InstanceName,
					path.Join(path.Base(buildDir), instance.Directory, "mock-client"),
					i+1, mockCount,
				)
			}(instance, i)
		}
		wg.Wait()

		select {
		case err := <-ec:
			return err
		default:
		}

		for p, data := range files {
			if err := writeAndFormat(p, data); err != nil {
				return err
			}
		}
		return nil
	}, nil
}

// ServiceMockGenHook returns a PostGenHook to generate service mocks
func ServiceMockGenHook(h *PackageHelper, t *Template) PostGenHook {
	return func(instances map[string][]*ModuleInstance) error {
		fmt.Println("Generating service mocks:")
		mockCount := len(instances["service"])
		files := make(map[string][]byte)
		ec := make(chan error, mockCount)
		var wg sync.WaitGroup
		wg.Add(mockCount)
		for i, instance := range instances["service"] {
			go func(instance *ModuleInstance, i int) {
				defer wg.Done()

				buildDir := h.CodeGenTargetPath()
				genDir := filepath.Join(buildDir, instance.Directory, "mock-service")

				mockInit, err := generateMockInitializer(instance, h, t)
				if err != nil {
					ec <- errors.Wrapf(
						err,
						"Error generating service mock_init.go for %s",
						instance.InstanceName,
					)
					return
				}
				files[filepath.Join(genDir, "mock_init.go")] = mockInit

				mockService, err := t.ExecTemplate("service_mock.tmpl", instance, h)
				if err != nil {
					ec <- errors.Wrapf(
						err,
						"Error generating service mock_service.go for %s",
						instance.InstanceName,
					)
					return
				}
				files[filepath.Join(genDir, "mock_service.go")] = mockService

				fmt.Printf(
					genFormattor,
					"mock",
					instance.ClassName,
					instance.InstanceName,
					path.Join(path.Base(buildDir), instance.Directory, "mock-service"),
					i+1, mockCount,
				)
			}(instance, i)
		}
		wg.Wait()

		select {
		case err := <-ec:
			return err
		default:
		}

		for p, data := range files {
			if err := writeAndFormat(p, data); err != nil {
				return err
			}
		}
		return nil
	}
}

// generateMockInitializer generates code to initialize modules with leaf nodes being mocks
func generateMockInitializer(instance *ModuleInstance, h *PackageHelper, t *Template) ([]byte, error) {
	leafWithFixture := map[string]string{}
	for _, leaf := range instance.RecursiveDependencies["client"] {
		var mc moduleConfig
		if err := json.Unmarshal(leaf.JSONFileRaw, &mc); err != nil {
			return nil, errors.Wrapf(
				err,
				"error parsing client-config.json for client %q",
				instance.InstanceName,
			)
		}
		if mc.Config != nil && mc.Config.Fixture != nil {
			leafWithFixture[leaf.InstanceName] = mc.Config.Fixture.ImportPath
		}
	}
	data := map[string]interface{}{
		"Instance":        instance,
		"LeafWithFixture": leafWithFixture,
	}
	return t.ExecTemplate("module_mock_initializer.tmpl", data, h)
}

// writeAndFormat writes the data to given file path, creates path if it does not exist and formats the file
func writeAndFormat(path string, data []byte) error {
	if err := writeFile(path, data); err != nil {
		return errors.Wrapf(
			err,
			"Error writing to file %q",
			path,
		)
	}
	return FormatGoFile(path)
}
<|endoftext|>


<commit_before>package formspec

import (
	"errors"
	"fmt"
)

// ----------------------------------------------------------------------------
// Error
// ----------------------------------------------------------------------------

type Error struct {
	Field   string `json:"field"`
	Message string `json:"message"`
}

func (ve *Error) Error() string {
	return ve.Message
}

// ----------------------------------------------------------------------------
// Formspec
// ----------------------------------------------------------------------------

type Form interface {
	FormValue(string) string
}

func New() *Formspec {
	return &Formspec{}
}

type Formspec struct {
	Rules []*Rule
}

func (f *Formspec) Rule(field string, ruleFunc RuleFunc) *Rule {
	rule := &Rule{Field: field, RuleFunc: ruleFunc}
	f.Rules = append(f.Rules, rule)
	return rule
}

func (fspec *Formspec) Validate(f Form) (errors []error, ok bool) {
	ok = true

	for _, rule := range fspec.Rules {
		err := rule.Call(f)

		if err != nil {
			ok = false
			errors = append(errors, &Error{Field: rule.Field, Message: err.Error()})
		}
	}

	return
}

func (f *Formspec) Clone() *Formspec {
	clone := &Formspec{}

	for _, rule := range f.Rules {
		clone.Rules = append(clone.Rules, rule.clone())
	}

	return clone
}

// ----------------------------------------------------------------------------
// Rule
// ----------------------------------------------------------------------------

type FilterFunc func(string) string
type RuleFunc func(value string, f Form) error

type Rule struct {
	Field       string
	RuleFunc    RuleFunc
	FilterFuncs []FilterFunc
	allowBlank  bool

	// This is used prior to Rule.message.
	fullMessage string
	// This is used prior to error message that is returned from Rule.RuleFunc.
	message string
}

func (v *Rule) AllowBlank() *Rule {
	v.allowBlank = true
	return v
}

// If you override error message. Use following funcs `FullMessage()/Message()`.

// FullMessage sets Rule.fullMessage.
func (v *Rule) FullMessage(m string) *Rule {
	v.fullMessage = m
	return v
}

// Message sets Rule.message.
func (v *Rule) Message(m string) *Rule {
	v.message = m
	return v
}

func (r *Rule) Filter(filterFunc FilterFunc) *Rule {
	r.FilterFuncs = append(r.FilterFuncs, filterFunc)
	return r
}

func (r *Rule) Call(f Form) error {
	v := f.FormValue(r.Field)

	// Filter value
	if len(r.FilterFuncs) > 0 {
		for _, filterFunc := range r.FilterFuncs {
			v = filterFunc(v)
		}
	}

	// If rule.allowblank is true, all rule returns no error when value is blank.
	if v == "" && r.allowBlank {
		return nil
	}

	err := r.RuleFunc(v, f)

	if err != nil {
		if r.fullMessage != "" {
			return errors.New(r.fullMessage)
		}

		if r.message != "" {
			return fmt.Errorf("%s %s", r.Field, r.message)
		}

		return fmt.Errorf("%s %s", r.Field, err.Error())
	}

	return nil
}

func (v *Rule) clone() *Rule {
	return &Rule{
		Field:       v.Field,
		RuleFunc:    v.RuleFunc,
		FilterFuncs: v.FilterFuncs,
		allowBlank:  v.allowBlank,
		message:     v.message,
		fullMessage: v.fullMessage,
	}
}
<commit_msg>Rename some internal variables.<commit_after>package formspec

import (
	"errors"
	"fmt"
)

// ----------------------------------------------------------------------------
// Error
// ----------------------------------------------------------------------------

type Error struct {
	Field   string `json:"field"`
	Message string `json:"message"`
}

func (e *Error) Error() string {
	return e.Message
}

// ----------------------------------------------------------------------------
// Formspec
// ----------------------------------------------------------------------------

type Form interface {
	FormValue(string) string
}

func New() *Formspec {
	return &Formspec{}
}

type Formspec struct {
	Rules []*Rule
}

func (f *Formspec) Rule(field string, ruleFunc RuleFunc) *Rule {
	rule := &Rule{Field: field, RuleFunc: ruleFunc}
	f.Rules = append(f.Rules, rule)
	return rule
}

func (f *Formspec) Validate(form Form) (errors []error, ok bool) {
	ok = true

	for _, rule := range f.Rules {
		err := rule.Call(form)

		if err != nil {
			ok = false
			errors = append(errors, &Error{Field: rule.Field, Message: err.Error()})
		}
	}

	return
}

func (f *Formspec) Clone() *Formspec {
	clone := &Formspec{}

	for _, rule := range f.Rules {
		clone.Rules = append(clone.Rules, rule.clone())
	}

	return clone
}

// ----------------------------------------------------------------------------
// Rule
// ----------------------------------------------------------------------------

type FilterFunc func(string) string
type RuleFunc func(value string, f Form) error

type Rule struct {
	Field       string
	RuleFunc    RuleFunc
	FilterFuncs []FilterFunc
	allowBlank  bool

	// This is used prior to Rule.message.
	fullMessage string
	// This is used prior to error message that is returned from Rule.RuleFunc.
	message string
}

func (r *Rule) AllowBlank() *Rule {
	r.allowBlank = true
	return r
}

// If you override error message. Use following funcs `FullMessage()/Message()`.

// FullMessage sets Rule.fullMessage.
func (r *Rule) FullMessage(m string) *Rule {
	r.fullMessage = m
	return r
}

// Message sets Rule.message.
func (r *Rule) Message(m string) *Rule {
	r.message = m
	return r
}

func (r *Rule) Filter(filterFunc FilterFunc) *Rule {
	r.FilterFuncs = append(r.FilterFuncs, filterFunc)
	return r
}

func (r *Rule) Call(f Form) error {
	v := f.FormValue(r.Field)

	// Filter value
	if len(r.FilterFuncs) > 0 {
		for _, filterFunc := range r.FilterFuncs {
			v = filterFunc(v)
		}
	}

	// If rule.allowblank is true, all rule returns no error when value is blank.
	if v == "" && r.allowBlank {
		return nil
	}

	err := r.RuleFunc(v, f)

	if err != nil {
		if r.fullMessage != "" {
			return errors.New(r.fullMessage)
		}

		if r.message != "" {
			return fmt.Errorf("%s %s", r.Field, r.message)
		}

		return fmt.Errorf("%s %s", r.Field, err.Error())
	}

	return nil
}

func (r *Rule) clone() *Rule {
	return &Rule{
		Field:       r.Field,
		RuleFunc:    r.RuleFunc,
		FilterFuncs: r.FilterFuncs,
		allowBlank:  r.allowBlank,
		message:     r.message,
		fullMessage: r.fullMessage,
	}
}
<|endoftext|>


<commit_before>package command

import (
	"strings"
	"github.com/webdevops/go-shell"
	"github.com/webdevops/go-shell/commandbuilder"
	"fmt"
)

type PostgresCommonOptions struct {
	Hostname string `long:"hostname"`
	Port     string `short:"P" long:"port"`
	Username string `short:"u" long:"user"`
	Password string `short:"p" long:"password"`
	Docker   string `          long:"docker"`
	SSH      string `          long:"ssh"`

	connection commandbuilder.Connection
	dumpCompression string
}

func postgresQuote(value string) string {
	return "'" + strings.Replace(value, "'", "\\'", -1) + "'"
}

func postgresIdentifier(value string) string {
	return "\"" + strings.Replace(value, "\"", "\\\"", -1) + "\""
}

func  (conf *PostgresCommonOptions) Init() {
	if conf.SSH != "" {
		conf.connection.Hostname = conf.SSH
		fmt.Println(fmt.Sprintf(" - Using ssh connection \"%s\"", conf.SSH))
	}

	if conf.Docker != "" {
		conf.connection.Docker = conf.Docker
		conf.InitDockerSettings()
	}
}

func (conf *PostgresCommonOptions) PsqlCommandBuilder(args ...string) []interface{} {
	connection := conf.connection.Clone()
	cmd := []string{}

	cmd = append(cmd, "psql")

	if conf.Hostname != "" {
		cmd = append(cmd, "-h", shell.Quote(conf.Hostname))
	}

	if conf.Port != "" {
		cmd = append(cmd, "-p", shell.Quote(conf.Port))
	}

	if conf.Username != "" {
		cmd = append(cmd, "-U", shell.Quote(conf.Username))
	}

	if conf.Password != "" {
		connection.Environment["PGPASSWORD"] = conf.Password
	}

	if len(args) > 0 {
		cmd = append(cmd, args...)
	}

	return connection.RawShellCommandBuilder(cmd...)
}

func (conf *PostgresCommonOptions) PgDumpCommandBuilder(schema string) []interface{} {
	connection := conf.connection.Clone()
	cmd := []string{}

	cmd = append(cmd, "pg_dump")

	if conf.Hostname != "" {
		cmd = append(cmd, "-h", shell.Quote(conf.Hostname))
	}

	if conf.Port != "" {
		cmd = append(cmd, "-p", shell.Quote(conf.Port))
	}

	if conf.Username != "" {
		cmd = append(cmd, "-U", shell.Quote(conf.Username))
	}

	if conf.Password != "" {
		connection.Environment["PGPASSWORD"] = conf.Password
	}

	cmd = append(cmd, shell.Quote(schema))

	switch conf.dumpCompression {
	case "gzip":
		cmd = append(cmd, "| gzip")
	case "bzip2":
		cmd = append(cmd, "| bzip2")
	case "xz":
		cmd = append(cmd, "| xz --compress --stdout")
	}

	return connection.RawShellCommandBuilder(cmd...)
}

func (conf *PostgresCommonOptions) PgDumpAllCommandBuilder() []interface{} {
	connection := conf.connection.Clone()
	cmd := []string{}

	cmd = append(cmd, "pg_dumpall", "-c")

	if conf.Hostname != "" {
		cmd = append(cmd, "-h", shell.Quote(conf.Hostname))
	}

	if conf.Port != "" {
		cmd = append(cmd, "-p", shell.Quote(conf.Port))
	}

	if conf.Username != "" {
		cmd = append(cmd, "-U", shell.Quote(conf.Username))
	}

	if conf.Password != "" {
		connection.Environment["PGPASSWORD"] = conf.Password
	}

	switch conf.dumpCompression {
	case "gzip":
		cmd = append(cmd, "| gzip")
	case "bzip2":
		cmd = append(cmd, "| bzip2")
	case "xz":
		cmd = append(cmd, "| xz --compress --stdout")
	}

	return connection.RawShellCommandBuilder(cmd...)
}

func (conf *PostgresCommonOptions) PostgresRestoreCommandBuilder(args ...string) []interface{} {
	connection := conf.connection.Clone()
	cmd := []string{}

	switch conf.dumpCompression {
	case "gzip":
		cmd = append(cmd, "gzip -dc |")
	case "bzip2":
		cmd = append(cmd, "bzcat |")
	case "xz":
		cmd = append(cmd, "xzcat |")
	}

	cmd = append(cmd, "pg_dump")

	if conf.Hostname != "" {
		cmd = append(cmd, "-h", shell.Quote(conf.Hostname))
	}

	if conf.Port != "" {
		cmd = append(cmd, "-p", shell.Quote(conf.Port))
	}

	if conf.Username != "" {
		cmd = append(cmd, "-U", shell.Quote(conf.Username))
	}

	if conf.Password != "" {
		connection.Environment["PGPASSWORD"] = conf.Password
	}

	if len(args) > 0 {
		cmd = append(cmd, args...)
	}

	return connection.RawShellCommandBuilder(cmd...)
}

func (conf *PostgresCommonOptions) ExecStatement(statement string) string {
	cmd := shell.Cmd(conf.PsqlCommandBuilder("postgres", "-c", shell.Quote(statement))...)
	return cmd.Run().Stdout.String()
}

func  (conf *PostgresCommonOptions) InitDockerSettings() {
	containerName := conf.connection.Docker

	connectionClone := conf.connection.Clone()
	connectionClone.Docker = ""
	connectionClone.Type  = "auto"

	containerId := connectionClone.DockerGetContainerId(containerName)
	fmt.Println(fmt.Sprintf(" - Using docker container \"%s\"", containerId))

	containerEnv := GetDockerEnvList(connectionClone, containerId)

	// get user from env
	if val, ok := containerEnv["POSTGRES_USER"]; ok {
		if conf.Username == "" {
			conf.Username = val
		}
	}

	// get user from env
	if val, ok := containerEnv["POSTGRES_PASSWORD"]; ok {
		if conf.Username == "" {
			conf.Password = val
		}
	}
}
<commit_msg>Fix postgres restore<commit_after>package command

import (
	"strings"
	"github.com/webdevops/go-shell"
	"github.com/webdevops/go-shell/commandbuilder"
	"fmt"
)

type PostgresCommonOptions struct {
	Hostname string `long:"hostname"`
	Port     string `short:"P" long:"port"`
	Username string `short:"u" long:"user"`
	Password string `short:"p" long:"password"`
	Docker   string `          long:"docker"`
	SSH      string `          long:"ssh"`

	connection commandbuilder.Connection
	dumpCompression string
}

func postgresQuote(value string) string {
	return "'" + strings.Replace(value, "'", "\\'", -1) + "'"
}

func postgresIdentifier(value string) string {
	return "\"" + strings.Replace(value, "\"", "\\\"", -1) + "\""
}

func  (conf *PostgresCommonOptions) Init() {
	if conf.SSH != "" {
		conf.connection.Hostname = conf.SSH
		fmt.Println(fmt.Sprintf(" - Using ssh connection \"%s\"", conf.SSH))
	}

	if conf.Docker != "" {
		conf.connection.Docker = conf.Docker
		conf.InitDockerSettings()
	}
}

func (conf *PostgresCommonOptions) PsqlCommandBuilder(args ...string) []interface{} {
	connection := conf.connection.Clone()
	cmd := []string{}

	cmd = append(cmd, "psql")

	if conf.Hostname != "" {
		cmd = append(cmd, "-h", shell.Quote(conf.Hostname))
	}

	if conf.Port != "" {
		cmd = append(cmd, "-p", shell.Quote(conf.Port))
	}

	if conf.Username != "" {
		cmd = append(cmd, "-U", shell.Quote(conf.Username))
	}

	if conf.Password != "" {
		connection.Environment["PGPASSWORD"] = conf.Password
	}

	if len(args) > 0 {
		cmd = append(cmd, args...)
	}

	return connection.RawShellCommandBuilder(cmd...)
}

func (conf *PostgresCommonOptions) PgDumpCommandBuilder(schema string) []interface{} {
	connection := conf.connection.Clone()
	cmd := []string{}

	cmd = append(cmd, "pg_dump")

	if conf.Hostname != "" {
		cmd = append(cmd, "-h", shell.Quote(conf.Hostname))
	}

	if conf.Port != "" {
		cmd = append(cmd, "-p", shell.Quote(conf.Port))
	}

	if conf.Username != "" {
		cmd = append(cmd, "-U", shell.Quote(conf.Username))
	}

	if conf.Password != "" {
		connection.Environment["PGPASSWORD"] = conf.Password
	}

	cmd = append(cmd, shell.Quote(schema))

	switch conf.dumpCompression {
	case "gzip":
		cmd = append(cmd, "| gzip")
	case "bzip2":
		cmd = append(cmd, "| bzip2")
	case "xz":
		cmd = append(cmd, "| xz --compress --stdout")
	}

	return connection.RawShellCommandBuilder(cmd...)
}

func (conf *PostgresCommonOptions) PgDumpAllCommandBuilder() []interface{} {
	connection := conf.connection.Clone()
	cmd := []string{}

	cmd = append(cmd, "pg_dumpall", "-c")

	if conf.Hostname != "" {
		cmd = append(cmd, "-h", shell.Quote(conf.Hostname))
	}

	if conf.Port != "" {
		cmd = append(cmd, "-p", shell.Quote(conf.Port))
	}

	if conf.Username != "" {
		cmd = append(cmd, "-U", shell.Quote(conf.Username))
	}

	if conf.Password != "" {
		connection.Environment["PGPASSWORD"] = conf.Password
	}

	switch conf.dumpCompression {
	case "gzip":
		cmd = append(cmd, "| gzip")
	case "bzip2":
		cmd = append(cmd, "| bzip2")
	case "xz":
		cmd = append(cmd, "| xz --compress --stdout")
	}

	return connection.RawShellCommandBuilder(cmd...)
}

func (conf *PostgresCommonOptions) PostgresRestoreCommandBuilder(args ...string) []interface{} {
	connection := conf.connection.Clone()
	cmd := []string{}

	switch conf.dumpCompression {
	case "gzip":
		cmd = append(cmd, "gzip -dc |")
	case "bzip2":
		cmd = append(cmd, "bzcat |")
	case "xz":
		cmd = append(cmd, "xzcat |")
	}

	cmd = append(cmd, "psql")

	if conf.Hostname != "" {
		cmd = append(cmd, "-h", shell.Quote(conf.Hostname))
	}

	if conf.Port != "" {
		cmd = append(cmd, "-p", shell.Quote(conf.Port))
	}

	if conf.Username != "" {
		cmd = append(cmd, "-U", shell.Quote(conf.Username))
	}

	if conf.Password != "" {
		connection.Environment["PGPASSWORD"] = conf.Password
	}

	if len(args) > 0 {
		cmd = append(cmd, args...)
	}

	return connection.RawShellCommandBuilder(cmd...)
}

func (conf *PostgresCommonOptions) ExecStatement(statement string) string {
	cmd := shell.Cmd(conf.PsqlCommandBuilder("postgres", "-c", shell.Quote(statement))...)
	return cmd.Run().Stdout.String()
}

func  (conf *PostgresCommonOptions) InitDockerSettings() {
	containerName := conf.connection.Docker

	connectionClone := conf.connection.Clone()
	connectionClone.Docker = ""
	connectionClone.Type  = "auto"

	containerId := connectionClone.DockerGetContainerId(containerName)
	fmt.Println(fmt.Sprintf(" - Using docker container \"%s\"", containerId))

	containerEnv := GetDockerEnvList(connectionClone, containerId)

	// get user from env
	if val, ok := containerEnv["POSTGRES_USER"]; ok {
		if conf.Username == "" {
			conf.Username = val
		}
	}

	// get user from env
	if val, ok := containerEnv["POSTGRES_PASSWORD"]; ok {
		if conf.Username == "" {
			conf.Password = val
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2020 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      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 gerrit

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

	"google.golang.org/protobuf/types/known/timestamppb"

	"go.chromium.org/luci/common/errors"
	gerritpb "go.chromium.org/luci/common/proto/gerrit"
)

// This file contains code related to JSON representations of messages that are
// used for requests to the Gerrit REST API, and unmarshalling code to convert
// from the JSON representations to protos defined in `gerritpb`.
//
// Each of these structs corresponds to an entity described at
// https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#json-entities
// and also to a message in `gerritpb`, and each has a unmarshalling method
// called ToProto.

// timestamp implements customized JSON marshal/unmarshal behavior that matches
// the timestamp format used in Gerrit.
type timestamp struct {
	time.Time
}

func (t *timestamp) MarshalJSON() ([]byte, error) {
	return []byte(fmt.Sprintf("\"%s\"", t.Time.UTC().Format(gerritTimestampLayout))), nil
}

func (t *timestamp) UnmarshalJSON(b []byte) error {
	parsedTime, err := time.Parse(gerritTimestampLayout, strings.Trim(string(b), "\""))
	if err != nil {
		return errors.Annotate(err, "parse gerrit timestamp").Err()
	}
	t.Time = parsedTime
	return nil
}

// changeInfo represents JSON for a gerritpb.ChangeInfo on the wire.
type changeInfo struct {
	Number   int64                 `json:"_number"`
	Owner    *gerritpb.AccountInfo `json:"owner"`
	Project  string                `json:"project"`
	Branch   string                `json:"branch"`
	ChangeID string                `json:"change_id"`

	// json.Unmarshal cannot convert enum string to value,
	// so this field is handled specially in ToProto.
	Status string `json:"status"`

	CurrentRevision string                         `json:"current_revision"`
	Revisions       map[string]*revisionInfo       `json:"revisions"`
	Labels          map[string]*gerritpb.LabelInfo `json:"labels"`
	Messages        []changeMessageInfo            `json:"messages"`

	// MoreChanges may be set on the last change in a response to a query for
	// changes, but this is not a property of the change itself and is not
	// needed in gerritpb.ChangeInfo.
	MoreChanges bool `json:"_more_changes"`
}

func (ci *changeInfo) ToProto() *gerritpb.ChangeInfo {
	ret := &gerritpb.ChangeInfo{
		Number:          ci.Number,
		Owner:           ci.Owner,
		Project:         ci.Project,
		Ref:             branchToRef(ci.Branch),
		Status:          gerritpb.ChangeInfo_Status(gerritpb.ChangeInfo_Status_value[ci.Status]),
		CurrentRevision: ci.CurrentRevision,
	}
	if ci.Revisions != nil {
		ret.Revisions = make(map[string]*gerritpb.RevisionInfo, len(ci.Revisions))
		for rev, info := range ci.Revisions {
			ret.Revisions[rev] = info.ToProto()
		}
	}
	if ci.Labels != nil {
		ret.Labels = make(map[string]*gerritpb.LabelInfo, len(ci.Labels))
		for label, info := range ci.Labels {
			ret.Labels[label] = info
		}
	}
	if ci.Messages != nil {
		ret.Messages = make([]*gerritpb.ChangeMessageInfo, len(ci.Messages))
		for i, msg := range ci.Messages {
			ret.Messages[i] = msg.ToProto()
		}
	}
	return ret
}

type changeMessageInfo struct {
	ID         string                `json:"id"`
	Author     *gerritpb.AccountInfo `json:"author"`
	RealAuthor *gerritpb.AccountInfo `json:"real_author"`
	Date       timestamp             `json:"date"`
	Message    string                `json:"message"`
}

func (cmi *changeMessageInfo) ToProto() *gerritpb.ChangeMessageInfo {
	if cmi == nil {
		return nil
	}
	return &gerritpb.ChangeMessageInfo{
		Id:         cmi.ID,
		Author:     cmi.Author,
		RealAuthor: cmi.RealAuthor,
		Date:       timestamppb.New(cmi.Date.Time),
		Message:    cmi.Message,
	}
}

type fileInfo struct {
	LinesInserted int32 `json:"lines_inserted"`
	LinesDeleted  int32 `json:"lines_deleted"`
	SizeDelta     int64 `json:"size_delta"`
	Size          int64 `json:"size"`
}

func (fi *fileInfo) ToProto() *gerritpb.FileInfo {
	return &gerritpb.FileInfo{
		LinesInserted: fi.LinesInserted,
		LinesDeleted:  fi.LinesDeleted,
		SizeDelta:     fi.SizeDelta,
		Size:          fi.Size,
	}
}

type revisionInfo struct {
	Number int                  `json:"_number"`
	Ref    string               `json:"ref"`
	Files  map[string]*fileInfo `json:"files"`
}

func (ri *revisionInfo) ToProto() *gerritpb.RevisionInfo {
	ret := &gerritpb.RevisionInfo{Number: int32(ri.Number), Ref: ri.Ref}
	if ri.Files != nil {
		ret.Files = make(map[string]*gerritpb.FileInfo, len(ri.Files))
		for i, fi := range ri.Files {
			ret.Files[i] = fi.ToProto()
		}
	}
	return ret
}

type mergeableInfo struct {
	SubmitType    string   `json:"submit_type"`
	Strategy      string   `json:"strategy"`
	Mergeable     bool     `json:"mergeable"`
	CommitMerged  bool     `json:"commit_merged"`
	ContentMerged bool     `json:"content_merged"`
	Conflicts     []string `json:"conflicts"`
	MergeableInto []string `json:"mergeable_into"`
}

func (mi *mergeableInfo) ToProto() (*gerritpb.MergeableInfo, error) {
	// Convert something like 'simple-two-way-in-core' to 'SIMPLE_TWO_WAY_IN_CORE'.
	strategyEnumName := strings.Replace(strings.ToUpper(mi.Strategy), "-", "_", -1)
	strategyEnumNum, found := gerritpb.MergeableStrategy_value[strategyEnumName]
	if !found {
		return nil, fmt.Errorf("no MergeableStrategy enum value for %q", strategyEnumName)
	}
	submitTypeEnumNum, found := gerritpb.MergeableInfo_SubmitType_value[mi.SubmitType]
	if !found {
		return nil, fmt.Errorf("no SubmitType enum value for %q", mi.SubmitType)
	}
	return &gerritpb.MergeableInfo{
		SubmitType:    gerritpb.MergeableInfo_SubmitType(submitTypeEnumNum),
		Strategy:      gerritpb.MergeableStrategy(strategyEnumNum),
		Mergeable:     mi.Mergeable,
		CommitMerged:  mi.CommitMerged,
		ContentMerged: mi.ContentMerged,
		Conflicts:     mi.Conflicts,
		MergeableInto: mi.MergeableInto,
	}, nil
}

type addReviewerRequest struct {
	Reviewer  string `json:"reviewer"`
	State     string `json:"state,omitempty"`
	Confirmed bool   `json:"confirmed,omitempty"`
	Notify    string `json:"notify,omitempty"`
}

type reviewerInfo struct {
	Name            string            `json"name,omitempty"`
	Email           string            `json"email,omitempty"`
	SecondaryEmails []string          `json"email,omitempty"`
	Username        string            `json"username,omitempty"`
	Approvals       map[string]string `json:"approvals,omitempty"`
	AccountID       int64             `json:"_account_id,omitempty"`
}

func (ri *reviewerInfo) ToProtoReviewerInfo() (*gerritpb.ReviewerInfo, error) {
	approvals := make(map[string]int32, 0)
	for label, score := range ri.Approvals {
		scoreInt, err := strconv.ParseInt(score, 10, 32)
		if err != nil {
			return nil, errors.Annotate(err, "parsing approvals").Err()
		}
		approvals[label] = int32(scoreInt)
	}
	return &gerritpb.ReviewerInfo{
		Account: &gerritpb.AccountInfo{
			Name:            ri.Name,
			Email:           ri.Email,
			SecondaryEmails: ri.SecondaryEmails,
			Username:        ri.Username,
			AccountId:       ri.AccountID,
		},
		Approvals: approvals,
	}, nil
}

type addReviewerResult struct {
	Input     string         `json:"input"`
	Reviewers []reviewerInfo `json:"reviewers,omitempty"`
	Ccs       []reviewerInfo `json:"ccs,omitempty"`
	Error     string         `json:"error,omitempty"`
	Confirm   bool           `json"confirm,omitempty"`
}

func (rr *addReviewerResult) ToProto() (*gerritpb.AddReviewerResult, error) {
	reviewers := make([]*gerritpb.ReviewerInfo, 0)
	for _, r := range rr.Reviewers {
		rInfo, err := r.ToProtoReviewerInfo()
		if err != nil {
			return nil, errors.Annotate(err, "converting reviewerInfo").Err()
		}
		reviewers = append(reviewers, rInfo)
	}
	ccs := make([]*gerritpb.ReviewerInfo, 0)
	for _, r := range rr.Ccs {
		rInfo, err := r.ToProtoReviewerInfo()
		if err != nil {
			return nil, errors.Annotate(err, "converting reviewerInfo").Err()
		}
		ccs = append(ccs, rInfo)
	}
	return &gerritpb.AddReviewerResult{
		Input:     rr.Input,
		Reviewers: reviewers,
		Ccs:       ccs,
		Error:     rr.Error,
		Confirm:   rr.Confirm,
	}, nil
}

func enumToString(v int32, m map[int32]string) string {
	if v == 0 {
		return ""
	}
	prefixLen := strings.LastIndex(m[0], "UNSPECIFIED")
	return m[v][prefixLen:]
}
<commit_msg>[chrome-cr-owners]: fix bad struct tags<commit_after>// Copyright 2020 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      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 gerrit

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

	"google.golang.org/protobuf/types/known/timestamppb"

	"go.chromium.org/luci/common/errors"
	gerritpb "go.chromium.org/luci/common/proto/gerrit"
)

// This file contains code related to JSON representations of messages that are
// used for requests to the Gerrit REST API, and unmarshalling code to convert
// from the JSON representations to protos defined in `gerritpb`.
//
// Each of these structs corresponds to an entity described at
// https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#json-entities
// and also to a message in `gerritpb`, and each has a unmarshalling method
// called ToProto.

// timestamp implements customized JSON marshal/unmarshal behavior that matches
// the timestamp format used in Gerrit.
type timestamp struct {
	time.Time
}

func (t *timestamp) MarshalJSON() ([]byte, error) {
	return []byte(fmt.Sprintf("\"%s\"", t.Time.UTC().Format(gerritTimestampLayout))), nil
}

func (t *timestamp) UnmarshalJSON(b []byte) error {
	parsedTime, err := time.Parse(gerritTimestampLayout, strings.Trim(string(b), "\""))
	if err != nil {
		return errors.Annotate(err, "parse gerrit timestamp").Err()
	}
	t.Time = parsedTime
	return nil
}

// changeInfo represents JSON for a gerritpb.ChangeInfo on the wire.
type changeInfo struct {
	Number   int64                 `json:"_number"`
	Owner    *gerritpb.AccountInfo `json:"owner"`
	Project  string                `json:"project"`
	Branch   string                `json:"branch"`
	ChangeID string                `json:"change_id"`

	// json.Unmarshal cannot convert enum string to value,
	// so this field is handled specially in ToProto.
	Status string `json:"status"`

	CurrentRevision string                         `json:"current_revision"`
	Revisions       map[string]*revisionInfo       `json:"revisions"`
	Labels          map[string]*gerritpb.LabelInfo `json:"labels"`
	Messages        []changeMessageInfo            `json:"messages"`

	// MoreChanges may be set on the last change in a response to a query for
	// changes, but this is not a property of the change itself and is not
	// needed in gerritpb.ChangeInfo.
	MoreChanges bool `json:"_more_changes"`
}

func (ci *changeInfo) ToProto() *gerritpb.ChangeInfo {
	ret := &gerritpb.ChangeInfo{
		Number:          ci.Number,
		Owner:           ci.Owner,
		Project:         ci.Project,
		Ref:             branchToRef(ci.Branch),
		Status:          gerritpb.ChangeInfo_Status(gerritpb.ChangeInfo_Status_value[ci.Status]),
		CurrentRevision: ci.CurrentRevision,
	}
	if ci.Revisions != nil {
		ret.Revisions = make(map[string]*gerritpb.RevisionInfo, len(ci.Revisions))
		for rev, info := range ci.Revisions {
			ret.Revisions[rev] = info.ToProto()
		}
	}
	if ci.Labels != nil {
		ret.Labels = make(map[string]*gerritpb.LabelInfo, len(ci.Labels))
		for label, info := range ci.Labels {
			ret.Labels[label] = info
		}
	}
	if ci.Messages != nil {
		ret.Messages = make([]*gerritpb.ChangeMessageInfo, len(ci.Messages))
		for i, msg := range ci.Messages {
			ret.Messages[i] = msg.ToProto()
		}
	}
	return ret
}

type changeMessageInfo struct {
	ID         string                `json:"id"`
	Author     *gerritpb.AccountInfo `json:"author"`
	RealAuthor *gerritpb.AccountInfo `json:"real_author"`
	Date       timestamp             `json:"date"`
	Message    string                `json:"message"`
}

func (cmi *changeMessageInfo) ToProto() *gerritpb.ChangeMessageInfo {
	if cmi == nil {
		return nil
	}
	return &gerritpb.ChangeMessageInfo{
		Id:         cmi.ID,
		Author:     cmi.Author,
		RealAuthor: cmi.RealAuthor,
		Date:       timestamppb.New(cmi.Date.Time),
		Message:    cmi.Message,
	}
}

type fileInfo struct {
	LinesInserted int32 `json:"lines_inserted"`
	LinesDeleted  int32 `json:"lines_deleted"`
	SizeDelta     int64 `json:"size_delta"`
	Size          int64 `json:"size"`
}

func (fi *fileInfo) ToProto() *gerritpb.FileInfo {
	return &gerritpb.FileInfo{
		LinesInserted: fi.LinesInserted,
		LinesDeleted:  fi.LinesDeleted,
		SizeDelta:     fi.SizeDelta,
		Size:          fi.Size,
	}
}

type revisionInfo struct {
	Number int                  `json:"_number"`
	Ref    string               `json:"ref"`
	Files  map[string]*fileInfo `json:"files"`
}

func (ri *revisionInfo) ToProto() *gerritpb.RevisionInfo {
	ret := &gerritpb.RevisionInfo{Number: int32(ri.Number), Ref: ri.Ref}
	if ri.Files != nil {
		ret.Files = make(map[string]*gerritpb.FileInfo, len(ri.Files))
		for i, fi := range ri.Files {
			ret.Files[i] = fi.ToProto()
		}
	}
	return ret
}

type mergeableInfo struct {
	SubmitType    string   `json:"submit_type"`
	Strategy      string   `json:"strategy"`
	Mergeable     bool     `json:"mergeable"`
	CommitMerged  bool     `json:"commit_merged"`
	ContentMerged bool     `json:"content_merged"`
	Conflicts     []string `json:"conflicts"`
	MergeableInto []string `json:"mergeable_into"`
}

func (mi *mergeableInfo) ToProto() (*gerritpb.MergeableInfo, error) {
	// Convert something like 'simple-two-way-in-core' to 'SIMPLE_TWO_WAY_IN_CORE'.
	strategyEnumName := strings.Replace(strings.ToUpper(mi.Strategy), "-", "_", -1)
	strategyEnumNum, found := gerritpb.MergeableStrategy_value[strategyEnumName]
	if !found {
		return nil, fmt.Errorf("no MergeableStrategy enum value for %q", strategyEnumName)
	}
	submitTypeEnumNum, found := gerritpb.MergeableInfo_SubmitType_value[mi.SubmitType]
	if !found {
		return nil, fmt.Errorf("no SubmitType enum value for %q", mi.SubmitType)
	}
	return &gerritpb.MergeableInfo{
		SubmitType:    gerritpb.MergeableInfo_SubmitType(submitTypeEnumNum),
		Strategy:      gerritpb.MergeableStrategy(strategyEnumNum),
		Mergeable:     mi.Mergeable,
		CommitMerged:  mi.CommitMerged,
		ContentMerged: mi.ContentMerged,
		Conflicts:     mi.Conflicts,
		MergeableInto: mi.MergeableInto,
	}, nil
}

type addReviewerRequest struct {
	Reviewer  string `json:"reviewer"`
	State     string `json:"state,omitempty"`
	Confirmed bool   `json:"confirmed,omitempty"`
	Notify    string `json:"notify,omitempty"`
}

type reviewerInfo struct {
	Name            string            `json:"name,omitempty"`
	Email           string            `json:"email,omitempty"`
	SecondaryEmails []string          `json:"secondary_emails,omitempty"`
	Username        string            `json:"username,omitempty"`
	Approvals       map[string]string `json:"approvals,omitempty"`
	AccountID       int64             `json:"_account_id,omitempty"`
}

func (ri *reviewerInfo) ToProtoReviewerInfo() (*gerritpb.ReviewerInfo, error) {
	approvals := make(map[string]int32, 0)
	for label, score := range ri.Approvals {
		scoreInt, err := strconv.ParseInt(score, 10, 32)
		if err != nil {
			return nil, errors.Annotate(err, "parsing approvals").Err()
		}
		approvals[label] = int32(scoreInt)
	}
	return &gerritpb.ReviewerInfo{
		Account: &gerritpb.AccountInfo{
			Name:            ri.Name,
			Email:           ri.Email,
			SecondaryEmails: ri.SecondaryEmails,
			Username:        ri.Username,
			AccountId:       ri.AccountID,
		},
		Approvals: approvals,
	}, nil
}

type addReviewerResult struct {
	Input     string         `json:"input"`
	Reviewers []reviewerInfo `json:"reviewers,omitempty"`
	Ccs       []reviewerInfo `json:"ccs,omitempty"`
	Error     string         `json:"error,omitempty"`
	Confirm   bool           `json:"confirm,omitempty"`
}

func (rr *addReviewerResult) ToProto() (*gerritpb.AddReviewerResult, error) {
	reviewers := make([]*gerritpb.ReviewerInfo, 0)
	for _, r := range rr.Reviewers {
		rInfo, err := r.ToProtoReviewerInfo()
		if err != nil {
			return nil, errors.Annotate(err, "converting reviewerInfo").Err()
		}
		reviewers = append(reviewers, rInfo)
	}
	ccs := make([]*gerritpb.ReviewerInfo, 0)
	for _, r := range rr.Ccs {
		rInfo, err := r.ToProtoReviewerInfo()
		if err != nil {
			return nil, errors.Annotate(err, "converting reviewerInfo").Err()
		}
		ccs = append(ccs, rInfo)
	}
	return &gerritpb.AddReviewerResult{
		Input:     rr.Input,
		Reviewers: reviewers,
		Ccs:       ccs,
		Error:     rr.Error,
		Confirm:   rr.Confirm,
	}, nil
}

func enumToString(v int32, m map[int32]string) string {
	if v == 0 {
		return ""
	}
	prefixLen := strings.LastIndex(m[0], "UNSPECIFIED")
	return m[v][prefixLen:]
}
<|endoftext|>


<commit_before>package fsevents

/*
#cgo LDFLAGS: -framework CoreServices
#include <CoreServices/CoreServices.h>
#include <sys/stat.h>

static CFArrayRef ArrayCreateMutable(int len) {
	return CFArrayCreateMutable(NULL, len, &kCFTypeArrayCallBacks);
}

extern void fsevtCallback(FSEventStreamRef p0, void * info, size_t p1, char** p2, FSEventStreamEventFlags* p3, FSEventStreamEventId* p4);

static FSEventStreamRef EventStreamCreateRelativeToDevice(FSEventStreamContext * context, dev_t dev, CFArrayRef paths, FSEventStreamEventId since, CFTimeInterval latency, FSEventStreamCreateFlags flags) {
	return FSEventStreamCreateRelativeToDevice(NULL, (FSEventStreamCallback) fsevtCallback, context, dev, paths, since, latency, flags);
}

static FSEventStreamRef EventStreamCreate(FSEventStreamContext * context, CFArrayRef paths, FSEventStreamEventId since, CFTimeInterval latency, FSEventStreamCreateFlags flags) {
	return FSEventStreamCreate(NULL, (FSEventStreamCallback) fsevtCallback, context, paths, since, latency, flags);
}
*/
import "C"
import "unsafe"
import "path/filepath"

// CreateFlags for creating a New stream.
type CreateFlags uint32

// kFSEventStreamCreateFlag...
const (
	// use CoreFoundation types instead of raw C types (disabled)
	useCFTypes CreateFlags = 1 << iota

	// NoDefer sends events on the leading edge (for interactive applications).
	// By default events are delivered after latency seconds (for background tasks).
	NoDefer

	// WatchRoot for a change to occur to a directory along the path being watched.
	WatchRoot

	// IgnoreSelf doesn't send events triggered by the current process (OS X 10.6+).
	IgnoreSelf

	// FileEvents sends events about individual files, generating significantly
	// more events (OS X 10.7+) than directory level notifications.
	FileEvents
)

// EventFlags passed to the FSEventStreamCallback function.
type EventFlags uint32

// kFSEventStreamEventFlag...
const (
	// MustScanSubDirs indicates that events were coalesced hierarchically.
	MustScanSubDirs EventFlags = 1 << iota
	// UserDropped or KernelDropped is set alongside MustScanSubDirs
	// to help diagnose the problem.
	UserDropped
	KernelDropped

	// EventIdsWrapped indicates the 64-bit event ID counter wrapped around.
	EventIdsWrapped

	// HistoryDone is a sentinel event when retrieving events sinceWhen.
	HistoryDone

	// RootChanged indicates a change to a directory along the path being watched.
	RootChanged

	// Mount for a volume mounted underneath the path being monitored.
	Mount
	// Unmount event occurs after a volume is unmounted.
	Unmount

	// The following flags are only set when using FileEvents.

	ItemCreated
	ItemRemoved
	ItemInodeMetaMod
	ItemRenamed
	ItemModified
	ItemFinderInfoMod
	ItemChangeOwner
	ItemXattrMod
	ItemIsFile
	ItemIsDir
	ItemIsSymlink
)

type FSEvent struct {
	Path  string
	Flags EventFlags
	Id    uint64
}

//export fsevtCallback
func fsevtCallback(stream C.FSEventStreamRef, info unsafe.Pointer, numEvents C.size_t, paths **C.char, flags *C.FSEventStreamEventFlags, ids *C.FSEventStreamEventId) {
	events := make([]FSEvent, int(numEvents))

	for i := 0; i < int(numEvents); i++ {
		cpaths := uintptr(unsafe.Pointer(paths)) + (uintptr(i) * unsafe.Sizeof(*paths))
		cpath := *(**C.char)(unsafe.Pointer(cpaths))

		cflags := uintptr(unsafe.Pointer(flags)) + (uintptr(i) * unsafe.Sizeof(*flags))
		cflag := *(*C.FSEventStreamEventFlags)(unsafe.Pointer(cflags))

		cids := uintptr(unsafe.Pointer(ids)) + (uintptr(i) * unsafe.Sizeof(*ids))
		cid := *(*C.FSEventStreamEventId)(unsafe.Pointer(cids))

		events[i] = FSEvent{Path: C.GoString(cpath), Flags: EventFlags(cflag), Id: uint64(cid)}
	}

	evtC := *(*chan []FSEvent)(info)
	evtC <- events
}

/*
	extern FSEventStreamRef FSEventStreamCreate(
		CFAllocatorRef allocator,
		FSEventStreamCallback callback,
		FSEventStreamContext *context,
		CFArrayRef pathsToWatch,
		FSEventStreamEventId sinceWhen,
		CFTimeInterval latency,
		FSEventStreamCreateFlags flags);

	typedef void ( *FSEventStreamCallback )(
		ConstFSEventStreamRef streamRef,
		void *clientCallBackInfo,
		size_t numEvents,
		void *eventPaths,
		const FSEventStreamEventFlags eventFlags[],
		const FSEventStreamEventId eventIds[]);
*/

func FSEventsLatestId() uint64 {
	return uint64(C.FSEventsGetCurrentEventId())
}

func DeviceForPath(pth string) int64 {
	cStat := C.struct_stat{}
	cPath := C.CString(pth)
	defer C.free(unsafe.Pointer(cPath))

	_ = C.lstat(cPath, &cStat)
	return int64(cStat.st_dev)
}

func GetIdForDeviceBeforeTime(dev, tm int64) uint64 {
	return uint64(C.FSEventsGetLastEventIdForDeviceBeforeTime(C.dev_t(dev), C.CFAbsoluteTime(tm)))
}

func FSEventsSince(paths []string, dev int64, since uint64) []FSEvent {
	cPaths := C.ArrayCreateMutable(C.int(len(paths)))
	defer C.CFRelease(C.CFTypeRef(cPaths))

	for _, p := range paths {
		p, _ = filepath.Abs(p)
		cpath := C.CString(p)
		defer C.free(unsafe.Pointer(cpath))

		str := C.CFStringCreateWithCString(nil, cpath, C.kCFStringEncodingUTF8)
		C.CFArrayAppendValue(cPaths, unsafe.Pointer(str))
	}

	if since == 0 {
		/* If since == 0 is passed to FSEventStreamCreate it will mean 'since the beginning of time'.
		We remap to 'now'. */
		since = C.kFSEventStreamEventIdSinceNow + (1 << 64)
	}

	evtC := make(chan []FSEvent)
	context := C.FSEventStreamContext{info: unsafe.Pointer(&evtC)}

	latency := C.CFTimeInterval(1.0)
	var stream C.FSEventStreamRef
	if dev != 0 {
		stream = C.EventStreamCreateRelativeToDevice(&context, C.dev_t(dev), cPaths, C.FSEventStreamEventId(since), latency, 0)
	} else {
		stream = C.EventStreamCreate(&context, cPaths, C.FSEventStreamEventId(since), latency, 0)
	}

	rlref := C.CFRunLoopGetCurrent()

	go func() {
		/* Schedule the stream on the runloop, then run the runloop concurrently with starting/flushing/stopping the stream */
		C.FSEventStreamScheduleWithRunLoop(stream, rlref, C.kCFRunLoopDefaultMode)
		go func() {
			C.CFRunLoopRun()
		}()
		C.FSEventStreamStart(stream)
		C.FSEventStreamFlushSync(stream)
		C.FSEventStreamStop(stream)
		C.FSEventStreamInvalidate(stream)
		C.FSEventStreamRelease(stream)
		C.CFRunLoopStop(rlref)
		close(evtC)
	}()

	var events []FSEvent
	for evts := range evtC {
		events = append(events, evts...)
	}

	return events
}

type FSEventStream struct {
	stream C.FSEventStreamRef
	rlref  C.CFRunLoopRef
	C      chan []FSEvent
}

func NewEventStream(paths []string, since uint64, flags CreateFlags) *FSEventStream {
	cPaths := C.ArrayCreateMutable(C.int(len(paths)))
	defer C.CFRelease(C.CFTypeRef(cPaths))

	for _, p := range paths {
		p, _ = filepath.Abs(p)
		cpath := C.CString(p)
		defer C.free(unsafe.Pointer(cpath))

		str := C.CFStringCreateWithCString(nil, cpath, C.kCFStringEncodingUTF8)
		C.CFArrayAppendValue(cPaths, unsafe.Pointer(str))
	}

	if since == 0 {
		/* If since == 0 is passed to FSEventStreamCreate it will mean 'since the beginning of time'.
		We remap to 'now'. */
		since = C.kFSEventStreamEventIdSinceNow + (1 << 64)
	}

	es := FSEventStream{C: make(chan []FSEvent)}
	context := C.FSEventStreamContext{info: unsafe.Pointer(&es.C)}

	latency := C.CFTimeInterval(1.0)
	es.stream = C.EventStreamCreate(&context, cPaths, C.FSEventStreamEventId(since), latency, C.FSEventStreamCreateFlags(flags))

	loopC := make(chan unsafe.Pointer)
	go func() {
		rlref := C.CFRunLoopGetCurrent()
		C.FSEventStreamScheduleWithRunLoop(es.stream, rlref, C.kCFRunLoopDefaultMode)
		loopC <- unsafe.Pointer(rlref)
		C.CFRunLoopRun()
	}()

	es.rlref = C.CFRunLoopRef(<-loopC)
	C.FSEventStreamStart(es.stream)

	return &es
}

func (es *FSEventStream) Flush() {
	C.FSEventStreamFlushSync(es.stream)
}

func (es *FSEventStream) Stop() {
	C.FSEventStreamStop(es.stream)
	C.FSEventStreamInvalidate(es.stream)
	C.FSEventStreamRelease(es.stream)
	C.CFRunLoopStop(es.rlref)
	close(es.C)
}
<commit_msg>simplify creating of runloop<commit_after>package fsevents

/*
#cgo LDFLAGS: -framework CoreServices
#include <CoreServices/CoreServices.h>
#include <sys/stat.h>

static CFArrayRef ArrayCreateMutable(int len) {
	return CFArrayCreateMutable(NULL, len, &kCFTypeArrayCallBacks);
}

extern void fsevtCallback(FSEventStreamRef p0, void * info, size_t p1, char** p2, FSEventStreamEventFlags* p3, FSEventStreamEventId* p4);

static FSEventStreamRef EventStreamCreateRelativeToDevice(FSEventStreamContext * context, dev_t dev, CFArrayRef paths, FSEventStreamEventId since, CFTimeInterval latency, FSEventStreamCreateFlags flags) {
	return FSEventStreamCreateRelativeToDevice(NULL, (FSEventStreamCallback) fsevtCallback, context, dev, paths, since, latency, flags);
}

static FSEventStreamRef EventStreamCreate(FSEventStreamContext * context, CFArrayRef paths, FSEventStreamEventId since, CFTimeInterval latency, FSEventStreamCreateFlags flags) {
	return FSEventStreamCreate(NULL, (FSEventStreamCallback) fsevtCallback, context, paths, since, latency, flags);
}
*/
import "C"
import "unsafe"
import "path/filepath"

// CreateFlags for creating a New stream.
type CreateFlags uint32

// kFSEventStreamCreateFlag...
const (
	// use CoreFoundation types instead of raw C types (disabled)
	useCFTypes CreateFlags = 1 << iota

	// NoDefer sends events on the leading edge (for interactive applications).
	// By default events are delivered after latency seconds (for background tasks).
	NoDefer

	// WatchRoot for a change to occur to a directory along the path being watched.
	WatchRoot

	// IgnoreSelf doesn't send events triggered by the current process (OS X 10.6+).
	IgnoreSelf

	// FileEvents sends events about individual files, generating significantly
	// more events (OS X 10.7+) than directory level notifications.
	FileEvents
)

// EventFlags passed to the FSEventStreamCallback function.
type EventFlags uint32

// kFSEventStreamEventFlag...
const (
	// MustScanSubDirs indicates that events were coalesced hierarchically.
	MustScanSubDirs EventFlags = 1 << iota
	// UserDropped or KernelDropped is set alongside MustScanSubDirs
	// to help diagnose the problem.
	UserDropped
	KernelDropped

	// EventIdsWrapped indicates the 64-bit event ID counter wrapped around.
	EventIdsWrapped

	// HistoryDone is a sentinel event when retrieving events sinceWhen.
	HistoryDone

	// RootChanged indicates a change to a directory along the path being watched.
	RootChanged

	// Mount for a volume mounted underneath the path being monitored.
	Mount
	// Unmount event occurs after a volume is unmounted.
	Unmount

	// The following flags are only set when using FileEvents.

	ItemCreated
	ItemRemoved
	ItemInodeMetaMod
	ItemRenamed
	ItemModified
	ItemFinderInfoMod
	ItemChangeOwner
	ItemXattrMod
	ItemIsFile
	ItemIsDir
	ItemIsSymlink
)

type FSEvent struct {
	Path  string
	Flags EventFlags
	Id    uint64
}

//export fsevtCallback
func fsevtCallback(stream C.FSEventStreamRef, info unsafe.Pointer, numEvents C.size_t, paths **C.char, flags *C.FSEventStreamEventFlags, ids *C.FSEventStreamEventId) {
	events := make([]FSEvent, int(numEvents))

	for i := 0; i < int(numEvents); i++ {
		cpaths := uintptr(unsafe.Pointer(paths)) + (uintptr(i) * unsafe.Sizeof(*paths))
		cpath := *(**C.char)(unsafe.Pointer(cpaths))

		cflags := uintptr(unsafe.Pointer(flags)) + (uintptr(i) * unsafe.Sizeof(*flags))
		cflag := *(*C.FSEventStreamEventFlags)(unsafe.Pointer(cflags))

		cids := uintptr(unsafe.Pointer(ids)) + (uintptr(i) * unsafe.Sizeof(*ids))
		cid := *(*C.FSEventStreamEventId)(unsafe.Pointer(cids))

		events[i] = FSEvent{Path: C.GoString(cpath), Flags: EventFlags(cflag), Id: uint64(cid)}
	}

	evtC := *(*chan []FSEvent)(info)
	evtC <- events
}

/*
	extern FSEventStreamRef FSEventStreamCreate(
		CFAllocatorRef allocator,
		FSEventStreamCallback callback,
		FSEventStreamContext *context,
		CFArrayRef pathsToWatch,
		FSEventStreamEventId sinceWhen,
		CFTimeInterval latency,
		FSEventStreamCreateFlags flags);

	typedef void ( *FSEventStreamCallback )(
		ConstFSEventStreamRef streamRef,
		void *clientCallBackInfo,
		size_t numEvents,
		void *eventPaths,
		const FSEventStreamEventFlags eventFlags[],
		const FSEventStreamEventId eventIds[]);
*/

func FSEventsLatestId() uint64 {
	return uint64(C.FSEventsGetCurrentEventId())
}

func DeviceForPath(pth string) int64 {
	cStat := C.struct_stat{}
	cPath := C.CString(pth)
	defer C.free(unsafe.Pointer(cPath))

	_ = C.lstat(cPath, &cStat)
	return int64(cStat.st_dev)
}

func GetIdForDeviceBeforeTime(dev, tm int64) uint64 {
	return uint64(C.FSEventsGetLastEventIdForDeviceBeforeTime(C.dev_t(dev), C.CFAbsoluteTime(tm)))
}

func FSEventsSince(paths []string, dev int64, since uint64) []FSEvent {
	cPaths := C.ArrayCreateMutable(C.int(len(paths)))
	defer C.CFRelease(C.CFTypeRef(cPaths))

	for _, p := range paths {
		p, _ = filepath.Abs(p)
		cpath := C.CString(p)
		defer C.free(unsafe.Pointer(cpath))

		str := C.CFStringCreateWithCString(nil, cpath, C.kCFStringEncodingUTF8)
		C.CFArrayAppendValue(cPaths, unsafe.Pointer(str))
	}

	if since == 0 {
		/* If since == 0 is passed to FSEventStreamCreate it will mean 'since the beginning of time'.
		We remap to 'now'. */
		since = C.kFSEventStreamEventIdSinceNow + (1 << 64)
	}

	evtC := make(chan []FSEvent)
	context := C.FSEventStreamContext{info: unsafe.Pointer(&evtC)}

	latency := C.CFTimeInterval(1.0)
	var stream C.FSEventStreamRef
	if dev != 0 {
		stream = C.EventStreamCreateRelativeToDevice(&context, C.dev_t(dev), cPaths, C.FSEventStreamEventId(since), latency, 0)
	} else {
		stream = C.EventStreamCreate(&context, cPaths, C.FSEventStreamEventId(since), latency, 0)
	}

	rlref := C.CFRunLoopGetCurrent()

	go func() {
		/* Schedule the stream on the runloop, then run the runloop concurrently with starting/flushing/stopping the stream */
		C.FSEventStreamScheduleWithRunLoop(stream, rlref, C.kCFRunLoopDefaultMode)
		go func() {
			C.CFRunLoopRun()
		}()
		C.FSEventStreamStart(stream)
		C.FSEventStreamFlushSync(stream)
		C.FSEventStreamStop(stream)
		C.FSEventStreamInvalidate(stream)
		C.FSEventStreamRelease(stream)
		C.CFRunLoopStop(rlref)
		close(evtC)
	}()

	var events []FSEvent
	for evts := range evtC {
		events = append(events, evts...)
	}

	return events
}

type FSEventStream struct {
	stream C.FSEventStreamRef
	rlref  C.CFRunLoopRef
	C      chan []FSEvent
}

func NewEventStream(paths []string, since uint64, flags CreateFlags) *FSEventStream {
	cPaths := C.ArrayCreateMutable(C.int(len(paths)))
	defer C.CFRelease(C.CFTypeRef(cPaths))

	for _, p := range paths {
		p, _ = filepath.Abs(p)
		cpath := C.CString(p)
		defer C.free(unsafe.Pointer(cpath))

		str := C.CFStringCreateWithCString(nil, cpath, C.kCFStringEncodingUTF8)
		C.CFArrayAppendValue(cPaths, unsafe.Pointer(str))
	}

	if since == 0 {
		/* If since == 0 is passed to FSEventStreamCreate it will mean 'since the beginning of time'.
		We remap to 'now'. */
		since = C.kFSEventStreamEventIdSinceNow + (1 << 64)
	}

	es := FSEventStream{C: make(chan []FSEvent)}
	context := C.FSEventStreamContext{info: unsafe.Pointer(&es.C)}

	latency := C.CFTimeInterval(1.0)
	es.stream = C.EventStreamCreate(&context, cPaths, C.FSEventStreamEventId(since), latency, C.FSEventStreamCreateFlags(flags))

	go func() {
		es.rlref = C.CFRunLoopGetCurrent()
		C.FSEventStreamScheduleWithRunLoop(es.stream, es.rlref, C.kCFRunLoopDefaultMode)
		C.FSEventStreamStart(es.stream)
		C.CFRunLoopRun()
	}()

	return &es
}

func (es *FSEventStream) Flush() {
	C.FSEventStreamFlushSync(es.stream)
}

func (es *FSEventStream) Stop() {
	C.FSEventStreamStop(es.stream)
	C.FSEventStreamInvalidate(es.stream)
	C.FSEventStreamRelease(es.stream)
	C.CFRunLoopStop(es.rlref)
	close(es.C)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math/rand"
	"os"
	"strconv"
)

func main() {
	if len(os.Args) != 2 {
		fmt.Println("请添加实验重复次数T")
		os.Exit(1)
	}

	t, err := strconv.Atoi(os.Args[1])
	if err != nil || t <= 0 {
		fmt.Println("无法把T转换为正整数：", err)
	}

	ns := []int{1e3, 1e4, 1e5, 1e6}

	for _, n := range ns {
		count := 0.
		for i := 0; i < t; i++ {
			sA := makeInts(n)
			sB := makeInts(n)
			for _, v := range sB {
				if rank(v, sA) != -1 {
					count++
				}
			}
		}
		fmt.Printf("======%d======\n", n)
		fmt.Println(count / float64(t))
	}
}

func makeInts(n int) []int {
	result := make([]int, n)
	for i := range result {
		result[i] = rand.Intn(1000000)
	}
	return result
}

func rank(key int, a []int) int {
	return rankRecur(key, a, 0, len(a)-1)
}

func rankRecur(key int, a []int, lo, hi int) int {
	if lo > hi {
		return -1
	}
	mid := (lo + hi) / 2
	switch {
	case a[mid] > key:
		return rankRecur(key, a, lo, mid-1)
	case a[mid] < key:
		return rankRecur(key, a, mid+1, hi)
	default:
		return mid
	}
}
<commit_msg>修改了1.1.39程序中的一个错误。<commit_after>package main

import (
	"fmt"
	"math/rand"
	"os"
	"sort"
	"strconv"
)

func main() {
	if len(os.Args) != 2 {
		fmt.Println("请添加实验重复次数T")
		os.Exit(1)
	}

	t, err := strconv.Atoi(os.Args[1])
	if err != nil || t <= 0 {
		fmt.Println("无法把T转换为正整数：", err)
	}

	ns := []int{1e3, 1e4, 1e5, 1e6}

	for _, n := range ns {
		count := 0.
		for i := 0; i < t; i++ {
			sA := makeInts(n)
			sort.Ints(sA)
			sB := makeInts(n)
			for _, v := range sB {
				if rank(v, sA) != -1 {
					count++
				}
			}
		}
		fmt.Printf("======%d======\n", n)
		fmt.Println(count / float64(t))
	}
}

func makeInts(n int) []int {
	result := make([]int, n)
	for i := range result {
		result[i] = rand.Intn(1000000)
	}
	return result
}

func rank(key int, a []int) int {
	return rankRecur(key, a, 0, len(a)-1)
}

func rankRecur(key int, a []int, lo, hi int) int {
	if lo > hi {
		return -1
	}
	mid := (lo + hi) / 2
	switch {
	case a[mid] > key:
		return rankRecur(key, a, lo, mid-1)
	case a[mid] < key:
		return rankRecur(key, a, mid+1, hi)
	default:
		return mid
	}
}
<|endoftext|>


<commit_before>package vitali

import (
    "testing"
    "net/http"
    "net/url"
    "net/http/httptest"
)

type Provider struct {
    Ctx
    Provides `GET:"application/json,text/html"`
    Views `GET:"provider_test.html"`
}

type ProviderModel struct {
    Foo string `json:"foo"`
}

func (c *Provider) Get() interface{} {
    return ProviderModel{"bar"}
}

func TestProviderJson(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/provider",
        },
        Header: make(http.Header),
    }
    r.Header.Set("Accept", "application/json")

    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/provider", Provider{}},
    })
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusOK {
        t.Errorf("response code is %d", rr.Code)
    }
    entity := rr.Body.String()
    if entity != `{"foo":"bar"}` {
        t.Errorf("entity is `%s`", entity)
    }
    vary := rr.Header().Get("Vary")
    if vary != "Accept" {
        t.Errorf("vary header is: %s", vary)
    }
}

func TestProviderEmptyAccept(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/provider",
        },
        Header: make(http.Header),
    }

    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/provider", Provider{}},
    })
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusOK {
        t.Errorf("response code is %d", rr.Code)
    }
    entity := rr.Body.String()
    if entity != `{"foo":"bar"}` {
        t.Errorf("entity is `%s`", entity)
    }
    vary := rr.Header().Get("Vary")
    if vary != "Accept" {
        t.Errorf("vary header is: %s", vary)
    }
}

func TestProviderAcceptAll(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/provider",
        },
        Header: make(http.Header),
    }
    r.Header.Set("Accept", "*/*")

    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/provider", Provider{}},
    })
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusOK {
        t.Errorf("response code is %d", rr.Code)
    }
    entity := rr.Body.String()
    if entity != `{"foo":"bar"}` {
        t.Errorf("entity is `%s`", entity)
    }
    vary := rr.Header().Get("Vary")
    if vary != "Accept" {
        t.Errorf("vary header is: %s", vary)
    }
}

func TestProviderPartial(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/provider",
        },
        Header: make(http.Header),
    }
    r.Header.Set("Accept", "text/*")

    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/provider", Provider{}},
    })
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusOK {
        t.Errorf("response code is %d", rr.Code)
    }
    entity := rr.Body.String()
    if entity != "foobar\n" {
        t.Errorf("entity is `%s`", entity)
    }
    vary := rr.Header().Get("Vary")
    if vary != "Accept" {
        t.Errorf("vary header is: %s", vary)
    }
}

func TestProviderQ(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/provider",
        },
        Header: make(http.Header),
    }
    r.Header.Set("Accept", "text/*; q=0.8, application/json; q=0.9")

    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/provider", Provider{}},
    })
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusOK {
        t.Errorf("response code is %d", rr.Code)
    }
    entity := rr.Body.String()
    if entity != `{"foo":"bar"}` {
        t.Errorf("entity is `%s`", entity)
    }
    vary := rr.Header().Get("Vary")
    if vary != "Accept" {
        t.Errorf("vary header is: %s", vary)
    }
}

func TestNotAcceptable(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/provider",
        },
        Header: make(http.Header),
    }
    r.Header.Set("Accept", "application/xml")

    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/provider", Provider{}},
    })
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusNotAcceptable {
        t.Errorf("response code is %d", rr.Code)
    }
    vary := rr.Header().Get("Vary")
    if vary != "Accept" {
        t.Errorf("vary header is: %s", vary)
    }
}
<commit_msg>add error message body test<commit_after>package vitali

import (
    "testing"
    "net/http"
    "net/url"
    "net/http/httptest"
)

type Provider struct {
    Ctx
    Provides `GET:"application/json,text/html"`
    Views `GET:"provider_test.html"`
}

type ProviderModel struct {
    Foo string `json:"foo"`
}

func (c *Provider) Get() interface{} {
    return ProviderModel{"bar"}
}

func TestProviderJson(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/provider",
        },
        Header: make(http.Header),
    }
    r.Header.Set("Accept", "application/json")

    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/provider", Provider{}},
    })
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusOK {
        t.Errorf("response code is %d", rr.Code)
    }
    entity := rr.Body.String()
    if entity != `{"foo":"bar"}` {
        t.Errorf("entity is `%s`", entity)
    }
    vary := rr.Header().Get("Vary")
    if vary != "Accept" {
        t.Errorf("vary header is: %s", vary)
    }
}

func TestProviderEmptyAccept(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/provider",
        },
        Header: make(http.Header),
    }

    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/provider", Provider{}},
    })
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusOK {
        t.Errorf("response code is %d", rr.Code)
    }
    entity := rr.Body.String()
    if entity != `{"foo":"bar"}` {
        t.Errorf("entity is `%s`", entity)
    }
    vary := rr.Header().Get("Vary")
    if vary != "Accept" {
        t.Errorf("vary header is: %s", vary)
    }
}

func TestProviderAcceptAll(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/provider",
        },
        Header: make(http.Header),
    }
    r.Header.Set("Accept", "*/*")

    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/provider", Provider{}},
    })
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusOK {
        t.Errorf("response code is %d", rr.Code)
    }
    entity := rr.Body.String()
    if entity != `{"foo":"bar"}` {
        t.Errorf("entity is `%s`", entity)
    }
    vary := rr.Header().Get("Vary")
    if vary != "Accept" {
        t.Errorf("vary header is: %s", vary)
    }
}

func TestProviderPartial(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/provider",
        },
        Header: make(http.Header),
    }
    r.Header.Set("Accept", "text/*")

    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/provider", Provider{}},
    })
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusOK {
        t.Errorf("response code is %d", rr.Code)
    }
    entity := rr.Body.String()
    if entity != "foobar\n" {
        t.Errorf("entity is `%s`", entity)
    }
    vary := rr.Header().Get("Vary")
    if vary != "Accept" {
        t.Errorf("vary header is: %s", vary)
    }
}

func TestProviderQ(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/provider",
        },
        Header: make(http.Header),
    }
    r.Header.Set("Accept", "text/*; q=0.8, application/json; q=0.9")

    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/provider", Provider{}},
    })
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusOK {
        t.Errorf("response code is %d", rr.Code)
    }
    entity := rr.Body.String()
    if entity != `{"foo":"bar"}` {
        t.Errorf("entity is `%s`", entity)
    }
    vary := rr.Header().Get("Vary")
    if vary != "Accept" {
        t.Errorf("vary header is: %s", vary)
    }
}

func TestNotAcceptable(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/provider",
        },
        Header: make(http.Header),
    }
    r.Header.Set("Accept", "application/xml")

    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/provider", Provider{}},
    })
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusNotAcceptable {
        t.Errorf("response code is %d", rr.Code)
    }
    vary := rr.Header().Get("Vary")
    if vary != "Accept" {
        t.Errorf("vary header is: %s", vary)
    }
}

type ReturnNotFound struct {
    Ctx
    Provides `GET:"application/json"`
}

type ErrBody struct {
    Code int `json:"code"`
    Reason string `json:"reason"`
}

func (c *ReturnNotFound) Get() interface{} {
    return c.NotFound(ErrBody{666, "deadbeef"})
}

func Test4xxErrBody(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/notfound",
        },
        Header: make(http.Header),
    }
    r.Header.Set("Accept", "application/json")

    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/notfound", ReturnNotFound{}},
    })
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusNotFound {
        t.Errorf("response code is %d", rr.Code)
    }

    entity := rr.Body.String()
    if entity != "{\"code\":666,\"reason\":\"deadbeef\"}" {
        t.Errorf("body is %s", entity)
    }
}
<|endoftext|>