<commit_before>package azure

import (
	"context"
	"fmt"
	"io"
	"net/http"
	"strconv"
	"strings"

	"github.com/docker/api/context/cloud"
	"github.com/docker/api/errdefs"

	"github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2018-10-01/containerinstance"
	"github.com/compose-spec/compose-go/types"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"

	"github.com/docker/api/azure/convert"
	"github.com/docker/api/azure/login"
	"github.com/docker/api/backend"
	"github.com/docker/api/compose"
	"github.com/docker/api/containers"
	apicontext "github.com/docker/api/context"
	"github.com/docker/api/context/store"
)

const singleContainerName = "single--container--aci"

// ErrNoSuchContainer is returned when the mentioned container does not exist
var ErrNoSuchContainer = errors.New("no such container")

func init() {
	backend.Register("aci", "aci", func(ctx context.Context) (backend.Service, error) {
		return New(ctx)
	})
}

func getter() interface{} {
	return &store.AciContext{}
}

// New creates a backend that can manage containers
func New(ctx context.Context) (backend.Service, error) {
	currentContext := apicontext.CurrentContext(ctx)
	contextStore, err := store.New()
	if err != nil {
		return nil, err
	}
	metadata, err := contextStore.Get(currentContext, getter)
	if err != nil {
		return nil, errors.Wrap(err, "wrong context type")
	}
	aciContext, _ := metadata.Metadata.Data.(store.AciContext)

	auth, _ := login.NewAuthorizerFromLogin()
	containerGroupsClient := containerinstance.NewContainerGroupsClient(aciContext.SubscriptionID)
	containerGroupsClient.Authorizer = auth

	return getAciAPIService(containerGroupsClient, aciContext)
}

func getAciAPIService(cgc containerinstance.ContainerGroupsClient, aciCtx store.AciContext) (*aciAPIService, error) {
	service, err := login.NewAzureLoginService()
	if err != nil {
		return nil, err
	}
	return &aciAPIService{
		aciContainerService: aciContainerService{
			containerGroupsClient: cgc,
			ctx:                   aciCtx,
		},
		aciComposeService: aciComposeService{
			ctx: aciCtx,
		},
		aciCloudService: aciCloudService{
			loginService: service,
		},
	}, nil
}

type aciAPIService struct {
	aciContainerService
	aciComposeService
	aciCloudService
}

func (a *aciAPIService) ContainerService() containers.Service {
	return &a.aciContainerService
}

func (a *aciAPIService) ComposeService() compose.Service {
	return &a.aciComposeService
}

func (a *aciAPIService) CloudService() cloud.Service {
	return &a.aciCloudService
}

type aciContainerService struct {
	containerGroupsClient containerinstance.ContainerGroupsClient
	ctx                   store.AciContext
}

func (cs *aciContainerService) List(ctx context.Context, _ bool) ([]containers.Container, error) {
	var containerGroups []containerinstance.ContainerGroup
	result, err := cs.containerGroupsClient.ListByResourceGroup(ctx, cs.ctx.ResourceGroup)
	if err != nil {
		return []containers.Container{}, err
	}

	for result.NotDone() {
		containerGroups = append(containerGroups, result.Values()...)
		if err := result.NextWithContext(ctx); err != nil {
			return []containers.Container{}, err
		}
	}

	var res []containers.Container
	for _, containerGroup := range containerGroups {
		group, err := cs.containerGroupsClient.Get(ctx, cs.ctx.ResourceGroup, *containerGroup.Name)
		if err != nil {
			return []containers.Container{}, err
		}

		for _, container := range *group.Containers {
			var containerID string
			if *container.Name == singleContainerName {
				containerID = *containerGroup.Name
			} else {
				containerID = *containerGroup.Name + "_" + *container.Name
			}
			status := "Unknown"
			if container.InstanceView != nil && container.InstanceView.CurrentState != nil {
				status = *container.InstanceView.CurrentState.State
			}

			res = append(res, containers.Container{
				ID:     containerID,
				Image:  *container.Image,
				Status: status,
				Ports:  convert.ToPorts(group.IPAddress, *container.Ports),
			})
		}
	}

	return res, nil
}

func (cs *aciContainerService) Run(ctx context.Context, r containers.ContainerConfig) error {
	var ports []types.ServicePortConfig
	for _, p := range r.Ports {
		ports = append(ports, types.ServicePortConfig{
			Target:    p.ContainerPort,
			Published: p.HostPort,
		})
	}

	projectVolumes, serviceConfigVolumes, err := convert.GetRunVolumes(r.Volumes)
	if err != nil {
		return err
	}

	project := compose.Project{
		Name: r.ID,
		Config: types.Config{
			Services: []types.ServiceConfig{
				{
					Name:    singleContainerName,
					Image:   r.Image,
					Ports:   ports,
					Labels:  r.Labels,
					Volumes: serviceConfigVolumes,
				},
			},
			Volumes: projectVolumes,
		},
	}

	logrus.Debugf("Running container %q with name %q\n", r.Image, r.ID)
	groupDefinition, err := convert.ToContainerGroup(cs.ctx, project)
	if err != nil {
		return err
	}

	return createACIContainers(ctx, cs.ctx, groupDefinition)
}

func (cs *aciContainerService) Stop(ctx context.Context, containerName string, timeout *uint32) error {
	return errdefs.ErrNotImplemented
}

func getGroupAndContainerName(containerID string) (groupName string, containerName string) {
	tokens := strings.Split(containerID, "_")
	groupName = tokens[0]
	if len(tokens) > 1 {
		containerName = tokens[len(tokens)-1]
		groupName = containerID[:len(containerID)-(len(containerName)+1)]
	} else {
		containerName = singleContainerName
	}
	return groupName, containerName
}

func (cs *aciContainerService) Exec(ctx context.Context, name string, command string, reader io.Reader, writer io.Writer) error {
	groupName, containerAciName := getGroupAndContainerName(name)
	containerExecResponse, err := execACIContainer(ctx, cs.ctx, command, groupName, containerAciName)
	if err != nil {
		return err
	}

	return exec(
		context.Background(),
		*containerExecResponse.WebSocketURI,
		*containerExecResponse.Password,
		reader,
		writer,
	)
}

func (cs *aciContainerService) Logs(ctx context.Context, containerName string, req containers.LogsRequest) error {
	groupName, containerAciName := getGroupAndContainerName(containerName)
	logs, err := getACIContainerLogs(ctx, cs.ctx, groupName, containerAciName)
	if err != nil {
		return err
	}
	if req.Tail != "all" {
		tail, err := strconv.Atoi(req.Tail)
		if err != nil {
			return err
		}
		lines := strings.Split(logs, "\n")

		// If asked for less lines than exist, take only those lines
		if tail <= len(lines) {
			logs = strings.Join(lines[len(lines)-tail:], "\n")
		}
	}

	_, err = fmt.Fprint(req.Writer, logs)
	return err
}

func (cs *aciContainerService) Delete(ctx context.Context, containerID string, _ bool) error {
	cg, err := deleteACIContainerGroup(ctx, cs.ctx, containerID)
	if err != nil {
		return err
	}
	if cg.StatusCode == http.StatusNoContent {
		return ErrNoSuchContainer
	}

	return err
}

type aciComposeService struct {
	ctx store.AciContext
}

func (cs *aciComposeService) Up(ctx context.Context, opts compose.ProjectOptions) error {
	project, err := compose.ProjectFromOptions(&opts)
	if err != nil {
		return err
	}
	logrus.Debugf("Up on project with name %q\n", project.Name)
	groupDefinition, err := convert.ToContainerGroup(cs.ctx, *project)

	if err != nil {
		return err
	}
	return createACIContainers(ctx, cs.ctx, groupDefinition)
}

func (cs *aciComposeService) Down(ctx context.Context, opts compose.ProjectOptions) error {
	project, err := compose.ProjectFromOptions(&opts)
	if err != nil {
		return err
	}
	logrus.Debugf("Down on project with name %q\n", project.Name)

	cg, err := deleteACIContainerGroup(ctx, cs.ctx, project.Name)
	if err != nil {
		return err
	}
	if cg.StatusCode == http.StatusNoContent {
		return ErrNoSuchContainer
	}

	return err
}

type aciCloudService struct {
	loginService login.AzureLoginService
}

func (cs *aciCloudService) Login(ctx context.Context, params map[string]string) error {
	return cs.loginService.Login(ctx)
}
<commit_msg>Fix ace e2e tests : also use context store with config dir when registering aci backend<commit_after>package azure

import (
	"context"
	"fmt"
	"io"
	"net/http"
	"strconv"
	"strings"

	"github.com/docker/api/context/cloud"
	"github.com/docker/api/errdefs"

	"github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2018-10-01/containerinstance"
	"github.com/compose-spec/compose-go/types"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"

	"github.com/docker/api/azure/convert"
	"github.com/docker/api/azure/login"
	"github.com/docker/api/backend"
	"github.com/docker/api/compose"
	"github.com/docker/api/containers"
	apicontext "github.com/docker/api/context"
	"github.com/docker/api/context/store"
)

const singleContainerName = "single--container--aci"

// ErrNoSuchContainer is returned when the mentioned container does not exist
var ErrNoSuchContainer = errors.New("no such container")

func init() {
	backend.Register("aci", "aci", func(ctx context.Context) (backend.Service, error) {
		return New(ctx)
	})
}

func getter() interface{} {
	return &store.AciContext{}
}

// New creates a backend that can manage containers
func New(ctx context.Context) (backend.Service, error) {
	currentContext := apicontext.CurrentContext(ctx)
	contextStore := store.ContextStore(ctx)
	metadata, err := contextStore.Get(currentContext, getter)
	if err != nil {
		return nil, errors.Wrap(err, "wrong context type")
	}
	aciContext, _ := metadata.Metadata.Data.(store.AciContext)

	auth, _ := login.NewAuthorizerFromLogin()
	containerGroupsClient := containerinstance.NewContainerGroupsClient(aciContext.SubscriptionID)
	containerGroupsClient.Authorizer = auth

	return getAciAPIService(containerGroupsClient, aciContext)
}

func getAciAPIService(cgc containerinstance.ContainerGroupsClient, aciCtx store.AciContext) (*aciAPIService, error) {
	service, err := login.NewAzureLoginService()
	if err != nil {
		return nil, err
	}
	return &aciAPIService{
		aciContainerService: aciContainerService{
			containerGroupsClient: cgc,
			ctx:                   aciCtx,
		},
		aciComposeService: aciComposeService{
			ctx: aciCtx,
		},
		aciCloudService: aciCloudService{
			loginService: service,
		},
	}, nil
}

type aciAPIService struct {
	aciContainerService
	aciComposeService
	aciCloudService
}

func (a *aciAPIService) ContainerService() containers.Service {
	return &a.aciContainerService
}

func (a *aciAPIService) ComposeService() compose.Service {
	return &a.aciComposeService
}

func (a *aciAPIService) CloudService() cloud.Service {
	return &a.aciCloudService
}

type aciContainerService struct {
	containerGroupsClient containerinstance.ContainerGroupsClient
	ctx                   store.AciContext
}

func (cs *aciContainerService) List(ctx context.Context, _ bool) ([]containers.Container, error) {
	var containerGroups []containerinstance.ContainerGroup
	result, err := cs.containerGroupsClient.ListByResourceGroup(ctx, cs.ctx.ResourceGroup)
	if err != nil {
		return []containers.Container{}, err
	}

	for result.NotDone() {
		containerGroups = append(containerGroups, result.Values()...)
		if err := result.NextWithContext(ctx); err != nil {
			return []containers.Container{}, err
		}
	}

	var res []containers.Container
	for _, containerGroup := range containerGroups {
		group, err := cs.containerGroupsClient.Get(ctx, cs.ctx.ResourceGroup, *containerGroup.Name)
		if err != nil {
			return []containers.Container{}, err
		}

		for _, container := range *group.Containers {
			var containerID string
			if *container.Name == singleContainerName {
				containerID = *containerGroup.Name
			} else {
				containerID = *containerGroup.Name + "_" + *container.Name
			}
			status := "Unknown"
			if container.InstanceView != nil && container.InstanceView.CurrentState != nil {
				status = *container.InstanceView.CurrentState.State
			}

			res = append(res, containers.Container{
				ID:     containerID,
				Image:  *container.Image,
				Status: status,
				Ports:  convert.ToPorts(group.IPAddress, *container.Ports),
			})
		}
	}

	return res, nil
}

func (cs *aciContainerService) Run(ctx context.Context, r containers.ContainerConfig) error {
	var ports []types.ServicePortConfig
	for _, p := range r.Ports {
		ports = append(ports, types.ServicePortConfig{
			Target:    p.ContainerPort,
			Published: p.HostPort,
		})
	}

	projectVolumes, serviceConfigVolumes, err := convert.GetRunVolumes(r.Volumes)
	if err != nil {
		return err
	}

	project := compose.Project{
		Name: r.ID,
		Config: types.Config{
			Services: []types.ServiceConfig{
				{
					Name:    singleContainerName,
					Image:   r.Image,
					Ports:   ports,
					Labels:  r.Labels,
					Volumes: serviceConfigVolumes,
				},
			},
			Volumes: projectVolumes,
		},
	}

	logrus.Debugf("Running container %q with name %q\n", r.Image, r.ID)
	groupDefinition, err := convert.ToContainerGroup(cs.ctx, project)
	if err != nil {
		return err
	}

	return createACIContainers(ctx, cs.ctx, groupDefinition)
}

func (cs *aciContainerService) Stop(ctx context.Context, containerName string, timeout *uint32) error {
	return errdefs.ErrNotImplemented
}

func getGroupAndContainerName(containerID string) (groupName string, containerName string) {
	tokens := strings.Split(containerID, "_")
	groupName = tokens[0]
	if len(tokens) > 1 {
		containerName = tokens[len(tokens)-1]
		groupName = containerID[:len(containerID)-(len(containerName)+1)]
	} else {
		containerName = singleContainerName
	}
	return groupName, containerName
}

func (cs *aciContainerService) Exec(ctx context.Context, name string, command string, reader io.Reader, writer io.Writer) error {
	groupName, containerAciName := getGroupAndContainerName(name)
	containerExecResponse, err := execACIContainer(ctx, cs.ctx, command, groupName, containerAciName)
	if err != nil {
		return err
	}

	return exec(
		context.Background(),
		*containerExecResponse.WebSocketURI,
		*containerExecResponse.Password,
		reader,
		writer,
	)
}

func (cs *aciContainerService) Logs(ctx context.Context, containerName string, req containers.LogsRequest) error {
	groupName, containerAciName := getGroupAndContainerName(containerName)
	logs, err := getACIContainerLogs(ctx, cs.ctx, groupName, containerAciName)
	if err != nil {
		return err
	}
	if req.Tail != "all" {
		tail, err := strconv.Atoi(req.Tail)
		if err != nil {
			return err
		}
		lines := strings.Split(logs, "\n")

		// If asked for less lines than exist, take only those lines
		if tail <= len(lines) {
			logs = strings.Join(lines[len(lines)-tail:], "\n")
		}
	}

	_, err = fmt.Fprint(req.Writer, logs)
	return err
}

func (cs *aciContainerService) Delete(ctx context.Context, containerID string, _ bool) error {
	cg, err := deleteACIContainerGroup(ctx, cs.ctx, containerID)
	if err != nil {
		return err
	}
	if cg.StatusCode == http.StatusNoContent {
		return ErrNoSuchContainer
	}

	return err
}

type aciComposeService struct {
	ctx store.AciContext
}

func (cs *aciComposeService) Up(ctx context.Context, opts compose.ProjectOptions) error {
	project, err := compose.ProjectFromOptions(&opts)
	if err != nil {
		return err
	}
	logrus.Debugf("Up on project with name %q\n", project.Name)
	groupDefinition, err := convert.ToContainerGroup(cs.ctx, *project)

	if err != nil {
		return err
	}
	return createACIContainers(ctx, cs.ctx, groupDefinition)
}

func (cs *aciComposeService) Down(ctx context.Context, opts compose.ProjectOptions) error {
	project, err := compose.ProjectFromOptions(&opts)
	if err != nil {
		return err
	}
	logrus.Debugf("Down on project with name %q\n", project.Name)

	cg, err := deleteACIContainerGroup(ctx, cs.ctx, project.Name)
	if err != nil {
		return err
	}
	if cg.StatusCode == http.StatusNoContent {
		return ErrNoSuchContainer
	}

	return err
}

type aciCloudService struct {
	loginService login.AzureLoginService
}

func (cs *aciCloudService) Login(ctx context.Context, params map[string]string) error {
	return cs.loginService.Login(ctx)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
	"os"
	"path/filepath"
	"plugin"
	"rais/src/iiif"
	"sort"

	"github.com/uoregon-libraries/gopkg/logger"
)

type plugGeneric func()
type plugIDToPath func(iiif.ID) (string, error)
type plugLogger func(*logger.Logger)
type plugWrapHandler func(string, http.Handler) (http.Handler, error)

var idToPathPlugins []plugIDToPath
var wrapHandlerPlugins []plugWrapHandler
var teardownPlugins []plugGeneric

// pluginsFor returns a list of all plugin files which matched the given
// pattern.  Files are sorted by name.
func pluginsFor(pattern string) ([]string, error) {
	if !filepath.IsAbs(pattern) {
		var dir = filepath.Join(filepath.Dir(os.Args[0]), "plugins")
		pattern = filepath.Join(dir, pattern)
	}

	var files, err = filepath.Glob(pattern)
	if err != nil {
		return nil, fmt.Errorf("invalid plugin file pattern %q", pattern)
	}
	if len(files) == 0 {
		return nil, fmt.Errorf("plugin pattern %q doesn't match any files", pattern)
	}

	sort.Strings(files)
	return files, nil
}

// LoadPlugins searches for any plugins matching the pattern given.  If the
// pattern is not an absolute URL, it is treated as a pattern under the
// binary's dir/plugins.
func LoadPlugins(l *logger.Logger, patterns []string) {
	var plugFiles []string
	var seen = make(map[string]bool)
	for _, pattern := range patterns {
		var matches, err = pluginsFor(pattern)
		if err != nil {
			l.Fatalf("Cannot process pattern %q: %s", pattern, err)
		}

		// We do a sanity check before actually processing any plugins
		for _, file := range matches {
			if filepath.Ext(file) != ".so" {
				l.Fatalf("Cannot load unknown file %q (plugins must be compiled .so files)", file)
			}
			if seen[file] {
				l.Fatalf("Cannot load the same plugin twice (%q)", file)
			}
			seen[file] = true
		}

		plugFiles = append(plugFiles, matches...)
	}

	for _, file := range plugFiles {
		l.Infof("Loading plugin %q", file)
		loadPlugin(file, l)
	}
}

// loadPlugin attempts to read the given plugin file and extract known symbols.
// If a plugin exposes Initialize or SetLogger, they're called here once we're
// sure the plugin is valid.  IDToPath functions are indexed globally for use
// in the RAIS image serving handler.
//
// This function is unnecessarily complicated and needs refactoring.  Other
// than the concrete type, the "index a function" blocks are all basically the
// same.
func loadPlugin(fullpath string, l *logger.Logger) {
	var p, err = plugin.Open(fullpath)
	if err != nil {
		l.Errorf("Error loading plugin %q: %s", fullpath, err)
		return
	}

	var sym plugin.Symbol
	var fnCount int

	var log plugLogger
	sym, err = p.Lookup("SetLogger")
	if err == nil {
		var f, ok = sym.(func(*logger.Logger))
		if !ok {
			l.Errorf("%q.SetLogger is invalid", fullpath)
			return
		}
		l.Debugf("Found %q.SetLogger", fullpath)
		log = plugLogger(f)
		fnCount++
	}

	var idToPath plugIDToPath
	sym, err = p.Lookup("IDToPath")
	if err == nil {
		var f, ok = sym.(func(iiif.ID) (string, error))
		if !ok {
			l.Errorf("%q.IDToPath is invalid", fullpath)
			return
		}
		l.Debugf("Found %q.IDToPath", fullpath)
		idToPath = plugIDToPath(f)
		fnCount++
	}

	var init plugGeneric
	sym, err = p.Lookup("Initialize")
	if err == nil {
		var f, ok = sym.(func())
		if !ok {
			l.Errorf("%q.Initialize is invalid", fullpath)
			return
		}
		l.Debugf("Found %q.Initialize", fullpath)
		init = plugGeneric(f)
		fnCount++
	}

	var teardown plugGeneric
	sym, err = p.Lookup("Teardown")
	if err == nil {
		var f, ok = sym.(func())
		if !ok {
			l.Errorf("%q.Teardown is invalid", fullpath)
			return
		}

		l.Debugf("Found %q.Teardown", fullpath)
		teardown = plugGeneric(f)
		fnCount++
	}

	var wrapHandler plugWrapHandler
	sym, err = p.Lookup("WrapHandler")
	if err == nil {
		var f, ok = sym.(func(string, http.Handler) (http.Handler, error))
		if !ok {
			l.Errorf("%q.WrapHandler is invalid", fullpath)
			return
		}

		l.Debugf("Found %q.WrapHandler", fullpath)
		wrapHandler = plugWrapHandler(f)
		fnCount++
	}

	if fnCount == 0 {
		l.Warnf("%q doesn't expose any known functions", fullpath)
		return
	}

	// We can call SetLogger and Initialize immediately, as they're never called a second time
	if log != nil {
		log(l)
	}
	if init != nil {
		init()
	}

	// After initialization, we check if the plugin explicitly set itself to Disabled
	sym, err = p.Lookup("Disabled")
	if err == nil {
		var disabled, ok = sym.(*bool)
		if !ok {
			l.Errorf("%q.Disabled is not a boolean", fullpath)
			return
		}
		if *disabled {
			l.Infof("%q is disabled", fullpath)
			return
		}
		l.Debugf("%q is explicitly enabled", fullpath)
	}

	// Index other available functions
	if idToPath != nil {
		idToPathPlugins = append(idToPathPlugins, idToPath)
	}
	if teardown != nil {
		teardownPlugins = append(teardownPlugins, teardown)
	}
	if wrapHandler != nil {
		wrapHandlerPlugins = append(wrapHandlerPlugins, wrapHandler)
	}
}
<commit_msg>plugins: refactor plugin loading<commit_after>package main

import (
	"errors"
	"fmt"
	"net/http"
	"os"
	"path/filepath"
	"plugin"
	"rais/src/iiif"
	"reflect"
	"sort"
	"strings"

	"github.com/uoregon-libraries/gopkg/logger"
)

var idToPathPlugins []func(iiif.ID) (string, error)
var wrapHandlerPlugins []func(string, http.Handler) (http.Handler, error)
var teardownPlugins []func()

// pluginsFor returns a list of all plugin files which matched the given
// pattern.  Files are sorted by name.
func pluginsFor(pattern string) ([]string, error) {
	if !filepath.IsAbs(pattern) {
		var dir = filepath.Join(filepath.Dir(os.Args[0]), "plugins")
		pattern = filepath.Join(dir, pattern)
	}

	var files, err = filepath.Glob(pattern)
	if err != nil {
		return nil, fmt.Errorf("invalid plugin file pattern %q", pattern)
	}
	if len(files) == 0 {
		return nil, fmt.Errorf("plugin pattern %q doesn't match any files", pattern)
	}

	sort.Strings(files)
	return files, nil
}

// LoadPlugins searches for any plugins matching the pattern given.  If the
// pattern is not an absolute URL, it is treated as a pattern under the
// binary's dir/plugins.
func LoadPlugins(l *logger.Logger, patterns []string) {
	var plugFiles []string
	var seen = make(map[string]bool)
	for _, pattern := range patterns {
		var matches, err = pluginsFor(pattern)
		if err != nil {
			l.Fatalf("Cannot process pattern %q: %s", pattern, err)
		}

		// We do a sanity check before actually processing any plugins
		for _, file := range matches {
			if filepath.Ext(file) != ".so" {
				l.Fatalf("Cannot load unknown file %q (plugins must be compiled .so files)", file)
			}
			if seen[file] {
				l.Fatalf("Cannot load the same plugin twice (%q)", file)
			}
			seen[file] = true
		}

		plugFiles = append(plugFiles, matches...)
	}

	for _, file := range plugFiles {
		l.Infof("Loading plugin %q", file)
		var err = loadPlugin(file, l)
		if err != nil {
			l.Errorf("Unable to load %q: %s", file, err)
		}
	}
}

type pluginWrapper struct {
	*plugin.Plugin
	path      string
	functions []string
	errors    []string
}

func newPluginWrapper(path string) (*pluginWrapper, error) {
	var p, err = plugin.Open(path)
	if err != nil {
		return nil, fmt.Errorf("cannot load plugin %q: %s", path, err)
	}
	return &pluginWrapper{Plugin: p, path: path}, nil
}

// loadPluginFn loads the symbol by the given name and attempts to set it to
// the given object via reflection.  If the two aren't the same type, an error
// is added to the pluginWrapper's error list.
func (pw *pluginWrapper) loadPluginFn(name string, obj interface{}) {
	var sym, err = pw.Lookup(name)
	if err != nil {
		return
	}

	var objElem = reflect.ValueOf(obj).Elem()
	var objType = objElem.Type()
	var symV = reflect.ValueOf(sym)

	if !symV.Type().AssignableTo(objType) {
		pw.errors = append(pw.errors, fmt.Sprintf("invalid signature for %s (expecting %s)", name, objType))
		return
	}

	objElem.Set(symV)
	pw.functions = append(pw.functions, name)
}

// loadPlugin attempts to read the given plugin file and extract known symbols.
// If a plugin exposes Initialize or SetLogger, they're called here once we're
// sure the plugin is valid.  IDToPath functions are indexed globally for use
// in the RAIS image serving handler.
func loadPlugin(fullpath string, l *logger.Logger) error {
	var pw, err = newPluginWrapper(fullpath)
	if err != nil {
		return err
	}

	// Set up dummy / no-op functions so we can call these without risk
	var log = func(*logger.Logger) {}
	var initialize = func() {}

	// Simply initialize those functions we only want indexed if they exist
	var idToPath func(iiif.ID) (string, error)
	var teardown func()
	var wrapHandler func(string, http.Handler) (http.Handler, error)

	pw.loadPluginFn("SetLogger", &log)
	pw.loadPluginFn("IDToPath", &idToPath)
	pw.loadPluginFn("Initialize", &initialize)
	pw.loadPluginFn("Teardown", &teardown)
	pw.loadPluginFn("WrapHandler", &wrapHandler)

	if len(pw.errors) != 0 {
		return errors.New(strings.Join(pw.errors, ", "))
	}
	if len(pw.functions) == 0 {
		return fmt.Errorf("no known functions exposed")
	}

	// We need to call SetLogger and Initialize immediately, as they're never
	// called a second time and they tell us if the plugin is going to be used
	log(l)
	initialize()

	// After initialization, we check if the plugin explicitly set itself to Disabled
	var sym plugin.Symbol
	sym, err = pw.Lookup("Disabled")
	if err == nil {
		var disabled, ok = sym.(*bool)
		if !ok {
			return fmt.Errorf("non-boolean Disabled value exposed")
		}
		if *disabled {
			l.Infof("%q is disabled", fullpath)
			return nil
		}
		l.Debugf("%q is explicitly enabled", fullpath)
	}

	// Index remaining functions
	if idToPath != nil {
		idToPathPlugins = append(idToPathPlugins, idToPath)
	}
	if teardown != nil {
		teardownPlugins = append(teardownPlugins, teardown)
	}
	if wrapHandler != nil {
		wrapHandlerPlugins = append(wrapHandlerPlugins, wrapHandler)
	}

	return nil
}
<|endoftext|>


<commit_before>package backend

import (
	"reflect"
	"strings"

	"github.com/cblomart/vsphere-graphite/utils"
)

// Point : Information collected for a point
type Point struct {
	VCenter      string   `influx:"tag,vcenter"`
	ObjectType   string   `influx:"tag,type"`
	ObjectName   string   `influx:"tag,name"`
	Group        string   `influx:"key,1"`
	Counter      string   `influx:"key,2"`
	Instance     string   `influx:"tag,instance"`
	Rollup       string   `influx:"key,3"`
	Value        int64    `influx:"value"`
	Datastore    []string `influx:"tag,datastore" json:",omitempty"`
	ESXi         string   `influx:"tag,host" json:",omitempty"`
	Cluster      string   `influx:"tag,cluster" json:",omitempty"`
	Network      []string `influx:"tag,network" json:",omitempty"`
	ResourcePool string   `influx:"tag,resourcepool" json:",omitempty"`
	Folder       string   `influx:"tag,folder" json:",omitempty"`
	ViTags       []string `influx:"tag,vitags" json:",omitempty"`
	//NumCPU       int32    `influx:"tag,numcpu" json:",omitempty"`
	//MemorySizeMB int32    `influx:"tag,memorysizemb" json:",omitempty"`
	Timestamp int64 `influx:"time" elastic:"type:date,format:epoch_second"`
}

// GetTags returns the tags of point as a map of strings
func (point *Point) GetTags(noarray bool, separator string) map[string]string {
	tags := map[string]string{}
	tags["vcenter"] = point.VCenter
	tags["type"] = point.ObjectType
	tags["name"] = point.ObjectName
	if noarray {
		if len(point.Datastore) > 0 {
			tags["datastore"] = point.Datastore[0]
		}
	} else {
		if len(point.Datastore) > 0 {
			tags["datastore"] = strings.Join(point.Datastore, separator)
		}
	}
	if noarray {
		if len(point.Network) > 0 {
			tags["network"] = point.Network[0]
		}
	} else {
		if len(point.Network) > 0 {
			tags["network"] = strings.Join(point.Network, separator)
		}
	}
	if len(point.ESXi) > 0 {
		tags["host"] = point.ESXi
	}
	if len(point.Cluster) > 0 {
		tags["cluster"] = point.Cluster
	}
	if len(point.Instance) > 0 {
		tags["instance"] = point.Instance
	}
	if len(point.ResourcePool) > 0 {
		tags["resourcepool"] = point.ResourcePool
	}
	if len(point.Folder) > 0 {
		tags["folder"] = point.Folder
	}
	if noarray {
		if len(point.ViTags) > 0 {
			tags["vitags"] = point.ViTags[0]
		}
	} else {
		if len(point.ViTags) > 0 {
			tags["vitags"] = strings.Join(point.ViTags, separator)
		}
	}
	/*
		if point.NumCPU != 0 {
			tags["numcpu"] = strconv.FormatInt(int64(point.NumCPU), 10)
		}
		if point.MemorySizeMB != 0 {
			tags["memorysizemb"] = strconv.FormatInt(int64(point.MemorySizeMB), 10)
		}
	*/
	return tags
}

// GetInfluxPoint : convert a point to an influxpoint
func (point *Point) GetInfluxPoint(noarray bool, valuefield string) *InfluxPoint {
	keyParts := make(map[int]string)
	ip := InfluxPoint{
		Fields: make(map[string]string),
		Tags:   make(map[string]string),
	}
	v := reflect.ValueOf(point).Elem()
	for i := 0; i < v.NumField(); i++ {
		vfield := v.Field(i)
		tfield := v.Type().Field(i)
		tag := tfield.Tag.Get(InfluxTag)
		tagfields := strings.Split(tag, ",")
		if len(tagfields) == 0 || len(tagfields) > 2 {
			stdlog.Println("tag field ignored: " + tag)
			continue
		}
		tagtype := tagfields[0]
		tagname := strings.ToLower(tfield.Name)
		if len(tagfields) == 2 {
			tagname = tagfields[1]
		}
		switch tagtype {
		case "key":
			keyParts[utils.MustAtoi(tagname)] = utils.ValToString(vfield.Interface(), "_", false)
		case "tag":
			value := utils.ValToString(vfield.Interface(), ",", noarray)
			// need to escape " " and "," in tags
			value = strings.Replace(value, ",", "\\,", -1)
			value = strings.Replace(value, " ", "\\ ", -1)
			ip.Tags[tagname] = utils.ValToString(vfield.Interface(), ",", noarray)
		case "value":
			ip.Fields[valuefield] = utils.ValToString(vfield.Interface(), ",", true) + "i"
		case "time":
			ip.Timestamp = vfield.Int()
		default:
		}
	}
	// sort key part keys and join them
	ip.Key = utils.Join(keyParts, "_")
	return &ip
}

// ToInflux serialises the data to be consumed by influx line protocol
// see https://docs.influxdata.com/influxdb/v1.2/write_protocols/line_protocol_tutorial/
func (point *Point) ToInflux(noarray bool, valuefield string) string {
	return point.GetInfluxPoint(noarray, valuefield).ToInflux(noarray, valuefield)
}
<commit_msg>correct influx tag handling<commit_after>package backend

import (
	"reflect"
	"strings"

	"github.com/cblomart/vsphere-graphite/utils"
)

// Point : Information collected for a point
type Point struct {
	VCenter      string   `influx:"tag,vcenter"`
	ObjectType   string   `influx:"tag,type"`
	ObjectName   string   `influx:"tag,name"`
	Group        string   `influx:"key,1"`
	Counter      string   `influx:"key,2"`
	Instance     string   `influx:"tag,instance"`
	Rollup       string   `influx:"key,3"`
	Value        int64    `influx:"value"`
	Datastore    []string `influx:"tag,datastore" json:",omitempty"`
	ESXi         string   `influx:"tag,host" json:",omitempty"`
	Cluster      string   `influx:"tag,cluster" json:",omitempty"`
	Network      []string `influx:"tag,network" json:",omitempty"`
	ResourcePool string   `influx:"tag,resourcepool" json:",omitempty"`
	Folder       string   `influx:"tag,folder" json:",omitempty"`
	ViTags       []string `influx:"tag,vitags" json:",omitempty"`
	//NumCPU       int32    `influx:"tag,numcpu" json:",omitempty"`
	//MemorySizeMB int32    `influx:"tag,memorysizemb" json:",omitempty"`
	Timestamp int64 `influx:"time" elastic:"type:date,format:epoch_second"`
}

// GetTags returns the tags of point as a map of strings
func (point *Point) GetTags(noarray bool, separator string) map[string]string {
	tags := map[string]string{}
	tags["vcenter"] = point.VCenter
	tags["type"] = point.ObjectType
	tags["name"] = point.ObjectName
	if noarray {
		if len(point.Datastore) > 0 {
			tags["datastore"] = point.Datastore[0]
		}
	} else {
		if len(point.Datastore) > 0 {
			tags["datastore"] = strings.Join(point.Datastore, separator)
		}
	}
	if noarray {
		if len(point.Network) > 0 {
			tags["network"] = point.Network[0]
		}
	} else {
		if len(point.Network) > 0 {
			tags["network"] = strings.Join(point.Network, separator)
		}
	}
	if len(point.ESXi) > 0 {
		tags["host"] = point.ESXi
	}
	if len(point.Cluster) > 0 {
		tags["cluster"] = point.Cluster
	}
	if len(point.Instance) > 0 {
		tags["instance"] = point.Instance
	}
	if len(point.ResourcePool) > 0 {
		tags["resourcepool"] = point.ResourcePool
	}
	if len(point.Folder) > 0 {
		tags["folder"] = point.Folder
	}
	if noarray {
		if len(point.ViTags) > 0 {
			tags["vitags"] = point.ViTags[0]
		}
	} else {
		if len(point.ViTags) > 0 {
			tags["vitags"] = strings.Join(point.ViTags, separator)
		}
	}
	/*
		if point.NumCPU != 0 {
			tags["numcpu"] = strconv.FormatInt(int64(point.NumCPU), 10)
		}
		if point.MemorySizeMB != 0 {
			tags["memorysizemb"] = strconv.FormatInt(int64(point.MemorySizeMB), 10)
		}
	*/
	return tags
}

// GetInfluxPoint : convert a point to an influxpoint
func (point *Point) GetInfluxPoint(noarray bool, valuefield string) *InfluxPoint {
	keyParts := make(map[int]string)
	ip := InfluxPoint{
		Fields: make(map[string]string),
		Tags:   make(map[string]string),
	}
	v := reflect.ValueOf(point).Elem()
	for i := 0; i < v.NumField(); i++ {
		vfield := v.Field(i)
		tfield := v.Type().Field(i)
		tag := tfield.Tag.Get(InfluxTag)
		tagfields := strings.Split(tag, ",")
		if len(tagfields) == 0 || len(tagfields) > 2 {
			stdlog.Println("tag field ignored: " + tag)
			continue
		}
		tagtype := tagfields[0]
		tagname := strings.ToLower(tfield.Name)
		if len(tagfields) == 2 {
			tagname = tagfields[1]
		}
		switch tagtype {
		case "key":
			keyParts[utils.MustAtoi(tagname)] = utils.ValToString(vfield.Interface(), "_", false)
		case "tag":
			value := utils.ValToString(vfield.Interface(), ",", noarray)
			// need to escape " " and "," in tags
			value = strings.Replace(value, ",", "\\,", -1)
			value = strings.Replace(value, " ", "\\ ", -1)
			ip.Tags[tagname] = value
		case "value":
			ip.Fields[valuefield] = utils.ValToString(vfield.Interface(), ",", true) + "i"
		case "time":
			ip.Timestamp = vfield.Int()
		default:
		}
	}
	// sort key part keys and join them
	ip.Key = utils.Join(keyParts, "_")
	return &ip
}

// ToInflux serialises the data to be consumed by influx line protocol
// see https://docs.influxdata.com/influxdb/v1.2/write_protocols/line_protocol_tutorial/
func (point *Point) ToInflux(noarray bool, valuefield string) string {
	return point.GetInfluxPoint(noarray, valuefield).ToInflux(noarray, valuefield)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"encoding/json"
	"io/ioutil"
	"log"
	"math/rand"
	"time"
	"errors"
	"net/smtp"
	"net"
)

// wichtel-bot settings
type Settings struct {
	SmtpServer      string
	SmtpPort        string
	SmtpUser        string
	SmtpPassword    string
	SenderEmail     string
	MaximumDrawRuns int
}

// A wichtel for the wichtel draw - wichtel are identified by their email
type Wichtel struct {
	Name                  string
	Email                 string
	ExcludeWichtelByEmail []string
}

type WichtelGroup []Wichtel

type WichtelMap map[*Wichtel]Wichtel

const MAXIMUM_DRAW_RUNS = 100

// Main function running the wichtel draw
func main() {
	fmt.Println("Hello wichtel admin!")

	var settings Settings

	settings.readSettings("config/settings.json")

	var wichtelGroup WichtelGroup

	wichtelGroup.readWichtelInput("config/wichtel.json")

	fmt.Println("You are about to draw wichtel from: ", wichtelGroup)

	var runs = 1
	for ; runs < MAXIMUM_DRAW_RUNS; {
		err, wichtelMap := wichtelGroup.assignWichtel()
		if err == nil {
			fmt.Println("Wichtel successfully assigned: ")
			for santa, wichtel := range wichtelMap {
				fmt.Println((*santa).Email, wichtel.Email)
				sendEmail(settings, wichtel, *santa)
			}
			return
		}
	}

}

// Draw a random wichtel from the wichtel pool
func (wichtelGroup WichtelGroup) drawRandomWichtel() (wichtel Wichtel, remainingWichtelGroup WichtelGroup) {
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	var randomIndex = r.Intn(len(wichtelGroup))
	wichtel = wichtelGroup[randomIndex]
	remainingWichtelGroup = append(wichtelGroup[:randomIndex], wichtelGroup[randomIndex + 1:]...)
	return
}

// Send out wichtel emails
func sendEmail(settings Settings, wichtel Wichtel, santa Wichtel) {

	if(settings.SmtpServer == "mail.example.com"){
		fmt.Println("Please provide smtp settings to send out wichtel mails.")
		return
	}
	host, _, _ := net.SplitHostPort(settings.SmtpServer + ":" + settings.SmtpPort)

	// Set up authentication information.
	auth := smtp.PlainAuth("", settings.SmtpUser, settings.SmtpPassword, host)

	// Connect to the server, authenticate, set the sender and recipient,
	// and send the email all in one step.
	to := []string{santa.Email}
	fromHeader := "From: " + settings.SenderEmail + "\n"
	toHeader := "To: " + santa.Email + "\n"
	mime := "MIME-version: 1.0;\nContent-Type: text/plain; charset=\"UTF-8\";\n\n";
	subject := "Subject: Dein Wichtel!\n"

	msg := []byte(fromHeader + toHeader + subject + mime + "Dein Wichtel ist: " + wichtel.Name + " (" + wichtel.Email + ")\r\n" +
		"Happy Wichteling!\r\n" +
		"\r\n" +
		"¨¨¨¨¨¨¨¨¨. *\r\n" +
		"¨¨¨¨¨¨¨¨¨ **\r\n" +
		"¨¨¨¨¨¨¨¨¨*o*\r\n" +
		"¨¨¨¨¨¨¨¨*♥*o*\r\n" +
		"¨¨¨¨¨¨¨***o***\r\n" +
		"¨¨¨¨¨¨**o**♥*o*\r\n" +
		"¨¨¨¨¨**♥**o**o**\r\n" +
		"¨¨¨¨**o**♥***♥*o*\r\n" +
		"¨¨¨*****♥*o**o****\r\n" +
		"¨¨**♥**o*****o**♥**\r\n" +
		"¨******o*****♥**o***\r\n" +
		"	****o***♥**o***o***♥ *\r\n" +
		"¨¨¨¨¨____!_!____\r\n" +
		"¨¨¨¨¨\\_________/¨¨\r\n")
	err := smtp.SendMail(settings.SmtpServer + ":" + settings.SmtpPort, auth, settings.SenderEmail, to, msg)
	if err != nil {
		log.Fatal(err)
	}else {
		fmt.Println("Mail sent successfully.")
	}
}

func (settings *Settings) readSettings(filePath string) {

	content, err := ioutil.ReadFile(filePath)
	if err != nil {
		log.Fatal(err)
	}

	jsonErr := json.Unmarshal(content, settings)

	if jsonErr != nil {
		log.Fatal("Settings unmarshal failed: ", jsonErr)
	}
}

func (wichtelGroup *WichtelGroup) readWichtelInput(filePath string) {

	content, err := ioutil.ReadFile(filePath)
	if err != nil {
		log.Fatal(err)
	}

	jsonErr := json.Unmarshal(content, wichtelGroup)

	if jsonErr != nil {
		log.Fatal("Wichtel unmarshal failed: ", jsonErr)
	}
}

func (inputGroup WichtelGroup) assignWichtel() (err error, wichtelMap WichtelMap) {

	wichtelMap = make(WichtelMap)
	var santaGroup = append([]Wichtel(nil), inputGroup...)
	var wichtelGroup WichtelGroup = append([]Wichtel(nil), inputGroup...)

	for len(wichtelGroup) > 0 {
		var wichtel Wichtel;
		var santa Wichtel;

		wichtel, wichtelGroup = wichtelGroup.drawRandomWichtel()
		santa, santaGroup = santaGroup[0], santaGroup[1:]
		if !santa.checkWichtel(wichtel) {
			err = errors.New("Draw did not succeed")
			return
		}

		wichtelMap[&santa] = wichtel
	}

	return
}

func (santa Wichtel) checkWichtel(wichtel Wichtel) (bool) {
	if (santa.Email == wichtel.Email) {
		return false
	}

	for _, mail := range santa.ExcludeWichtelByEmail {
		if mail == wichtel.Email {
			return false
		}
	}

	return true
}<commit_msg>Fix wichtel mail x-mas tree<commit_after>package main

import (
	"fmt"
	"encoding/json"
	"io/ioutil"
	"log"
	"math/rand"
	"time"
	"errors"
	"net/smtp"
	"net"
)

// wichtel-bot settings
type Settings struct {
	SmtpServer      string
	SmtpPort        string
	SmtpUser        string
	SmtpPassword    string
	SenderEmail     string
	MaximumDrawRuns int
}

// A wichtel for the wichtel draw - wichtel are identified by their email
type Wichtel struct {
	Name                  string
	Email                 string
	ExcludeWichtelByEmail []string
}

type WichtelGroup []Wichtel

type WichtelMap map[*Wichtel]Wichtel

const MAXIMUM_DRAW_RUNS = 100

// Main function running the wichtel draw
func main() {
	fmt.Println("Hello wichtel admin!")

	var settings Settings

	settings.readSettings("config/settings.json")

	var wichtelGroup WichtelGroup

	wichtelGroup.readWichtelInput("config/wichtel.json")

	fmt.Println("You are about to draw wichtel from: ", wichtelGroup)

	var runs = 1
	for ; runs < MAXIMUM_DRAW_RUNS; {
		err, wichtelMap := wichtelGroup.assignWichtel()
		if err == nil {
			fmt.Println("Wichtel successfully assigned: ")
			for santa, wichtel := range wichtelMap {
				fmt.Println((*santa).Email, wichtel.Email)
				sendEmail(settings, wichtel, *santa)
			}
			return
		}
	}

}

// Draw a random wichtel from the wichtel pool
func (wichtelGroup WichtelGroup) drawRandomWichtel() (wichtel Wichtel, remainingWichtelGroup WichtelGroup) {
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	var randomIndex = r.Intn(len(wichtelGroup))
	wichtel = wichtelGroup[randomIndex]
	remainingWichtelGroup = append(wichtelGroup[:randomIndex], wichtelGroup[randomIndex + 1:]...)
	return
}

// Send out wichtel emails
func sendEmail(settings Settings, wichtel Wichtel, santa Wichtel) {

	if(settings.SmtpServer == "mail.example.com"){
		fmt.Println("Please provide smtp settings to send out wichtel mails.")
		return
	}
	host, _, _ := net.SplitHostPort(settings.SmtpServer + ":" + settings.SmtpPort)

	// Set up authentication information.
	auth := smtp.PlainAuth("", settings.SmtpUser, settings.SmtpPassword, host)

	// Connect to the server, authenticate, set the sender and recipient,
	// and send the email all in one step.
	to := []string{santa.Email}
	fromHeader := "From: " + settings.SenderEmail + "\n"
	toHeader := "To: " + santa.Email + "\n"
	mime := "MIME-version: 1.0;\nContent-Type: text/plain; charset=\"UTF-8\";\n\n";
	subject := "Subject: Dein Wichtel!\n"

	msg := []byte(fromHeader + toHeader + subject + mime + "Dein Wichtel ist: " + wichtel.Name + " (" + wichtel.Email + ")\r\n" +
		"Happy Wichteling!\r\n" +
		"\r\n" +
		"¨¨¨¨¨¨¨¨¨. *\r\n" +
		"¨¨¨¨¨¨¨¨¨ **\r\n" +
		"¨¨¨¨¨¨¨¨¨*o*\r\n" +
		"¨¨¨¨¨¨¨¨*♥*o*\r\n" +
		"¨¨¨¨¨¨¨***o***\r\n" +
		"¨¨¨¨¨¨**o**♥*o*\r\n" +
		"¨¨¨¨¨**♥**o**o**\r\n" +
		"¨¨¨¨**o**♥***♥*o*\r\n" +
		"¨¨¨*****♥*o**o****\r\n" +
		"¨¨**♥**o*****o**♥**\r\n" +
		"¨******o*****♥**o***\r\n" +
		"****o***♥**o***o***♥ *\r\n" +
		"¨¨¨¨¨____!_!____\r\n" +
		"¨¨¨¨¨\\_________/¨¨\r\n")
	err := smtp.SendMail(settings.SmtpServer + ":" + settings.SmtpPort, auth, settings.SenderEmail, to, msg)
	if err != nil {
		log.Fatal(err)
	}else {
		fmt.Println("Mail sent successfully.")
	}
}

func (settings *Settings) readSettings(filePath string) {

	content, err := ioutil.ReadFile(filePath)
	if err != nil {
		log.Fatal(err)
	}

	jsonErr := json.Unmarshal(content, settings)

	if jsonErr != nil {
		log.Fatal("Settings unmarshal failed: ", jsonErr)
	}
}

func (wichtelGroup *WichtelGroup) readWichtelInput(filePath string) {

	content, err := ioutil.ReadFile(filePath)
	if err != nil {
		log.Fatal(err)
	}

	jsonErr := json.Unmarshal(content, wichtelGroup)

	if jsonErr != nil {
		log.Fatal("Wichtel unmarshal failed: ", jsonErr)
	}
}

func (inputGroup WichtelGroup) assignWichtel() (err error, wichtelMap WichtelMap) {

	wichtelMap = make(WichtelMap)
	var santaGroup = append([]Wichtel(nil), inputGroup...)
	var wichtelGroup WichtelGroup = append([]Wichtel(nil), inputGroup...)

	for len(wichtelGroup) > 0 {
		var wichtel Wichtel;
		var santa Wichtel;

		wichtel, wichtelGroup = wichtelGroup.drawRandomWichtel()
		santa, santaGroup = santaGroup[0], santaGroup[1:]
		if !santa.checkWichtel(wichtel) {
			err = errors.New("Draw did not succeed")
			return
		}

		wichtelMap[&santa] = wichtel
	}

	return
}

func (santa Wichtel) checkWichtel(wichtel Wichtel) (bool) {
	if (santa.Email == wichtel.Email) {
		return false
	}

	for _, mail := range santa.ExcludeWichtelByEmail {
		if mail == wichtel.Email {
			return false
		}
	}

	return true
}<|endoftext|>


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

package ssh

import (
	"fmt"
	"net"
)

// OpenChannelError is returned if the other side rejects an
// OpenChannel request.
type OpenChannelError struct {
	Reason  RejectionReason
	Message string
}

func (e *OpenChannelError) Error() string {
	return fmt.Sprintf("ssh: rejected: %s (%s)", e.Reason, e.Message)
}

// ConnMetadata holds metadata for the connection.
type ConnMetadata interface {
	// User returns the user ID for this connection.
	User() string

	// SessionID returns the sesson hash, also denoted by H.
	SessionID() []byte

	// ClientVersion returns the client's version string as hashed
	// into the session ID.
	ClientVersion() []byte

	// ServerVersion returns the server's version string as hashed
	// into the session ID.
	ServerVersion() []byte

	// RemoteAddr returns the remote address for this connection.
	RemoteAddr() net.Addr

	// LocalAddr returns the local address for this connection.
	LocalAddr() net.Addr
}

// Conn represents an SSH connection for both server and client roles.
// Conn is the basis for implementing an application layer, such
// as ClientConn, which implements the traditional shell access for
// clients.
type Conn interface {
	ConnMetadata

	// SendRequest sends a global request, and returns the
	// reply. If wantReply is true, it returns the response status
	// and payload. See also RFC4254, section 4.
	SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error)

	// OpenChannel tries to open an channel. If the request is
	// rejected, it returns *OpenChannelError. On success it returns
	// the SSH Channel and a Go channel for incoming, out-of-band
	// requests. The Go channel must be serviced, or the
	// connection will hang.
	OpenChannel(name string, data []byte) (Channel, <-chan *Request, error)

	// Close closes the underlying network connection
	Close() error

	// Wait blocks until the connection has shut down, and returns the
	// error causing the shutdown.
	Wait() error

	// TODO(hanwen): consider exposing:
	//   RequestKeyChange
	//   Disconnect
}

// DiscardRequests consumes and rejects all requests from the
// passed-in channel.
func DiscardRequests(in <-chan *Request) {
	for req := range in {
		if req.WantReply {
			req.Reply(false, nil)
		}
	}
}

// A connection represents an incoming connection.
type connection struct {
	transport *handshakeTransport
	sshConn

	// The connection protocol.
	*mux
}

func (c *connection) Close() error {
	return c.sshConn.conn.Close()
}

// sshconn provides net.Conn metadata, but disallows direct reads and
// writes.
type sshConn struct {
	conn net.Conn

	user          string
	sessionID     []byte
	clientVersion []byte
	serverVersion []byte
}

func dup(src []byte) []byte {
	dst := make([]byte, len(src))
	copy(dst, src)
	return dst
}

func (c *sshConn) User() string {
	return c.user
}

func (c *sshConn) RemoteAddr() net.Addr {
	return c.conn.RemoteAddr()
}

func (c *sshConn) Close() error {
	return c.conn.Close()
}

func (c *sshConn) LocalAddr() net.Addr {
	return c.conn.LocalAddr()
}

func (c *sshConn) SessionID() []byte {
	return dup(c.sessionID)
}

func (c *sshConn) ClientVersion() []byte {
	return dup(c.clientVersion)
}

func (c *sshConn) ServerVersion() []byte {
	return dup(c.serverVersion)
}
<commit_msg>ssh: fixing a small typo in connection.go<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ssh

import (
	"fmt"
	"net"
)

// OpenChannelError is returned if the other side rejects an
// OpenChannel request.
type OpenChannelError struct {
	Reason  RejectionReason
	Message string
}

func (e *OpenChannelError) Error() string {
	return fmt.Sprintf("ssh: rejected: %s (%s)", e.Reason, e.Message)
}

// ConnMetadata holds metadata for the connection.
type ConnMetadata interface {
	// User returns the user ID for this connection.
	User() string

	// SessionID returns the session hash, also denoted by H.
	SessionID() []byte

	// ClientVersion returns the client's version string as hashed
	// into the session ID.
	ClientVersion() []byte

	// ServerVersion returns the server's version string as hashed
	// into the session ID.
	ServerVersion() []byte

	// RemoteAddr returns the remote address for this connection.
	RemoteAddr() net.Addr

	// LocalAddr returns the local address for this connection.
	LocalAddr() net.Addr
}

// Conn represents an SSH connection for both server and client roles.
// Conn is the basis for implementing an application layer, such
// as ClientConn, which implements the traditional shell access for
// clients.
type Conn interface {
	ConnMetadata

	// SendRequest sends a global request, and returns the
	// reply. If wantReply is true, it returns the response status
	// and payload. See also RFC4254, section 4.
	SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error)

	// OpenChannel tries to open an channel. If the request is
	// rejected, it returns *OpenChannelError. On success it returns
	// the SSH Channel and a Go channel for incoming, out-of-band
	// requests. The Go channel must be serviced, or the
	// connection will hang.
	OpenChannel(name string, data []byte) (Channel, <-chan *Request, error)

	// Close closes the underlying network connection
	Close() error

	// Wait blocks until the connection has shut down, and returns the
	// error causing the shutdown.
	Wait() error

	// TODO(hanwen): consider exposing:
	//   RequestKeyChange
	//   Disconnect
}

// DiscardRequests consumes and rejects all requests from the
// passed-in channel.
func DiscardRequests(in <-chan *Request) {
	for req := range in {
		if req.WantReply {
			req.Reply(false, nil)
		}
	}
}

// A connection represents an incoming connection.
type connection struct {
	transport *handshakeTransport
	sshConn

	// The connection protocol.
	*mux
}

func (c *connection) Close() error {
	return c.sshConn.conn.Close()
}

// sshconn provides net.Conn metadata, but disallows direct reads and
// writes.
type sshConn struct {
	conn net.Conn

	user          string
	sessionID     []byte
	clientVersion []byte
	serverVersion []byte
}

func dup(src []byte) []byte {
	dst := make([]byte, len(src))
	copy(dst, src)
	return dst
}

func (c *sshConn) User() string {
	return c.user
}

func (c *sshConn) RemoteAddr() net.Addr {
	return c.conn.RemoteAddr()
}

func (c *sshConn) Close() error {
	return c.conn.Close()
}

func (c *sshConn) LocalAddr() net.Addr {
	return c.conn.LocalAddr()
}

func (c *sshConn) SessionID() []byte {
	return dup(c.sessionID)
}

func (c *sshConn) ClientVersion() []byte {
	return dup(c.clientVersion)
}

func (c *sshConn) ServerVersion() []byte {
	return dup(c.serverVersion)
}
<|endoftext|>


<commit_before>package stacks

import (
	"bytes"
	"fmt"
	"text/template"
)

// DeployTimeParser - Parses templates during deployment to resolve specfic Dependency functions like stackout...
func (s *Stack) DeployTimeParser() error {

	// define Delims
	left, right := s.delims("deploy")

	// Create template
	t, err := template.New("deploy-template").Delims(left, right).Funcs(*s.DeployTimeFunc).Parse(s.Template)
	if err != nil {
		return err
	}

	// so that we can write to string
	var doc bytes.Buffer

	// Add metadata specific to the stack we're working with to the parser
	s.TemplateValues["stack"] = s.Name
	s.TemplateValues["parameters"] = s.Parameters

	t.Execute(&doc, s.TemplateValues)
	s.Template = doc.String()
	Log.Debug(fmt.Sprintf("Deploy Time Template Generate:\n%s", s.Template))

	return nil
}

// GenTimeParser - Parses templates before deploying them...
func (s *Stack) GenTimeParser() error {

	if err := s.FetchContent(); err != nil {
		return err
	}

	// define Delims
	left, right := s.delims("gen")

	// create template
	t, err := template.New("gen-template").Delims(left, right).Funcs(*s.GenTimeFunc).Parse(s.Template)
	if err != nil {
		return err
	}

	// so that we can write to string
	var doc bytes.Buffer

	// Add metadata specific to the stack we're working with to the parser
	s.TemplateValues["stack"] = s.Name
	s.TemplateValues["parameters"] = s.Parameters

	t.Execute(&doc, s.TemplateValues)
	s.Template = doc.String()
	return nil
}
<commit_msg>update {{.stacks}} to represent stack values and add {{.name}} for stack name<commit_after>package stacks

import (
	"bytes"
	"fmt"
	"text/template"
)

// DeployTimeParser - Parses templates during deployment to resolve specfic Dependency functions like stackout...
func (s *Stack) DeployTimeParser() error {

	// define Delims
	left, right := s.delims("deploy")

	// Create template
	t, err := template.New("deploy-template").Delims(left, right).Funcs(*s.DeployTimeFunc).Parse(s.Template)
	if err != nil {
		return err
	}

	// so that we can write to string
	var doc bytes.Buffer

	// Add metadata specific to the stack we're working with to the parser
	s.TemplateValues["stack"] = s.TemplateValues[s.Name]
	s.TemplateValues["parameters"] = s.Parameters
	s.TemplateValues["name"] = s.Name

	t.Execute(&doc, s.TemplateValues)
	s.Template = doc.String()
	Log.Debug(fmt.Sprintf("Deploy Time Template Generate:\n%s", s.Template))

	return nil
}

// GenTimeParser - Parses templates before deploying them...
func (s *Stack) GenTimeParser() error {

	if err := s.FetchContent(); err != nil {
		return err
	}

	// define Delims
	left, right := s.delims("gen")

	// create template
	t, err := template.New("gen-template").Delims(left, right).Funcs(*s.GenTimeFunc).Parse(s.Template)
	if err != nil {
		return err
	}

	// so that we can write to string
	var doc bytes.Buffer

	// Add metadata specific to the stack we're working with to the parser
	s.TemplateValues["stack"] = s.TemplateValues[s.Name]
	s.TemplateValues["parameters"] = s.Parameters
	s.TemplateValues["name"] = s.Name

	t.Execute(&doc, s.TemplateValues)
	s.Template = doc.String()
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package state

import (
	"strings"

	"github.com/juju/errors"
	"github.com/juju/loggo"
	"gopkg.in/juju/names.v2"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"gopkg.in/mgo.v2/txn"
)

var upgradesLogger = loggo.GetLogger("juju.state.upgrade")

// runForAllModelStates will run runner function for every model passing a state
// for that model.
func runForAllModelStates(st *State, runner func(st *State) error) error {
	models, closer := st.getCollection(modelsC)
	defer closer()

	var modelDocs []bson.M
	err := models.Find(nil).Select(bson.M{"_id": 1}).All(&modelDocs)
	if err != nil {
		return errors.Annotate(err, "failed to read models")
	}

	for _, modelDoc := range modelDocs {
		modelUUID := modelDoc["_id"].(string)
		envSt, err := st.ForModel(names.NewModelTag(modelUUID))
		if err != nil {
			return errors.Annotatef(err, "failed to open model %q", modelUUID)
		}
		defer envSt.Close()
		if err := runner(envSt); err != nil {
			return errors.Annotatef(err, "model UUID %q", modelUUID)
		}
	}
	return nil
}

// readBsonDField returns the value of a given field in a bson.D.
func readBsonDField(d bson.D, name string) (interface{}, bool) {
	for i := range d {
		field := &d[i]
		if field.Name == name {
			return field.Value, true
		}
	}
	return nil, false
}

// replaceBsonDField replaces a field in bson.D.
func replaceBsonDField(d bson.D, name string, value interface{}) error {
	for i, field := range d {
		if field.Name == name {
			newField := field
			newField.Value = value
			d[i] = newField
			return nil
		}
	}
	return errors.NotFoundf("field %q", name)
}

// RenameAddModelPermission renames any permissions called addmodel to add-model.
func RenameAddModelPermission(st *State) error {
	coll, closer := st.getRawCollection(permissionsC)
	defer closer()
	upgradesLogger.Infof("migrating addmodel permission")

	iter := coll.Find(bson.M{"access": "addmodel"}).Iter()
	defer iter.Close()
	var ops []txn.Op
	var doc bson.M
	for iter.Next(&doc) {
		id, ok := doc["_id"]
		if !ok {
			return errors.New("no id found in permission doc")
		}

		ops = append(ops, txn.Op{
			C:      permissionsC,
			Id:     id,
			Assert: txn.DocExists,
			Update: bson.D{{"$set", bson.D{{"access", "add-model"}}}},
		})
	}
	if err := iter.Err(); err != nil {
		return errors.Trace(err)
	}
	return st.runRawTransaction(ops)
}

// StripLocalUserDomain removes any @local suffix from any relevant document field values.
func StripLocalUserDomain(st *State) error {
	var ops []txn.Op
	more, err := stripLocalFromFields(st, cloudCredentialsC, "_id", "owner")
	if err != nil {
		return err
	}
	ops = append(ops, more...)

	more, err = stripLocalFromFields(st, modelsC, "owner", "cloud-credential")
	if err != nil {
		return err
	}
	ops = append(ops, more...)

	more, err = stripLocalFromFields(st, usermodelnameC, "_id")
	if err != nil {
		return err
	}
	ops = append(ops, more...)

	more, err = stripLocalFromFields(st, controllerUsersC, "_id", "user", "createdby")
	if err != nil {
		return err
	}
	ops = append(ops, more...)

	more, err = stripLocalFromFields(st, modelUsersC, "_id", "user", "createdby")
	if err != nil {
		return err
	}
	ops = append(ops, more...)

	more, err = stripLocalFromFields(st, permissionsC, "_id", "subject-global-key")
	if err != nil {
		return err
	}
	ops = append(ops, more...)

	more, err = stripLocalFromFields(st, modelUserLastConnectionC, "_id", "user")
	if err != nil {
		return err
	}
	ops = append(ops, more...)
	return st.runRawTransaction(ops)
}

func stripLocalFromFields(st *State, collName string, fields ...string) ([]txn.Op, error) {
	coll, closer := st.getRawCollection(collName)
	defer closer()
	upgradesLogger.Infof("migrating document fields of the %s collection", collName)

	iter := coll.Find(nil).Iter()
	defer iter.Close()
	var ops []txn.Op
	var doc bson.D
	for iter.Next(&doc) {
		// Get a copy of the current doc id so we can see if it has changed.
		var newId interface{}
		id, ok := readBsonDField(doc, "_id")
		if ok {
			newId = id
		}

		// Take a copy of the current doc fields.
		newDoc := make(bson.D, len(doc))
		for i, f := range doc {
			newDoc[i] = f
		}

		// Iterate over the fields that need to be updated and
		// record any updates to be made.
		var update bson.D
		for _, field := range fields {
			isId := field == "_id"
			fieldVal, ok := readBsonDField(doc, field)
			if !ok {
				continue
			}
			updatedVal := strings.Replace(fieldVal.(string), "@local", "", -1)
			if err := replaceBsonDField(newDoc, field, updatedVal); err != nil {
				return nil, err
			}
			if isId {
				newId = updatedVal
			} else {
				if fieldVal != updatedVal {
					update = append(update, bson.DocElem{
						"$set", bson.D{{field, updatedVal}},
					})
				}
			}
		}

		// For documents where the id has not changed, we can
		// use an update operation.
		if newId == id {
			if len(update) > 0 {
				ops = append(ops, txn.Op{
					C:      collName,
					Id:     id,
					Assert: txn.DocExists,
					Update: update,
				})
			}
		} else {
			// Where the id has changed, we need to remove the old and
			// insert the new document.
			ops = append(ops, []txn.Op{{
				C:      collName,
				Id:     id,
				Assert: txn.DocExists,
				Remove: true,
			}, {
				C:      collName,
				Id:     newId,
				Assert: txn.DocMissing,
				Insert: newDoc,
			}}...)
		}
	}
	if err := iter.Err(); err != nil {
		return nil, errors.Trace(err)
	}
	return ops, nil
}

func DropOldLogIndex(st *State) error {
	// If the log collection still has the old e,t index, remove it.
	key := []string{"e", "t"}
	db := st.MongoSession().DB(logsDB)
	collection := db.C(logsC)
	err := collection.DropIndex(key...)
	if err == nil {
		return nil
	}
	if queryErr, ok := err.(*mgo.QueryError); ok {
		if queryErr.Code == 0 && strings.HasPrefix(queryErr.Message, "index not found") {
			return nil
		}
	}
	return errors.Trace(err)
}
<commit_msg>Don't check the error code, apparently it changes<commit_after>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package state

import (
	"strings"

	"github.com/juju/errors"
	"github.com/juju/loggo"
	"gopkg.in/juju/names.v2"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"gopkg.in/mgo.v2/txn"
)

var upgradesLogger = loggo.GetLogger("juju.state.upgrade")

// runForAllModelStates will run runner function for every model passing a state
// for that model.
func runForAllModelStates(st *State, runner func(st *State) error) error {
	models, closer := st.getCollection(modelsC)
	defer closer()

	var modelDocs []bson.M
	err := models.Find(nil).Select(bson.M{"_id": 1}).All(&modelDocs)
	if err != nil {
		return errors.Annotate(err, "failed to read models")
	}

	for _, modelDoc := range modelDocs {
		modelUUID := modelDoc["_id"].(string)
		envSt, err := st.ForModel(names.NewModelTag(modelUUID))
		if err != nil {
			return errors.Annotatef(err, "failed to open model %q", modelUUID)
		}
		defer envSt.Close()
		if err := runner(envSt); err != nil {
			return errors.Annotatef(err, "model UUID %q", modelUUID)
		}
	}
	return nil
}

// readBsonDField returns the value of a given field in a bson.D.
func readBsonDField(d bson.D, name string) (interface{}, bool) {
	for i := range d {
		field := &d[i]
		if field.Name == name {
			return field.Value, true
		}
	}
	return nil, false
}

// replaceBsonDField replaces a field in bson.D.
func replaceBsonDField(d bson.D, name string, value interface{}) error {
	for i, field := range d {
		if field.Name == name {
			newField := field
			newField.Value = value
			d[i] = newField
			return nil
		}
	}
	return errors.NotFoundf("field %q", name)
}

// RenameAddModelPermission renames any permissions called addmodel to add-model.
func RenameAddModelPermission(st *State) error {
	coll, closer := st.getRawCollection(permissionsC)
	defer closer()
	upgradesLogger.Infof("migrating addmodel permission")

	iter := coll.Find(bson.M{"access": "addmodel"}).Iter()
	defer iter.Close()
	var ops []txn.Op
	var doc bson.M
	for iter.Next(&doc) {
		id, ok := doc["_id"]
		if !ok {
			return errors.New("no id found in permission doc")
		}

		ops = append(ops, txn.Op{
			C:      permissionsC,
			Id:     id,
			Assert: txn.DocExists,
			Update: bson.D{{"$set", bson.D{{"access", "add-model"}}}},
		})
	}
	if err := iter.Err(); err != nil {
		return errors.Trace(err)
	}
	return st.runRawTransaction(ops)
}

// StripLocalUserDomain removes any @local suffix from any relevant document field values.
func StripLocalUserDomain(st *State) error {
	var ops []txn.Op
	more, err := stripLocalFromFields(st, cloudCredentialsC, "_id", "owner")
	if err != nil {
		return err
	}
	ops = append(ops, more...)

	more, err = stripLocalFromFields(st, modelsC, "owner", "cloud-credential")
	if err != nil {
		return err
	}
	ops = append(ops, more...)

	more, err = stripLocalFromFields(st, usermodelnameC, "_id")
	if err != nil {
		return err
	}
	ops = append(ops, more...)

	more, err = stripLocalFromFields(st, controllerUsersC, "_id", "user", "createdby")
	if err != nil {
		return err
	}
	ops = append(ops, more...)

	more, err = stripLocalFromFields(st, modelUsersC, "_id", "user", "createdby")
	if err != nil {
		return err
	}
	ops = append(ops, more...)

	more, err = stripLocalFromFields(st, permissionsC, "_id", "subject-global-key")
	if err != nil {
		return err
	}
	ops = append(ops, more...)

	more, err = stripLocalFromFields(st, modelUserLastConnectionC, "_id", "user")
	if err != nil {
		return err
	}
	ops = append(ops, more...)
	return st.runRawTransaction(ops)
}

func stripLocalFromFields(st *State, collName string, fields ...string) ([]txn.Op, error) {
	coll, closer := st.getRawCollection(collName)
	defer closer()
	upgradesLogger.Infof("migrating document fields of the %s collection", collName)

	iter := coll.Find(nil).Iter()
	defer iter.Close()
	var ops []txn.Op
	var doc bson.D
	for iter.Next(&doc) {
		// Get a copy of the current doc id so we can see if it has changed.
		var newId interface{}
		id, ok := readBsonDField(doc, "_id")
		if ok {
			newId = id
		}

		// Take a copy of the current doc fields.
		newDoc := make(bson.D, len(doc))
		for i, f := range doc {
			newDoc[i] = f
		}

		// Iterate over the fields that need to be updated and
		// record any updates to be made.
		var update bson.D
		for _, field := range fields {
			isId := field == "_id"
			fieldVal, ok := readBsonDField(doc, field)
			if !ok {
				continue
			}
			updatedVal := strings.Replace(fieldVal.(string), "@local", "", -1)
			if err := replaceBsonDField(newDoc, field, updatedVal); err != nil {
				return nil, err
			}
			if isId {
				newId = updatedVal
			} else {
				if fieldVal != updatedVal {
					update = append(update, bson.DocElem{
						"$set", bson.D{{field, updatedVal}},
					})
				}
			}
		}

		// For documents where the id has not changed, we can
		// use an update operation.
		if newId == id {
			if len(update) > 0 {
				ops = append(ops, txn.Op{
					C:      collName,
					Id:     id,
					Assert: txn.DocExists,
					Update: update,
				})
			}
		} else {
			// Where the id has changed, we need to remove the old and
			// insert the new document.
			ops = append(ops, []txn.Op{{
				C:      collName,
				Id:     id,
				Assert: txn.DocExists,
				Remove: true,
			}, {
				C:      collName,
				Id:     newId,
				Assert: txn.DocMissing,
				Insert: newDoc,
			}}...)
		}
	}
	if err := iter.Err(); err != nil {
		return nil, errors.Trace(err)
	}
	return ops, nil
}

func DropOldLogIndex(st *State) error {
	// If the log collection still has the old e,t index, remove it.
	key := []string{"e", "t"}
	db := st.MongoSession().DB(logsDB)
	collection := db.C(logsC)
	err := collection.DropIndex(key...)
	if err == nil {
		return nil
	}
	if queryErr, ok := err.(*mgo.QueryError); ok {
		if strings.HasPrefix(queryErr.Message, "index not found") {
			return nil
		}
	}
	return errors.Trace(err)
}
<|endoftext|>


<commit_before>// Copyright 2013, Cong Ding. All rights reserved.
//
// 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.
//
// author: Cong Ding <dinggnu@gmail.com>

package stun

import (
	"encoding/binary"
	"hash/crc32"
	"net"
)

type attribute struct {
	types  uint16
	length uint16
	value  []byte
}

func newAttribute(types uint16, value []byte) *attribute {
	a := new(attribute)
	a.types = types
	a.value = padding(value)
	a.length = uint16(len(a.value))
	return a
}

func newFingerprintAttribute(packet *packet) *attribute {
	crc := crc32.ChecksumIEEE(packet.bytes()) ^ fingerprint
	buf := make([]byte, 4)
	binary.BigEndian.PutUint32(buf, crc)
	return newAttribute(attribute_fingerprint, buf)
}

func newSoftwareAttribute(packet *packet, name string) *attribute {
	return newAttribute(attribute_SOFTWARE, []byte(name))
}

func newChangeReqAttribute(packet *packet, changeIp bool, changePort bool) *attribute {
	value := make([]byte, 4)
	if changeIp {
		value[3] |= 0x04
	}
	if changePort {
		value[3] |= 0x02
	}
	return newAttribute(attribute_CHANGE_REQUEST, value)
}

func (v *attribute) xorMappedAddr() *Host {
	cookie := make([]byte, 4)
	binary.BigEndian.PutUint32(cookie, magicCookie)
	xorIp := make([]byte, 16)
	for i := 0; i < len(v.value)-4; i++ {
		xorIp[i] = v.value[i+4] ^ cookie[i]
	}
	port := binary.BigEndian.Uint16(v.value[2:4])
	return &Host{binary.BigEndian.Uint16(v.value[0:2]),
		net.IP(xorIp).String(), port ^ (magicCookie >> 32)}
}

func (v *attribute) address() *Host {
	h := new(Host)
	h.family = binary.BigEndian.Uint16(v.value[0:2])
	h.port = binary.BigEndian.Uint16(v.value[2:4])
	h.ip = net.IP(v.value[4:]).String()
	return h
}
<commit_msg>Fix bug where sometimes IPv4 addresses get displayed as IPv6<commit_after>// Copyright 2013, Cong Ding. All rights reserved.
//
// 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.
//
// author: Cong Ding <dinggnu@gmail.com>

package stun

import (
	"encoding/binary"
	"hash/crc32"
	"net"
)

type attribute struct {
	types  uint16
	length uint16
	value  []byte
}

func newAttribute(types uint16, value []byte) *attribute {
	a := new(attribute)
	a.types = types
	a.value = padding(value)
	a.length = uint16(len(a.value))
	return a
}

func newFingerprintAttribute(packet *packet) *attribute {
	crc := crc32.ChecksumIEEE(packet.bytes()) ^ fingerprint
	buf := make([]byte, 4)
	binary.BigEndian.PutUint32(buf, crc)
	return newAttribute(attribute_fingerprint, buf)
}

func newSoftwareAttribute(packet *packet, name string) *attribute {
	return newAttribute(attribute_SOFTWARE, []byte(name))
}

func newChangeReqAttribute(packet *packet, changeIp bool, changePort bool) *attribute {
	value := make([]byte, 4)
	if changeIp {
		value[3] |= 0x04
	}
	if changePort {
		value[3] |= 0x02
	}
	return newAttribute(attribute_CHANGE_REQUEST, value)
}

func (v *attribute) xorMappedAddr() *Host {
	cookie := make([]byte, 4)
	binary.BigEndian.PutUint32(cookie, magicCookie)
	xorIp := make([]byte, 16)
	for i := 0; i < len(v.value)-4; i++ {
		xorIp[i] = v.value[i+4] ^ cookie[i]
	}
	family := binary.BigEndian.Uint16(v.value[0:2])
	port := binary.BigEndian.Uint16(v.value[2:4])

	// Truncate if IPv4, otherwise net.IP sometimes renders it as an IPv6 address.
	if family == attribute_FAMILY_IPV4 {
		xorIp = xorIp[:4]
	}

	return &Host{family, net.IP(xorIp).String(), port ^ (magicCookie >> 32)}
}

func (v *attribute) address() *Host {
	h := new(Host)
	h.family = binary.BigEndian.Uint16(v.value[0:2])
	h.port = binary.BigEndian.Uint16(v.value[2:4])

	// Truncate if IPv4, otherwise net.IP sometimes renders it as an IPv6 address.
	if h.family == attribute_FAMILY_IPV4 {
		v.value = v.value[:8]
	}
	h.ip = net.IP(v.value[4:]).String()
	return h
}
<|endoftext|>


<commit_before>package builds

import (
	"net/http"
	"sync"
	"time"

	"github.com/winston-ci/redgreen/logbuffer"
)

type Build struct {
	Guid        string            `json:"guid"`
	CreatedAt   time.Time         `json:"created_at"`
	Image       string            `json:"image"`
	Path        string            `json:"path"`
	Script      string            `json:"script"`
	Environment map[string]string `json:"environment"`
	Status      string            `json:"status"`

	bits        chan *http.Request `json:"-"`
	servingBits *sync.WaitGroup

	logBuffer *logbuffer.LogBuffer
}

type BuildResult struct {
	Status string `json:"status"`
}
<commit_msg>remove redundant json blacklist tag<commit_after>package builds

import (
	"net/http"
	"sync"
	"time"

	"github.com/winston-ci/redgreen/logbuffer"
)

type Build struct {
	Guid        string            `json:"guid"`
	CreatedAt   time.Time         `json:"created_at"`
	Image       string            `json:"image"`
	Path        string            `json:"path"`
	Script      string            `json:"script"`
	Environment map[string]string `json:"environment"`
	Status      string            `json:"status"`

	bits        chan *http.Request
	servingBits *sync.WaitGroup

	logBuffer *logbuffer.LogBuffer
}

type BuildResult struct {
	Status string `json:"status"`
}
<|endoftext|>


<commit_before>package vfmd

import (
	"bytes"
	"regexp"
)

// TODO(akavel): add tests for blocks

type BlockSplitter struct {
}

func (b *BlockSplitter) WriteLine(line []byte) error {
	// TODO(akavel): NIY
	return nil
}

func (b *BlockSplitter) Close() error {
	// TODO(akavel): NIY
	return nil
}

type Line []byte

func (line Line) isBlank() bool {
	return len(bytes.Trim(line, " \t")) == 0
}
func (line Line) hasNonSpaceInPrefix(n int) bool {
	for i := 0; i < n && i < len(line); i++ {
		if line[i] != ' ' {
			return true
		}
	}
	return false
}
func (line Line) hasFourSpacePrefix() bool {
	return bytes.HasPrefix(line, []byte("    "))
}

type BlockDetector interface {
	// Detect checks if the provided start line and optionally second line
	// signify start of the particular block kind.  If unsuccessful, 0 and
	// 0 should be returned.  If successful, at least one of the returned
	// numbers should be positive.  Consume is number of lines that sure
	// belong to the block, and won't be needed in any subsequent calls to
	// Continue.  Pause is number of lines that may be still needed in
	// subsequent calls to Continue, and/or aren't yet fully confirmed to
	// belong to the block.
	//
	// Note: it is not allowed for Detect to report 0 lines to consume and
	// then for Continue to reject all the paused lines.
	//
	// Note: second==nil means end of file/stream
	Detect(start, second Line) (consume, pause int)
	// Continue checks if the specified paused lines and next line may
	// belong to the block, as reported started by Detect.  If any of the
	// lines is detected to be of a next block, Continue should report:
	// consume <= len(paused), and nothing to pause.  Otherwise, Continue
	// must report: consume+pause == len(paused)+1.
	//
	// Number of paused lines passed to Continue will always be equal to
	// value reported from previous Detect or Continue.
	//
	// Note: next==nil means end of file/stream; however, Continue will
	// never be called with next==nil if previous call to
	// Detect/Continue didn't report any lines to pause.
	Continue(paused []Line, next Line) (consume, pause int)
}

var (
	reUnorderedList  = regexp.MustCompile(`^( *[\*\-\+] +)[^ ]`)
	reOrderedList    = regexp.MustCompile(`^( *([0-9]+)\. +)[^ ]`)
	reHorizontalRule = regexp.MustCompile(`^ *((\* *\* *\* *[\* ]*)|(\- *\- *\- *[\- ]*)|(_ *_ *_ *[_ ]*))$`)
)

type BlockNeverContinue struct{}

func (BlockNeverContinue) Continue([]Line, Line) (consume, pause int) { return 0, 0 }

// static assertion of BlockDetector interface implementation by the listed types
var _ []BlockDetector = []BlockDetector{
	&NullBlock{},
	&ReferenceResolutionBlock{},
	&SetextHeaderBlock{},
	&CodeBlock{},
	&AtxHeaderBlock{},
	&QuoteBlock{},
	&HorizontalRuleBlock{},
	&UnorderedListBlock{},
	&OrderedListBlock{},
	&ParagraphBlock{},
}

type NullBlock struct{ BlockNeverContinue }

func (b *NullBlock) Detect(start, second Line) (consume, pause int) {
	if start.isBlank() {
		return 1, 0
	}
	return 0, 0
}

type ReferenceResolutionBlock struct {
	BlockNeverContinue
	unprocessedReferenceID        []byte
	refValueSequence              []byte
	unprocessedUrl                []byte
	refDefinitionTrailingSequence []byte
}

func (b *ReferenceResolutionBlock) Detect(start, second Line) (consume, pause int) {
	if start.hasFourSpacePrefix() {
		return 0, 0
	}
	// TODO(akavel): move the regexp out of function, for speed (or cache it?)
	re := regexp.MustCompile(`^ *\[(([^\\\[\]\!]|\\.|\![^\[])*((\!\[([^\\\[\]]|\\.)*\](\[([^\\\[\]]|\\.)*\])?)?([^\\\[\]]|\\.)*)*)\] *:(.*)$`)
	m := re.FindSubmatch(start)
	if len(m) == 0 {
		return 0, 0
	}
	b.unprocessedReferenceID = m[1]
	b.refValueSequence = m[9] // TODO(akavel): verify if right one
	re = regexp.MustCompile(`^ *([^ \<\>]+|\<[^\<\>]*\>)( .*)?$`)
	m = re.FindSubmatch(b.refValueSequence)
	if len(m) == 0 {
		return 0, 0
	}
	b.unprocessedUrl = m[1]
	b.refDefinitionTrailingSequence = m[2]

	// Detected ok. Now check if 1 or 2 lines.
	re = regexp.MustCompile(`^ +("(([^"\\]|\\.)*)"|'(([^'\\]|\\.)*)'|\(([^\\\(\)]|\\.)*\)) *$`)
	if bytes.IndexAny(b.refDefinitionTrailingSequence, " ") == -1 &&
		second != nil &&
		re.Match(second) {
		return 2, 0
	} else {
		return 1, 0
	}
}

type SetextHeaderBlock struct{ BlockNeverContinue }

func (b *SetextHeaderBlock) Detect(start, second Line) (consume, pause int) {
	if second == nil {
		return 0, 0
	}
	re := regexp.MustCompile(`^(-+|=+) *$`)
	if re.Match(second) {
		return 2, 0
	}
	return 0, 0
}

type CodeBlock struct{}

func (b *CodeBlock) Detect(start, second Line) (consume, pause int) {
	if start.hasFourSpacePrefix() {
		return 1, 0
	}
	return 0, 0
}
func (b *CodeBlock) Continue(paused []Line, next Line) (consume, pause int) {
	// FIXME(akavel): handle next==nil !!!
	if next == nil {
		return 0, 0
		// note: len(paused)==1 if prev was blank, so we can ditch it anyway
	}
	// TODO(akavel): verify it's coded ok, it was converted from a different approach
	switch {
	// previous was blank, next is not tab-indented. Reject both.
	case len(paused) == 1 && !next.hasFourSpacePrefix():
		return 0, 0
	case next.isBlank():
		return len(paused), 1 // note: only case where we pause a line
	case next.hasFourSpacePrefix():
		return len(paused) + 1, 0
	// next not blank & not indented. End the block.
	default:
		return len(paused), 0
	}
}

type AtxHeaderBlock struct{ BlockNeverContinue }

func (b *AtxHeaderBlock) Detect(start, second Line) (consume, pause int) {
	if bytes.HasPrefix(start, []byte("#")) {
		return 1, 0
	}
	return 0, 0
}

type QuoteBlock struct{}

func (b *QuoteBlock) Detect(start, second Line) (consume, pause int) {
	ltrim := bytes.TrimLeft(start, " ")
	if len(ltrim) > 0 && ltrim[0] == '>' {
		return 0, 1
	}
	return 0, 0
}
func (b *QuoteBlock) Continue(paused []Line, next Line) (consume, pause int) {
	// TODO(akavel): verify it's coded ok, it was converted from a different approach
	if next == nil {
		return len(paused), 0
	}
	if paused[0].isBlank() {
		if next.isBlank() ||
			next.hasFourSpacePrefix() ||
			bytes.TrimLeft(next, " ")[0] != '>' {
			return len(paused), 0
		}
	} else if !next.hasFourSpacePrefix() &&
		reHorizontalRule.Match(next) {
		return len(paused), 0
	}
	return len(paused), 1
}

type HorizontalRuleBlock struct{ BlockNeverContinue }

func (b *HorizontalRuleBlock) Detect(start, second Line) (consume, pause int) {
	if reHorizontalRule.Match(start) {
		return 1, 0
	}
	return 0, 0
}

type UnorderedListBlock struct {
	Starter []byte
}

func (b *UnorderedListBlock) Detect(start, second Line) (consume, pause int) {
	m := reUnorderedList.FindSubmatch(start)
	if m == nil {
		return 0, 0
	}
	b.Starter = m[1]
	return 0, 1
}
func (b *UnorderedListBlock) Continue(paused []Line, next Line) (consume, pause int) {
	if next == nil {
		return len(paused), 0
	}

	if paused[0].isBlank() {
		if next.isBlank() {
			return len(paused), 0
		}
		if !bytes.HasPrefix(next, b.Starter) &&
			// FIXME(akavel): spec refers to runes ("characters"), not bytes; fix this everywhere
			next.hasNonSpaceInPrefix(len(b.Starter)) {
			return len(paused), 0
		}
	} else {
		if !bytes.HasPrefix(next, b.Starter) &&
			next.hasNonSpaceInPrefix(len(b.Starter)) &&
			!next.hasFourSpacePrefix() &&
			(reUnorderedList.Match(next) ||
				reOrderedList.Match(next) ||
				reHorizontalRule.Match(next)) {
			return len(paused), 0
		}
	}
	return len(paused), 1
}

type OrderedListBlock struct {
	Starter []byte
}

func (b *OrderedListBlock) Detect(start, second Line) (consume, pause int) {
	m := reOrderedList.FindSubmatch(start)
	if m == nil {
		return 0, 0
	}
	b.Starter = m[1]
	return 0, 1
}
func (b *OrderedListBlock) Continue(paused []Line, next Line) (consume, pause int) {
	if next == nil {
		return len(paused), 0
	}

	if paused[0].isBlank() {
		if next.isBlank() {
			return len(paused), 0
		}
		if !reOrderedList.Match(next) &&
			next.hasNonSpaceInPrefix(len(b.Starter)) {
			return len(paused), 0
		}
	} else {
		if !reOrderedList.Match(next) &&
			next.hasNonSpaceInPrefix(len(b.Starter)) &&
			!next.hasFourSpacePrefix() &&
			(reUnorderedList.Match(next) ||
				reHorizontalRule.Match(next)) {
			return len(paused), 0
		}
	}
	return len(paused), 1
}

type ParagraphBlock struct {
	// NOTE: below fields must be set appropriately when creating a ParagraphBlock
	IsInBlockquote bool
	IsInList       bool
}

func (b *ParagraphBlock) Detect(start, second Line) (consume, pause int) {
	return 0, 1
}
func (b *ParagraphBlock) Continue(paused []Line, next Line) (consume, pause int) {
	if next == nil {
		return len(paused), 0
	}
	// TODO(akavel): support HTML parser & related interactions [#paragraph-line-sequence]
	if paused[0].isBlank() {
		return len(paused), 0
	}
	if !next.hasFourSpacePrefix() {
		if reHorizontalRule.Match(next) ||
			(b.IsInBlockquote && bytes.HasPrefix(bytes.TrimLeft(next, " "), []byte(">"))) ||
			(b.IsInList && reOrderedList.Match(next)) ||
			(b.IsInList && reUnorderedList.Match(next)) {
			return len(paused), 0
		}
	}
	return len(paused), 1
}
<commit_msg>some temporary notes<commit_after>package vfmd

import (
	"bytes"
	"regexp"
)

// TODO(akavel): add tests for blocks

type BlockSplitter struct {
}

func (b *BlockSplitter) WriteLine(line []byte) error {
	// TODO(akavel): NIY
	return nil
}

func (b *BlockSplitter) Close() error {
	// TODO(akavel): NIY
	return nil
}

type Line []byte

func (line Line) isBlank() bool {
	return len(bytes.Trim(line, " \t")) == 0
}
func (line Line) hasNonSpaceInPrefix(n int) bool {
	for i := 0; i < n && i < len(line); i++ {
		if line[i] != ' ' {
			return true
		}
	}
	return false
}
func (line Line) hasFourSpacePrefix() bool {
	return bytes.HasPrefix(line, []byte("    "))
}

type BlockDetector interface {
	// Detect checks if the provided start line and optionally second line
	// signify start of the particular block kind.  If unsuccessful, 0 and
	// 0 should be returned.  If successful, at least one of the returned
	// numbers should be positive.  Consume is number of lines that sure
	// belong to the block, and won't be needed in any subsequent calls to
	// Continue.  Pause is number of lines that may be still needed in
	// subsequent calls to Continue, and/or aren't yet fully confirmed to
	// belong to the block.
	//
	// Note: it is not allowed for Detect to report 0 lines to consume and
	// then for Continue to reject all the paused lines.
	//
	// Note: second==nil means end of file/stream
	Detect(start, second Line) (consume, pause int)
	// Continue checks if the specified paused lines and next line may
	// belong to the block, as reported started by Detect.  If any of the
	// lines is detected to be of a next block, Continue should report:
	// consume <= len(paused), and nothing to pause.  Otherwise, Continue
	// must report: consume+pause == len(paused)+1.
	//
	// Number of paused lines passed to Continue will always be equal to
	// value reported from previous Detect or Continue.
	//
	// Note: next==nil means end of file/stream; however, Continue will
	// never be called with next==nil if previous call to
	// Detect/Continue didn't report any lines to pause.
	Continue(paused []Line, next Line) (consume, pause int)
}

var (
	reUnorderedList  = regexp.MustCompile(`^( *[\*\-\+] +)[^ ]`)
	reOrderedList    = regexp.MustCompile(`^( *([0-9]+)\. +)[^ ]`)
	reHorizontalRule = regexp.MustCompile(`^ *((\* *\* *\* *[\* ]*)|(\- *\- *\- *[\- ]*)|(_ *_ *_ *[_ ]*))$`)
)

type BlockNeverContinue struct{}

func (BlockNeverContinue) Continue([]Line, Line) (consume, pause int) { return 0, 0 }

// static assertion of BlockDetector interface implementation by the listed types
var _ []BlockDetector = []BlockDetector{
	&NullBlock{},
	&ReferenceResolutionBlock{},
	&SetextHeaderBlock{},
	&CodeBlock{},
	&AtxHeaderBlock{},
	&QuoteBlock{},
	&HorizontalRuleBlock{},
	&UnorderedListBlock{},
	&OrderedListBlock{},
	&ParagraphBlock{},
}

type NullBlock struct{ BlockNeverContinue }

func (b *NullBlock) Detect(start, second Line) (consume, pause int) {
	if start.isBlank() {
		return 1, 0
	}
	return 0, 0
}

type ReferenceResolutionBlock struct {
	BlockNeverContinue
	unprocessedReferenceID        []byte
	refValueSequence              []byte
	unprocessedUrl                []byte
	refDefinitionTrailingSequence []byte
}

func (b *ReferenceResolutionBlock) Detect(start, second Line) (consume, pause int) {
	if start.hasFourSpacePrefix() {
		return 0, 0
	}
	// TODO(akavel): move the regexp out of function, for speed (or cache it?)
	re := regexp.MustCompile(`^ *\[(([^\\\[\]\!]|\\.|\![^\[])*((\!\[([^\\\[\]]|\\.)*\](\[([^\\\[\]]|\\.)*\])?)?([^\\\[\]]|\\.)*)*)\] *:(.*)$`)
	m := re.FindSubmatch(start)
	if len(m) == 0 {
		return 0, 0
	}
	b.unprocessedReferenceID = m[1]
	b.refValueSequence = m[9] // TODO(akavel): verify if right one
	re = regexp.MustCompile(`^ *([^ \<\>]+|\<[^\<\>]*\>)( .*)?$`)
	m = re.FindSubmatch(b.refValueSequence)
	if len(m) == 0 {
		return 0, 0
	}
	b.unprocessedUrl = m[1]
	b.refDefinitionTrailingSequence = m[2]

	// Detected ok. Now check if 1 or 2 lines.
	re = regexp.MustCompile(`^ +("(([^"\\]|\\.)*)"|'(([^'\\]|\\.)*)'|\(([^\\\(\)]|\\.)*\)) *$`)
	if bytes.IndexAny(b.refDefinitionTrailingSequence, " ") == -1 &&
		second != nil &&
		re.Match(second) {
		return 2, 0
	} else {
		return 1, 0
	}
}

type SetextHeaderBlock struct{ BlockNeverContinue }

func (b *SetextHeaderBlock) Detect(start, second Line) (consume, pause int) {
	if second == nil {
		return 0, 0
	}
	re := regexp.MustCompile(`^(-+|=+) *$`)
	if re.Match(second) {
		return 2, 0
	}
	return 0, 0
}

type CodeBlock struct{}

func (b *CodeBlock) Detect(start, second Line) (consume, pause int) {
	if start.hasFourSpacePrefix() {
		return 1, 0
	}
	return 0, 0
}
func (b *CodeBlock) Continue(paused []Line, next Line) (consume, pause int) {
	// FIXME(akavel): handle next==nil !!!
	if next == nil {
		return 0, 0
		// note: len(paused)==1 if prev was blank, so we can ditch it anyway
	}
	// TODO(akavel): verify it's coded ok, it was converted from a different approach
	switch {
	// previous was blank, next is not tab-indented. Reject both.
	case len(paused) == 1 && !next.hasFourSpacePrefix():
		return 0, 0
	case next.isBlank():
		return len(paused), 1 // note: only case where we pause a line
	case next.hasFourSpacePrefix():
		return len(paused) + 1, 0
	// next not blank & not indented. End the block.
	default:
		return len(paused), 0
	}
}

type AtxHeaderBlock struct{ BlockNeverContinue }

func (b *AtxHeaderBlock) Detect(start, second Line) (consume, pause int) {
	if bytes.HasPrefix(start, []byte("#")) {
		return 1, 0
	}
	return 0, 0
}

type QuoteBlock struct{}

func (b *QuoteBlock) Detect(start, second Line) (consume, pause int) {
	ltrim := bytes.TrimLeft(start, " ")
	if len(ltrim) > 0 && ltrim[0] == '>' {
		return 0, 1
	}
	return 0, 0
}
func (b *QuoteBlock) Continue(paused []Line, next Line) (consume, pause int) {
	// TODO(akavel): verify it's coded ok, it was converted from a different approach
	if next == nil {
		return len(paused), 0
	}
	if paused[0].isBlank() {
		if next.isBlank() ||
			next.hasFourSpacePrefix() ||
			bytes.TrimLeft(next, " ")[0] != '>' {
			return len(paused), 0
		}
	} else if !next.hasFourSpacePrefix() &&
		reHorizontalRule.Match(next) {
		return len(paused), 0
	}
	return len(paused), 1
}

type HorizontalRuleBlock struct{ BlockNeverContinue }

func (b *HorizontalRuleBlock) Detect(start, second Line) (consume, pause int) {
	if reHorizontalRule.Match(start) {
		return 1, 0
	}
	return 0, 0
}

type UnorderedListBlock struct {
	Starter []byte
}

func (b *UnorderedListBlock) Detect(start, second Line) (consume, pause int) {
	m := reUnorderedList.FindSubmatch(start)
	if m == nil {
		return 0, 0
	}
	b.Starter = m[1]
	return 0, 1
}
func (b *UnorderedListBlock) Continue(paused []Line, next Line) (consume, pause int) {
	if next == nil {
		return len(paused), 0
	}

	if paused[0].isBlank() {
		if next.isBlank() {
			return len(paused), 0
		}
		if !bytes.HasPrefix(next, b.Starter) &&
			// FIXME(akavel): spec refers to runes ("characters"), not bytes; fix this everywhere
			next.hasNonSpaceInPrefix(len(b.Starter)) {
			return len(paused), 0
		}
	} else {
		if !bytes.HasPrefix(next, b.Starter) &&
			next.hasNonSpaceInPrefix(len(b.Starter)) &&
			!next.hasFourSpacePrefix() &&
			(reUnorderedList.Match(next) ||
				reOrderedList.Match(next) ||
				reHorizontalRule.Match(next)) {
			return len(paused), 0
		}
	}
	return len(paused), 1
}

type OrderedListBlock struct {
	Starter []byte
}

func (b *OrderedListBlock) Detect(start, second Line) (consume, pause int) {
	m := reOrderedList.FindSubmatch(start)
	if m == nil {
		return 0, 0
	}
	b.Starter = m[1]
	return 0, 1
}
func (b *OrderedListBlock) Continue(paused []Line, next Line) (consume, pause int) {
	if next == nil {
		return len(paused), 0
	}

	if paused[0].isBlank() {
		if next.isBlank() {
			return len(paused), 0
		}
		if !reOrderedList.Match(next) &&
			next.hasNonSpaceInPrefix(len(b.Starter)) {
			return len(paused), 0
		}
	} else {
		if !reOrderedList.Match(next) &&
			next.hasNonSpaceInPrefix(len(b.Starter)) &&
			!next.hasFourSpacePrefix() &&
			(reUnorderedList.Match(next) ||
				reHorizontalRule.Match(next)) {
			return len(paused), 0
		}
	}
	return len(paused), 1
}

type ParagraphBlock struct {
	// NOTE: below fields must be set appropriately when creating a ParagraphBlock
	IsInBlockquote bool
	IsInList       bool
}

func (b *ParagraphBlock) Detect(start, second Line) (consume, pause int) {
	return 0, 1
}
func (b *ParagraphBlock) Continue(paused []Line, next Line) (consume, pause int) {
	if next == nil {
		return len(paused), 0
	}
	// TODO(akavel): support HTML parser & related interactions [#paragraph-line-sequence]
	if paused[0].isBlank() {
		return len(paused), 0
	}
	if !next.hasFourSpacePrefix() {
		if reHorizontalRule.Match(next) ||
			(b.IsInBlockquote && bytes.HasPrefix(bytes.TrimLeft(next, " "), []byte(">"))) ||
			(b.IsInList && reOrderedList.Match(next)) ||
			(b.IsInList && reUnorderedList.Match(next)) {
			return len(paused), 0
		}
	}
	return len(paused), 1
}

/*
NOTES:

AtxHeaderBlock
 -> text-span-sequence

SetextHeaderBlock
 -> text-span-sequence

QuoteBlock
 -> process lines (strip certain prefix bytes)
  -> detect[defaults..., ParagraphBlock{InQuote=1}]

UnorderedListBlock
 -> detect[UnorderedItemBlock]
  -> process lines (strip certain prefix bytes)
   -> detect[defaults..., ParagraphBlock{InList=1}]

OrderedListBlock
 -> detect[OrderedItemBlock]
  -> process lines (strip certain prefix bytes)
   -> detect[defaults..., ParagraphBlock{InList=1}]

ParagraphBlock
 -> join & trim
  -> process as text-span-sequence

Block{
	block.Detector
	NLines int
	Nested []Block
}

// This function is guaranteed to be run after the line has been reported by
// Detect or Continue as consumed, and after all preceding lines were
// PostProcessed, and before any subsequent lines were PostProcessed.
PostProcess(Line)
*/
<|endoftext|>


<commit_before>// Copyright 2021 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 main

import (
	"flag"
	"fmt"
	"log"
	"net"

	"github.com/bazelbuild/remote-apis-sdks/go/pkg/fakes"
	regrpc "github.com/bazelbuild/remote-apis/build/bazel/remote/execution/v2"
	bsgrpc "google.golang.org/genproto/googleapis/bytestream"
	"google.golang.org/grpc"

	"go.chromium.org/luci/common/system/signals"
)

func main() {
	port := flag.Int("port", 9000, "local port number used by fake server")
	flag.Parse()

	s := grpc.NewServer()
	cas := fakes.NewCAS()
	ex := &fakes.Exec{}
	bsgrpc.RegisterByteStreamServer(s, cas)
	regrpc.RegisterContentAddressableStorageServer(s, cas)
	regrpc.RegisterCapabilitiesServer(s, ex)

	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
	if err != nil {
		log.Fatalf("failed to listen: %v\n", err)
	}
	log.Printf("listening tcp port %d\n", *port)

	defer signals.HandleInterrupt(func() {
		log.Println("shutting down fake CAS gRPC server...")
		s.GracefulStop()
	})()

	log.Println("starting CAS fake server...")
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve fake CAS gRPC server: %v\n", err)
	}
}
<commit_msg>fakecas: dump listening address<commit_after>// Copyright 2021 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 main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"os"

	"github.com/bazelbuild/remote-apis-sdks/go/pkg/fakes"
	regrpc "github.com/bazelbuild/remote-apis/build/bazel/remote/execution/v2"
	bsgrpc "google.golang.org/genproto/googleapis/bytestream"
	"google.golang.org/grpc"

	"go.chromium.org/luci/common/system/signals"
)

func main() {
	port := flag.Int("port", 9000, "local port number used by fake server")
	addrFile := flag.String("addr-file", "", "dump listening address in this file")
	flag.Parse()

	s := grpc.NewServer()
	cas := fakes.NewCAS()
	ex := &fakes.Exec{}
	bsgrpc.RegisterByteStreamServer(s, cas)
	regrpc.RegisterContentAddressableStorageServer(s, cas)
	regrpc.RegisterCapabilitiesServer(s, ex)

	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
	if err != nil {
		log.Fatalf("failed to listen: %v\n", err)
	}
	log.Printf("listening address: %s\n", lis.Addr())

	if *addrFile != "" {
		if err := os.WriteFile(*addrFile, []byte(lis.Addr().String()), 0600); err != nil {
			log.Fatalf("failed to write addrFile: %v", err)
		}
	}

	defer signals.HandleInterrupt(func() {
		log.Println("shutting down fake CAS gRPC server...")
		s.GracefulStop()
	})()

	log.Println("starting CAS fake server...")
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve fake CAS gRPC server: %v\n", err)
	}
}
<|endoftext|>


<commit_before>// Package upstart provides functions to control upstart jobs.
// Note that this is only usable on systems where upstart is the init system.
package upstart

import (
	"github.com/guelfey/go.dbus"
)

// StartJob starts the specified job.
func StartJob(name string) error {
	job := &job{Name: name}
	return job.StartWithEnv(map[string]string{})
}

// StopJob stops the specified job.
func StopJob(name string) error {
	job := &job{Name: name}
	return job.Stop()
}

// RestartJob restarts the specified job.
func RestartJob(name string) error {
	job := &job{Name: name}
	return job.Restart()
}

// listJobInstances lists the instances of the specified job. Unless configured to run
// as multiple instances, a job has a single instance.
func listJobInstances(name string) ([]string, error) {
	ret := []string{}
	job := &job{Name: name}

	printInst := func(_ *dbus.Conn, inst dbus.ObjectPath) error {
		ret = append(ret, string(inst))
		return nil
	}

	err := job.foreachInstance(printInst)
	return ret, err

}
<commit_msg>Make ListInstances public<commit_after>// Package upstart provides functions to control upstart jobs.
// Note that this is only usable on systems where upstart is the init system.
package upstart

import (
	"github.com/guelfey/go.dbus"
)

// StartJob starts the specified job.
func StartJob(name string) error {
	job := &job{Name: name}
	return job.StartWithEnv(map[string]string{})
}

// StopJob stops the specified job.
func StopJob(name string) error {
	job := &job{Name: name}
	return job.Stop()
}

// RestartJob restarts the specified job.
func RestartJob(name string) error {
	job := &job{Name: name}
	return job.Restart()
}

// ListJobInstances lists the instances of the specified job. Unless configured to run
// as multiple instances, a job has a single instance.
func ListJobInstances(name string) ([]string, error) {
	ret := []string{}
	job := &job{Name: name}

	printInst := func(_ *dbus.Conn, inst dbus.ObjectPath) error {
		ret = append(ret, string(inst))
		return nil
	}

	err := job.foreachInstance(printInst)
	return ret, err

}
<|endoftext|>


<commit_before>package url

import (
	"github.com/pkg/errors"
)

const (
	portMax = 1<<16 - 1
)

func (u *URL) Validate() error {
	// Ensure the protocol is supported.
	if u.Protocol < Protocol_Local || u.Protocol > Protocol_SSH {
		return errors.New("unsupported protocol")
	}

	// Validate that username isn't set for local URLs.
	if u.Protocol == Protocol_Local && u.Username != "" {
		return errors.New("non-empty username for local URL")
	}

	// Validate that hostname isn't set for local URLs and is set for SSH URLs.
	if u.Protocol == Protocol_Local && u.Hostname != "" {
		return errors.New("non-empty hostname for local URL")
	} else if u.Protocol == Protocol_SSH && u.Hostname == "" {
		return errors.New("empty hostname for SSH URL")
	}

	// Ensure that the port is in a valid range. Unfortunately Protocol Buffers
	// doesn't offer a uint16 type.
	if u.Port > portMax {
		return errors.New("port value outside allowed range")
	}

	// Ensure that the path is non-empty.
	if u.Path == "" {
		return errors.New("path is empty")
	}

	// Success.
	return nil
}
<commit_msg>Removed URL validation function.<commit_after><|endoftext|>