<commit_before>package buildkite

import (
	"errors"
	"fmt"
)

// PipelinesService handles communication with the pipeline related
// methods of the buildkite API.
//
// buildkite API docs: https://buildkite.com/docs/api/pipelines
type PipelinesService struct {
	client *Client
}

// CreatePipeline - Create a Pipeline.
type CreatePipeline struct {
	Name       string `json:"name" yaml:"name"`
	Repository string `json:"repository" yaml:"repository"`

	// Either configuration needs to be specified as a yaml string or steps.
	Configuration string `json:"configuration,omitempty" yaml:"configuration,omitempty"`
	Steps         []Step `json:"steps,omitempty" yaml:"steps,omitempty"`

	// Optional fields
	DefaultBranch                   string            `json:"default_branch,omitempty" yaml:"default_branch,omitempty"`
	Description                     string            `json:"description,omitempty" yaml:"description,omitempty"`
	Env                             map[string]string `json:"env,omitempty" yaml:"env,omitempty"`
	ProviderSettings                ProviderSettings  `json:"provider_settings,omitempty" yaml:"provider_settings,omitempty"`
	BranchConfiguration             string            `json:"branch_configuration,omitempty" yaml:"branch_configuration,omitempty"`
	SkipQueuedBranchBuilds          bool              `json:"skip_queued_branch_builds,omitempty" yaml:"skip_queued_branch_builds,omitempty"`
	SkipQueuedBranchBuildsFilter    string            `json:"skip_queued_branch_builds_filter,omitempty" yaml:"skip_queued_branch_builds_filter,omitempty"`
	CancelRunningBranchBuilds       bool              `json:"cancel_running_branch_builds,omitempty" yaml:"cancel_running_branch_builds,omitempty"`
	CancelRunningBranchBuildsFilter string            `json:"cancel_running_branch_builds_filter,omitempty" yaml:"cancel_running_branch_builds_filter,omitempty"`
	TeamUuids                       []string          `json:"team_uuids,omitempty" yaml:"team_uuids,omitempty"`
	ClusterID                       string            `json:"cluster_id,omitempty" yaml:"cluster_id,omitempty"`
}

// Pipeline represents a buildkite pipeline.
type Pipeline struct {
	ID                              *string    `json:"id,omitempty" yaml:"id,omitempty"`
	URL                             *string    `json:"url,omitempty" yaml:"url,omitempty"`
	WebURL                          *string    `json:"web_url,omitempty" yaml:"web_url,omitempty"`
	Name                            *string    `json:"name,omitempty" yaml:"name,omitempty"`
	Slug                            *string    `json:"slug,omitempty" yaml:"slug,omitempty"`
	Repository                      *string    `json:"repository,omitempty" yaml:"repository,omitempty"`
	BuildsURL                       *string    `json:"builds_url,omitempty" yaml:"builds_url,omitempty"`
	BadgeURL                        *string    `json:"badge_url,omitempty" yaml:"badge_url,omitempty"`
	CreatedAt                       *Timestamp `json:"created_at,omitempty" yaml:"created_at,omitempty"`
	ArchivedAt                      *Timestamp `json:"archived_at,omitempty" yaml:"archived_at,omitempty"`
	DefaultBranch                   *string    `json:"default_branch,omitempty" yaml:"default_branch,omitempty"`
	Description                     *string    `json:"description,omitempty" yaml:"description,omitempty"`
	BranchConfiguration             *string    `json:"branch_configuration,omitempty" yaml:"branch_configuration,omitempty"`
	SkipQueuedBranchBuilds          *bool      `json:"skip_queued_branch_builds,omitempty" yaml:"skip_queued_branch_builds,omitempty"`
	SkipQueuedBranchBuildsFilter    *string    `json:"skip_queued_branch_builds_filter,omitempty" yaml:"skip_queued_branch_builds_filter,omitempty"`
	CancelRunningBranchBuilds       *bool      `json:"cancel_running_branch_builds,omitempty" yaml:"cancel_running_branch_builds,omitempty"`
	CancelRunningBranchBuildsFilter *string    `json:"cancel_running_branch_builds_filter,omitempty" yaml:"cancel_running_branch_builds_filter,omitempty"`
	ClusterID                       *string    `json:"cluster_id,omitempty" yaml:"cluster_id,omitempty"`
	Visibility                      *string    `json:"visibility,omitempty" yaml:"visibility,omitempty"`

	ScheduledBuildsCount *int `json:"scheduled_builds_count,omitempty" yaml:"scheduled_builds_count,omitempty"`
	RunningBuildsCount   *int `json:"running_builds_count,omitempty" yaml:"running_builds_count,omitempty"`
	ScheduledJobsCount   *int `json:"scheduled_jobs_count,omitempty" yaml:"scheduled_jobs_count,omitempty"`
	RunningJobsCount     *int `json:"running_jobs_count,omitempty" yaml:"running_jobs_count,omitempty"`
	WaitingJobsCount     *int `json:"waiting_jobs_count,omitempty" yaml:"waiting_jobs_count,omitempty"`

	// the provider of sources
	Provider *Provider `json:"provider,omitempty" yaml:"provider,omitempty"`

	// build steps
	Steps         []*Step           `json:"steps,omitempty" yaml:"steps,omitempty"`
	Configuration string            `json:"configuration,omitempty" yaml:"configuration,omitempty"`
	Env           map[string]string `json:"env,omitempty" yaml:"env,omitempty"`
}

// Step represents a build step in buildkites build pipeline
type Step struct {
	Type                *string           `json:"type,omitempty" yaml:"type,omitempty"`
	Name                *string           `json:"name,omitempty" yaml:"name,omitempty"`
	Command             *string           `json:"command,omitempty" yaml:"command,omitempty"`
	ArtifactPaths       *string           `json:"artifact_paths,omitempty" yaml:"artifact_paths,omitempty"`
	BranchConfiguration *string           `json:"branch_configuration,omitempty" yaml:"branch_configuration,omitempty"`
	Env                 map[string]string `json:"env,omitempty" yaml:"env,omitempty"`
	TimeoutInMinutes    *int              `json:"timeout_in_minutes,omitempty" yaml:"timeout_in_minutes,omitempty"`
	AgentQueryRules     []string          `json:"agent_query_rules,omitempty" yaml:"agent_query_rules,omitempty"`
}

// PipelineListOptions specifies the optional parameters to the
// PipelinesService.List method.
type PipelineListOptions struct {
	ListOptions
}

// Create - Creates a pipeline for a given organisation.
//
// buildkite API docs: https://buildkite.com/docs/rest-api/pipelines#create-a-pipeline
func (ps *PipelinesService) Create(org string, p *CreatePipeline) (*Pipeline, *Response, error) {
	u := fmt.Sprintf("v2/organizations/%s/pipelines", org)

	req, err := ps.client.NewRequest("POST", u, p)
	if err != nil {
		return nil, nil, err
	}

	pipeline := new(Pipeline)
	resp, err := ps.client.Do(req, pipeline)
	if err != nil {
		return nil, resp, err
	}

	return pipeline, resp, err
}

// Get fetches a pipeline.
//
// buildkite API docs: https://buildkite.com/docs/rest-api/pipelines#get-a-pipeline
func (ps *PipelinesService) Get(org string, slug string) (*Pipeline, *Response, error) {

	u := fmt.Sprintf("v2/organizations/%s/pipelines/%s", org, slug)

	req, err := ps.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	pipeline := new(Pipeline)
	resp, err := ps.client.Do(req, pipeline)
	if err != nil {
		return nil, resp, err
	}

	return pipeline, resp, err
}

// List the pipelines for a given organisation.
//
// buildkite API docs: https://buildkite.com/docs/api/pipelines#list-pipelines
func (ps *PipelinesService) List(org string, opt *PipelineListOptions) ([]Pipeline, *Response, error) {
	var u string

	u = fmt.Sprintf("v2/organizations/%s/pipelines", org)

	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := ps.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	pipelines := new([]Pipeline)
	resp, err := ps.client.Do(req, pipelines)
	if err != nil {
		return nil, resp, err
	}

	return *pipelines, resp, err
}

// Delete a pipeline.
//
// buildkite API docs: https://buildkite.com/docs/rest-api/pipelines#delete-a-pipeline
func (ps *PipelinesService) Delete(org string, slug string) (*Response, error) {

	u := fmt.Sprintf("v2/organizations/%s/pipelines/%s", org, slug)

	req, err := ps.client.NewRequest("DELETE", u, nil)
	if err != nil {
		return nil, err
	}

	return ps.client.Do(req, nil)
}

// Update - Updates a pipeline.
//
// buildkite API docs: https://buildkite.com/docs/rest-api/pipelines#update-a-pipeline
func (ps *PipelinesService) Update(org string, p *Pipeline) (*Response, error) {
	if p == nil {
		return nil, errors.New("pipeline must not be nil")
	}

	u := fmt.Sprintf("v2/organizations/%s/pipelines/%s", org, *p.Slug)

	req, err := ps.client.NewRequest("PATCH", u, p)
	if err != nil {
		return nil, err
	}

	resp, err := ps.client.Do(req, p)
	if err != nil {
		return resp, err
	}

	return resp, err
}

// AddWebhook - Adds webhook in github for pipeline.
//
// buildkite API docs: https://buildkite.com/docs/apis/rest-api/pipelines#add-a-webhook
func (ps *PipelinesService) AddWebhook(org string, slug string) (*Response, error) {

	u := fmt.Sprintf("v2/organizations/%s/pipelines/%s/webhook", org, slug)

	req, err := ps.client.NewRequest("POST", u, nil)
	if err != nil {
		return nil, err
	}

	return ps.client.Do(req, nil)
}

// Archive - Archives a pipeline.
//
// buildkite API docs: https://buildkite.com/docs/apis/rest-api/pipelines#archive-a-pipeline
func (ps *PipelinesService) Archive(org string, slug string) (*Response, error) {

	u := fmt.Sprintf("v2/organizations/%s/pipelines/%s/archive", org, slug)

	req, err := ps.client.NewRequest("POST", u, nil)
	if err != nil {
		return nil, err
	}

	return ps.client.Do(req, nil)
}

// Unarchive - Unarchive a pipeline.
//
// buildkite API docs: https://buildkite.com/docs/apis/rest-api/pipelines#unarchive-a-pipeline
func (ps *PipelinesService) Unarchive(org string, slug string) (*Response, error) {

	u := fmt.Sprintf("v2/organizations/%s/pipelines/%s/unarchive", org, slug)

	req, err := ps.client.NewRequest("POST", u, nil)
	if err != nil {
		return nil, err
	}

	return ps.client.Do(req, nil)
}
<commit_msg>revert pipelines<commit_after>package buildkite

import (
	"errors"
	"fmt"
)

// PipelinesService handles communication with the pipeline related
// methods of the buildkite API.
//
// buildkite API docs: https://buildkite.com/docs/api/pipelines
type PipelinesService struct {
	client *Client
}

// CreatePipeline - Create a Pipeline.
type CreatePipeline struct {
	Name       string `json:"name" yaml:"name"`
	Repository string `json:"repository" yaml:"repository"`

	// Either configuration needs to be specified as a yaml string or steps.
	Configuration string `json:"configuration,omitempty" yaml:"configuration,omitempty"`
	Steps         []Step `json:"steps,omitempty" yaml:"steps,omitempty"`

	// Optional fields
	DefaultBranch                   string            `json:"default_branch,omitempty" yaml:"default_branch,omitempty"`
	Description                     string            `json:"description,omitempty" yaml:"description,omitempty"`
	Env                             map[string]string `json:"env,omitempty" yaml:"env,omitempty"`
	ProviderSettings                ProviderSettings  `json:"provider_settings,omitempty" yaml:"provider_settings,omitempty"`
	BranchConfiguration             string            `json:"branch_configuration,omitempty" yaml:"branch_configuration,omitempty"`
	SkipQueuedBranchBuilds          bool              `json:"skip_queued_branch_builds,omitempty" yaml:"skip_queued_branch_builds,omitempty"`
	SkipQueuedBranchBuildsFilter    string            `json:"skip_queued_branch_builds_filter,omitempty" yaml:"skip_queued_branch_builds_filter,omitempty"`
	CancelRunningBranchBuilds       bool              `json:"cancel_running_branch_builds,omitempty" yaml:"cancel_running_branch_builds,omitempty"`
	CancelRunningBranchBuildsFilter string            `json:"cancel_running_branch_builds_filter,omitempty" yaml:"cancel_running_branch_builds_filter,omitempty"`
	TeamUuids                       []string          `json:"team_uuids,omitempty" yaml:"team_uuids,omitempty"`
	ClusterID                       string            `json:"cluster_id,omitempty" yaml:"cluster_id,omitempty"`
}

// Pipeline represents a buildkite pipeline.
type Pipeline struct {
	ID                              *string    `json:"id,omitempty" yaml:"id,omitempty"`
	URL                             *string    `json:"url,omitempty" yaml:"url,omitempty"`
	WebURL                          *string    `json:"web_url,omitempty" yaml:"web_url,omitempty"`
	Name                            *string    `json:"name,omitempty" yaml:"name,omitempty"`
	Slug                            *string    `json:"slug,omitempty" yaml:"slug,omitempty"`
	Repository                      *string    `json:"repository,omitempty" yaml:"repository,omitempty"`
	BuildsURL                       *string    `json:"builds_url,omitempty" yaml:"builds_url,omitempty"`
	BadgeURL                        *string    `json:"badge_url,omitempty" yaml:"badge_url,omitempty"`
	CreatedAt                       *Timestamp `json:"created_at,omitempty" yaml:"created_at,omitempty"`
	ArchivedAt                      *Timestamp `json:"archived_at,omitempty" yaml:"archived_at,omitempty"`
	DefaultBranch                   *string    `json:"default_branch,omitempty" yaml:"default_branch,omitempty"`
	Description                     *string    `json:"description,omitempty" yaml:"description,omitempty"`
	BranchConfiguration             *string    `json:"branch_configuration,omitempty" yaml:"branch_configuration,omitempty"`
	SkipQueuedBranchBuilds          *bool      `json:"skip_queued_branch_builds,omitempty" yaml:"skip_queued_branch_builds,omitempty"`
	SkipQueuedBranchBuildsFilter    *string    `json:"skip_queued_branch_builds_filter,omitempty" yaml:"skip_queued_branch_builds_filter,omitempty"`
	CancelRunningBranchBuilds       *bool      `json:"cancel_running_branch_builds,omitempty" yaml:"cancel_running_branch_builds,omitempty"`
	CancelRunningBranchBuildsFilter *string    `json:"cancel_running_branch_builds_filter,omitempty" yaml:"cancel_running_branch_builds_filter,omitempty"`
	ClusterID                       *string    `json:"cluster_id,omitempty" yaml:"cluster_id,omitempty"`

	ScheduledBuildsCount *int `json:"scheduled_builds_count,omitempty" yaml:"scheduled_builds_count,omitempty"`
	RunningBuildsCount   *int `json:"running_builds_count,omitempty" yaml:"running_builds_count,omitempty"`
	ScheduledJobsCount   *int `json:"scheduled_jobs_count,omitempty" yaml:"scheduled_jobs_count,omitempty"`
	RunningJobsCount     *int `json:"running_jobs_count,omitempty" yaml:"running_jobs_count,omitempty"`
	WaitingJobsCount     *int `json:"waiting_jobs_count,omitempty" yaml:"waiting_jobs_count,omitempty"`

	// the provider of sources
	Provider *Provider `json:"provider,omitempty" yaml:"provider,omitempty"`

	// build steps
	Steps         []*Step                `json:"steps,omitempty" yaml:"steps,omitempty"`
	Configuration string                 `json:"configuration,omitempty" yaml:"configuration,omitempty"`
	Env           map[string]interface{} `json:"env,omitempty" yaml:"env,omitempty"`
}

// Step represents a build step in buildkites build pipeline
type Step struct {
	Type                *string           `json:"type,omitempty" yaml:"type,omitempty"`
	Name                *string           `json:"name,omitempty" yaml:"name,omitempty"`
	Command             *string           `json:"command,omitempty" yaml:"command,omitempty"`
	ArtifactPaths       *string           `json:"artifact_paths,omitempty" yaml:"artifact_paths,omitempty"`
	BranchConfiguration *string           `json:"branch_configuration,omitempty" yaml:"branch_configuration,omitempty"`
	Env                 map[string]string `json:"env,omitempty" yaml:"env,omitempty"`
	TimeoutInMinutes    *int              `json:"timeout_in_minutes,omitempty" yaml:"timeout_in_minutes,omitempty"`
	AgentQueryRules     []string          `json:"agent_query_rules,omitempty" yaml:"agent_query_rules,omitempty"`
}

// PipelineListOptions specifies the optional parameters to the
// PipelinesService.List method.
type PipelineListOptions struct {
	ListOptions
}

// Create - Creates a pipeline for a given organisation.
//
// buildkite API docs: https://buildkite.com/docs/rest-api/pipelines#create-a-pipeline
func (ps *PipelinesService) Create(org string, p *CreatePipeline) (*Pipeline, *Response, error) {
	u := fmt.Sprintf("v2/organizations/%s/pipelines", org)

	req, err := ps.client.NewRequest("POST", u, p)
	if err != nil {
		return nil, nil, err
	}

	pipeline := new(Pipeline)
	resp, err := ps.client.Do(req, pipeline)
	if err != nil {
		return nil, resp, err
	}

	return pipeline, resp, err
}

// Get fetches a pipeline.
//
// buildkite API docs: https://buildkite.com/docs/rest-api/pipelines#get-a-pipeline
func (ps *PipelinesService) Get(org string, slug string) (*Pipeline, *Response, error) {

	u := fmt.Sprintf("v2/organizations/%s/pipelines/%s", org, slug)

	req, err := ps.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	pipeline := new(Pipeline)
	resp, err := ps.client.Do(req, pipeline)
	if err != nil {
		return nil, resp, err
	}

	return pipeline, resp, err
}

// List the pipelines for a given organisation.
//
// buildkite API docs: https://buildkite.com/docs/api/pipelines#list-pipelines
func (ps *PipelinesService) List(org string, opt *PipelineListOptions) ([]Pipeline, *Response, error) {
	var u string

	u = fmt.Sprintf("v2/organizations/%s/pipelines", org)

	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := ps.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	pipelines := new([]Pipeline)
	resp, err := ps.client.Do(req, pipelines)
	if err != nil {
		return nil, resp, err
	}

	return *pipelines, resp, err
}

// Delete a pipeline.
//
// buildkite API docs: https://buildkite.com/docs/rest-api/pipelines#delete-a-pipeline
func (ps *PipelinesService) Delete(org string, slug string) (*Response, error) {

	u := fmt.Sprintf("v2/organizations/%s/pipelines/%s", org, slug)

	req, err := ps.client.NewRequest("DELETE", u, nil)
	if err != nil {
		return nil, err
	}

	return ps.client.Do(req, nil)
}

// Update - Updates a pipeline.
//
// buildkite API docs: https://buildkite.com/docs/rest-api/pipelines#update-a-pipeline
func (ps *PipelinesService) Update(org string, p *Pipeline) (*Response, error) {
	if p == nil {
		return nil, errors.New("pipeline must not be nil")
	}

	u := fmt.Sprintf("v2/organizations/%s/pipelines/%s", org, *p.Slug)

	req, err := ps.client.NewRequest("PATCH", u, p)
	if err != nil {
		return nil, err
	}

	resp, err := ps.client.Do(req, p)
	if err != nil {
		return resp, err
	}

	return resp, err
}

// AddWebhook - Adds webhook in github for pipeline.
//
// buildkite API docs: https://buildkite.com/docs/apis/rest-api/pipelines#add-a-webhook
func (ps *PipelinesService) AddWebhook(org string, slug string) (*Response, error) {

	u := fmt.Sprintf("v2/organizations/%s/pipelines/%s/webhook", org, slug)

	req, err := ps.client.NewRequest("POST", u, nil)
	if err != nil {
		return nil, err
	}

	return ps.client.Do(req, nil)
}

// Archive - Archives a pipeline.
//
// buildkite API docs: https://buildkite.com/docs/apis/rest-api/pipelines#archive-a-pipeline
func (ps *PipelinesService) Archive(org string, slug string) (*Response, error) {

	u := fmt.Sprintf("v2/organizations/%s/pipelines/%s/archive", org, slug)

	req, err := ps.client.NewRequest("POST", u, nil)
	if err != nil {
		return nil, err
	}

	return ps.client.Do(req, nil)
}

// Unarchive - Unarchive a pipeline.
//
// buildkite API docs: https://buildkite.com/docs/apis/rest-api/pipelines#unarchive-a-pipeline
func (ps *PipelinesService) Unarchive(org string, slug string) (*Response, error) {

	u := fmt.Sprintf("v2/organizations/%s/pipelines/%s/unarchive", org, slug)

	req, err := ps.client.NewRequest("POST", u, nil)
	if err != nil {
		return nil, err
	}

	return ps.client.Do(req, nil)
}
<|endoftext|>


<commit_before>// Copyright 2021 Google LLC
//
// 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 bitlocker provides functionality for managing Bitlocker.
package bitlocker

import (
	"github.com/google/logger"
	"github.com/iamacarpet/go-win64api"
)

var (
	// Test Helpers
	funcBackup       = winapi.BackupBitLockerRecoveryKeys
	funcRecoveryInfo = winapi.GetBitLockerRecoveryInfo
)

// BackupToAD backs up Bitlocker recovery keys to Active Directory.
func BackupToAD() error {
	infos, err := funcRecoveryInfo()
	if err != nil {
		return err
	}
	volIDs := []string{}
	for _, i := range infos {
		if i.ConversionStatus != 1 {
			logger.Warningf("Skipping volume %s due to conversion status (%d).", i.DriveLetter, i.ConversionStatus)
			continue
		}
		logger.Infof("Backing up Bitlocker recovery password for drive %q.", i.DriveLetter)
		volIDs = append(volIDs, i.PersistentVolumeID)
	}
	return funcBackup(volIDs)
}
<commit_msg>Add bitlocker.EncryptWithTPM to Glazier.<commit_after>// Copyright 2021 Google LLC
//
// 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 bitlocker provides functionality for managing Bitlocker.
package bitlocker

import (
	"fmt"

	"github.com/google/logger"
	"github.com/go-ole/go-ole"
	"github.com/go-ole/go-ole/oleutil"
	"github.com/iamacarpet/go-win64api"
)

var (
	// Test Helpers
	funcBackup       = winapi.BackupBitLockerRecoveryKeys
	funcRecoveryInfo = winapi.GetBitLockerRecoveryInfo
)

// BackupToAD backs up Bitlocker recovery keys to Active Directory.
func BackupToAD() error {
	infos, err := funcRecoveryInfo()
	if err != nil {
		return err
	}
	volIDs := []string{}
	for _, i := range infos {
		if i.ConversionStatus != 1 {
			logger.Warningf("Skipping volume %s due to conversion status (%d).", i.DriveLetter, i.ConversionStatus)
			continue
		}
		logger.Infof("Backing up Bitlocker recovery password for drive %q.", i.DriveLetter)
		volIDs = append(volIDs, i.PersistentVolumeID)
	}
	return funcBackup(volIDs)
}

type wmi struct {
	intf *ole.IDispatch
	svc  *ole.IDispatch
}

func (w *wmi) connect() error {
	unknown, err := oleutil.CreateObject("WbemScripting.SWbemLocator")
	if err != nil {
		return fmt.Errorf("unable to create initial object, %w", err)
	}
	defer unknown.Release()
	w.intf, err = unknown.QueryInterface(ole.IID_IDispatch)
	if err != nil {
		return fmt.Errorf("unable to create initial object, %w", err)
	}
	serviceRaw, err := oleutil.CallMethod(w.intf, "ConnectServer", nil, `\\.\ROOT\CIMV2\Security\MicrosoftVolumeEncryption`)
	if err != nil {
		return fmt.Errorf("permission denied: %w", err)
	}
	w.svc = serviceRaw.ToIDispatch()
	return nil
}

func (w *wmi) close() {
	w.svc.Release()
	w.intf.Release()
}

const (
	// Encryption Methods
	// https://docs.microsoft.com/en-us/windows/win32/secprov/getencryptionmethod-win32-encryptablevolume
	None int32 = iota
	AES128WithDiffuser
	AES256WithDiffuser
	AES128
	AES256
	HardwareEncryption
	XtsAES128
	XtsAES256

	// Encryption Flags
	// https://docs.microsoft.com/en-us/windows/win32/secprov/encrypt-win32-encryptablevolume
	EncryptDataOnly    int32 = 0x00000001
	EncryptDemandWipe  int32 = 0x00000002
	EncryptSynchronous int32 = 0x00010000

	// Error Codes
	FVE_E_BOOTABLE_CDDVD   int32 = -2144272336
	FVE_E_PROTECTOR_EXISTS int32 = -2144272335
)

func encryptErrHandler(val int32) error {
	switch val {
	case FVE_E_BOOTABLE_CDDVD:
		return fmt.Errorf("BitLocker Drive Encryption detected bootable media (CD or DVD) in the computer. " +
			"Remove the media and restart the computer before configuring BitLocker.")
	case FVE_E_PROTECTOR_EXISTS:
		return fmt.Errorf("key protector cannot be added; only one key protector of this type is allowed for this drive")
	default:
		return fmt.Errorf("error code returned during encryption: %d", val)
	}
}

// EncryptWithTPM encrypts the drive with Bitlocker using TPM key protection.
//
// Example: bitlocker.EncryptWithTPM("c:", bitlocker.XtsAES256, bitlocker.EncryptDataOnly)
func EncryptWithTPM(driveLetter string, method int32, flags int32) error {
	ole.CoInitialize(0)
	defer ole.CoUninitialize()
	w := &wmi{}
	if err := w.connect(); err != nil {
		return fmt.Errorf("wmi.Connect: %w", err)
	}
	defer w.close()
	raw, err := oleutil.CallMethod(w.svc, "ExecQuery",
		"SELECT * FROM Win32_EncryptableVolume WHERE DriveLetter = '"+driveLetter+"'")
	if err != nil {
		return fmt.Errorf("ExecQuery: %w", err)
	}
	result := raw.ToIDispatch()
	defer result.Release()

	itemRaw, err := oleutil.CallMethod(result, "ItemIndex", 0)
	if err != nil {
		return fmt.Errorf("failed to fetch result row while processing BitLocker info: %w", err)
	}
	item := itemRaw.ToIDispatch()
	defer item.Release()

	// https://docs.microsoft.com/en-us/windows/win32/secprov/protectkeywithtpm-win32-encryptablevolume
	var volumeKeyProtectorID ole.VARIANT
	ole.VariantInit(&volumeKeyProtectorID)
	resultRaw, err := oleutil.CallMethod(item, "ProtectKeyWithTPM", nil, nil, &volumeKeyProtectorID)
	if err != nil {
		return fmt.Errorf("error calling ProtectKeyWithTPM(%s): %w", driveLetter, err)
	} else if val, ok := resultRaw.Value().(int32); val != 0 || !ok {
		return encryptErrHandler(val)
	}

	resultRaw, err = oleutil.CallMethod(item, "Encrypt", method, flags)
	if err != nil {
		return fmt.Errorf("error calling Encrypt(%s): %w", driveLetter, err)
	} else if val, ok := resultRaw.Value().(int32); val != 0 || !ok {
		return encryptErrHandler(val)
	}
	return nil
}
<|endoftext|>


<commit_before>package blackjack

import "log"

// ParseCard returns the integer value of a card following blackjack ruleset.
func ParseCard(card string) int {
	switch card {
	case "one":
		return 1
	case "two":
		return 2
	case "three":
		return 3
	case "four":
		return 4
	case "five":
		return 5
	case "six":
		return 6
	case "seven":
		return 7
	case "eight":
		return 8
	case "nine":
		return 9
	case "ten", "jack", "queen", "king":
		return 10
	case "ace":
		return 11
	default:
		log.Printf("card %s is not a valid card", card)
		return 0
	}
}

// IsBlackjack returns true if the player has a blackjack, false otherwise.
func IsBlackjack(card1, card2 string) bool {
	return ParseCard(card1)+ParseCard(card2) == 21
}

// LargeHand implements the decision tree for hand scores larger than 20 points.
func LargeHand(isBlackjack bool, dealerScore int) string {
	panic("Please implement the LargeHand function")
}

// SmallHand implements the decision tree for hand scores with less than 21 points.
func SmallHand(handScore, dealerScore int) string {
	panic("Please implement the SmallHand function")
}

// FirstTurn returns the semi-optimal decision for the first turn, given the cards of the player and the dealer.
// This function is already implemented and does not need to be edited. It pulls the other functions together in a
// complete decision tree for the first turn.
func FirstTurn(card1, card2, dealerCard string) string {
	handScore := ParseCard(card1) + ParseCard(card2)
	dealerScore := ParseCard(dealerCard)

	if 20 < handScore {
		return LargeHand(IsBlackjack(card1, card2), dealerScore)
	}
	return SmallHand(handScore, dealerScore)
}
<commit_msg>Implement large hand<commit_after>package blackjack

import "log"

// ParseCard returns the integer value of a card following blackjack ruleset.
func ParseCard(card string) int {
	switch card {
	case "one":
		return 1
	case "two":
		return 2
	case "three":
		return 3
	case "four":
		return 4
	case "five":
		return 5
	case "six":
		return 6
	case "seven":
		return 7
	case "eight":
		return 8
	case "nine":
		return 9
	case "ten", "jack", "queen", "king":
		return 10
	case "ace":
		return 11
	default:
		log.Printf("card %s is not a valid card", card)
		return 0
	}
}

// IsBlackjack returns true if the player has a blackjack, false otherwise.
func IsBlackjack(card1, card2 string) bool {
	return ParseCard(card1)+ParseCard(card2) == 21
}

// LargeHand implements the decision tree for hand scores larger than 20 points.
func LargeHand(isBlackjack bool, dealerScore int) string {
	if isBlackjack && dealerScore < 10 {
		return "W"
	} else if isBlackjack {
		return "S"
	} else {
		return "P"
	}
}

// SmallHand implements the decision tree for hand scores with less than 21 points.
func SmallHand(handScore, dealerScore int) string {
	panic("Please implement the SmallHand function")
}

// FirstTurn returns the semi-optimal decision for the first turn, given the cards of the player and the dealer.
// This function is already implemented and does not need to be edited. It pulls the other functions together in a
// complete decision tree for the first turn.
func FirstTurn(card1, card2, dealerCard string) string {
	handScore := ParseCard(card1) + ParseCard(card2)
	dealerScore := ParseCard(dealerCard)

	if 20 < handScore {
		return LargeHand(IsBlackjack(card1, card2), dealerScore)
	}
	return SmallHand(handScore, dealerScore)
}
<|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 callgraph defines the call graph and various algorithms
and utilities to operate on it.

A call graph is a labelled directed graph whose nodes represent
functions and whose edge labels represent syntactic function call
sites.  The presence of a labelled edge (caller, site, callee)
indicates that caller may call callee at the specified call site.

A call graph is a multigraph: it may contain multiple edges (caller,
*, callee) connecting the same pair of nodes, so long as the edges
differ by label; this occurs when one function calls another function
from multiple call sites.  Also, it may contain multiple edges
(caller, site, *) that differ only by callee; this indicates a
polymorphic call.

A SOUND call graph is one that overapproximates the dynamic calling
behaviors of the program in all possible executions.  One call graph
is more PRECISE than another if it is a smaller overapproximation of
the dynamic behavior.

All call graphs have a synthetic root node which is responsible for
calling main() and init().

Calls to built-in functions (e.g. panic, println) are not represented
in the call graph; they are treated like built-in operators of the
language.

*/
package callgraph // import "golang.org/x/tools/go/callgraph"

// TODO(adonovan): add a function to eliminate wrappers from the
// callgraph, preserving topology.
// More generally, we could eliminate "uninteresting" nodes such as
// nodes from packages we don't care about.

import (
	"fmt"
	"go/token"

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

// A Graph represents a call graph.
//
// A graph may contain nodes that are not reachable from the root.
// If the call graph is sound, such nodes indicate unreachable
// functions.
//
type Graph struct {
	Root  *Node                   // the distinguished root node
	Nodes map[*ssa.Function]*Node // all nodes by function
}

// New returns a new Graph with the specified root node.
func New(root *ssa.Function) *Graph {
	g := &Graph{Nodes: make(map[*ssa.Function]*Node)}
	g.Root = g.CreateNode(root)
	return g
}

// CreateNode returns the Node for fn, creating it if not present.
func (g *Graph) CreateNode(fn *ssa.Function) *Node {
	n, ok := g.Nodes[fn]
	if !ok {
		n = &Node{Func: fn, ID: len(g.Nodes)}
		g.Nodes[fn] = n
	}
	return n
}

// A Node represents a node in a call graph.
type Node struct {
	Func *ssa.Function // the function this node represents
	ID   int           // 0-based sequence number
	In   []*Edge       // unordered set of incoming call edges (n.In[*].Callee == n)
	Out  []*Edge       // unordered set of outgoing call edges (n.Out[*].Caller == n)
}

func (n *Node) String() string {
	return fmt.Sprintf("n%d:%s", n.ID, n.Func)
}

// A Edge represents an edge in the call graph.
//
// Site is nil for edges originating in synthetic or intrinsic
// functions, e.g. reflect.Call or the root of the call graph.
type Edge struct {
	Caller *Node
	Site   ssa.CallInstruction
	Callee *Node
}

func (e Edge) String() string {
	return fmt.Sprintf("%s --> %s", e.Caller, e.Callee)
}

func (e Edge) Description() string {
	var prefix string
	switch e.Site.(type) {
	case nil:
		return "synthetic call"
	case *ssa.Go:
		prefix = "concurrent "
	case *ssa.Defer:
		prefix = "deferred "
	}
	return prefix + e.Site.Common().Description()
}

func (e Edge) Pos() token.Pos {
	if e.Site == nil {
		return token.NoPos
	}
	return e.Site.Pos()
}

// AddEdge adds the edge (caller, site, callee) to the call graph.
// Elimination of duplicate edges is the caller's responsibility.
func AddEdge(caller *Node, site ssa.CallInstruction, callee *Node) {
	e := &Edge{caller, site, callee}
	callee.In = append(callee.In, e)
	caller.Out = append(caller.Out, e)
}
<commit_msg>go/callgraph: change reflect.Call to reflect.Value.Call in comment<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 callgraph defines the call graph and various algorithms
and utilities to operate on it.

A call graph is a labelled directed graph whose nodes represent
functions and whose edge labels represent syntactic function call
sites.  The presence of a labelled edge (caller, site, callee)
indicates that caller may call callee at the specified call site.

A call graph is a multigraph: it may contain multiple edges (caller,
*, callee) connecting the same pair of nodes, so long as the edges
differ by label; this occurs when one function calls another function
from multiple call sites.  Also, it may contain multiple edges
(caller, site, *) that differ only by callee; this indicates a
polymorphic call.

A SOUND call graph is one that overapproximates the dynamic calling
behaviors of the program in all possible executions.  One call graph
is more PRECISE than another if it is a smaller overapproximation of
the dynamic behavior.

All call graphs have a synthetic root node which is responsible for
calling main() and init().

Calls to built-in functions (e.g. panic, println) are not represented
in the call graph; they are treated like built-in operators of the
language.

*/
package callgraph // import "golang.org/x/tools/go/callgraph"

// TODO(adonovan): add a function to eliminate wrappers from the
// callgraph, preserving topology.
// More generally, we could eliminate "uninteresting" nodes such as
// nodes from packages we don't care about.

import (
	"fmt"
	"go/token"

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

// A Graph represents a call graph.
//
// A graph may contain nodes that are not reachable from the root.
// If the call graph is sound, such nodes indicate unreachable
// functions.
//
type Graph struct {
	Root  *Node                   // the distinguished root node
	Nodes map[*ssa.Function]*Node // all nodes by function
}

// New returns a new Graph with the specified root node.
func New(root *ssa.Function) *Graph {
	g := &Graph{Nodes: make(map[*ssa.Function]*Node)}
	g.Root = g.CreateNode(root)
	return g
}

// CreateNode returns the Node for fn, creating it if not present.
func (g *Graph) CreateNode(fn *ssa.Function) *Node {
	n, ok := g.Nodes[fn]
	if !ok {
		n = &Node{Func: fn, ID: len(g.Nodes)}
		g.Nodes[fn] = n
	}
	return n
}

// A Node represents a node in a call graph.
type Node struct {
	Func *ssa.Function // the function this node represents
	ID   int           // 0-based sequence number
	In   []*Edge       // unordered set of incoming call edges (n.In[*].Callee == n)
	Out  []*Edge       // unordered set of outgoing call edges (n.Out[*].Caller == n)
}

func (n *Node) String() string {
	return fmt.Sprintf("n%d:%s", n.ID, n.Func)
}

// A Edge represents an edge in the call graph.
//
// Site is nil for edges originating in synthetic or intrinsic
// functions, e.g. reflect.Value.Call or the root of the call graph.
type Edge struct {
	Caller *Node
	Site   ssa.CallInstruction
	Callee *Node
}

func (e Edge) String() string {
	return fmt.Sprintf("%s --> %s", e.Caller, e.Callee)
}

func (e Edge) Description() string {
	var prefix string
	switch e.Site.(type) {
	case nil:
		return "synthetic call"
	case *ssa.Go:
		prefix = "concurrent "
	case *ssa.Defer:
		prefix = "deferred "
	}
	return prefix + e.Site.Common().Description()
}

func (e Edge) Pos() token.Pos {
	if e.Site == nil {
		return token.NoPos
	}
	return e.Site.Pos()
}

// AddEdge adds the edge (caller, site, callee) to the call graph.
// Elimination of duplicate edges is the caller's responsibility.
func AddEdge(caller *Node, site ssa.CallInstruction, callee *Node) {
	e := &Edge{caller, site, callee}
	callee.In = append(callee.In, e)
	caller.Out = append(caller.Out, e)
}
<|endoftext|>


<commit_before>// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris

package client

import (
	"fmt"
	"os"

	"golang.org/x/crypto/ssh/terminal"
)

type TerminalEngine struct {
	tty           *os.File
	fd            int
	oldTerminal   *terminal.State
	terminal      *terminal.Terminal
	started       bool
	width, height int
}

func (t *TerminalEngine) Init() error {
	return nil
}

func NewTerminalEngine() *TerminalEngine {
	return &TerminalEngine{fd: -1}
}

var globalIsStarted = false

func (t *TerminalEngine) GetSize() (int, int) {
	if err := t.Startup(); err != nil {
		return 0, 0
	}
	return t.width, t.height
}

func (t *TerminalEngine) Startup() error {

	if t.started {
		return nil
	}

	t.started = true

	if globalIsStarted {
		return fmt.Errorf("Can only instantiate one terminal wrapper per proc")
	}

	globalIsStarted = true

	G.Log.Debug("+ Opening up /dev/tty terminal on Linux and OSX")
	file, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
	if err != nil {
		return err
	}
	t.tty = file
	t.fd = int(t.tty.Fd())
	t.width, t.height, err = terminal.GetSize(t.fd)
	if err != nil {
		return err
	}

	t.oldTerminal, err = terminal.MakeRaw(t.fd)
	if err != nil {
		return err
	}
	G.Log.Debug("| switched to raw console for tty")
	if t.terminal = terminal.NewTerminal(file, ""); t.terminal == nil {
		return fmt.Errorf("failed to open terminal")
	}
	t.terminal.AutoCompleteCallback = t.autoComp

	if err = t.terminal.SetSize(t.width, t.height); err != nil {
		return err
	}

	G.Log.Debug("- Done opening /dev/tty")
	return nil
}

func (t *TerminalEngine) Shutdown() error {
	if t.oldTerminal != nil {
		G.Log.Debug("Restoring terminal settings")

		// XXX bug in ssh/terminal. On success, we were getting an error
		// "errno 0"; so let's ignore it for now.
		terminal.Restore(t.fd, t.oldTerminal)
	}
	return nil
}

func (t *TerminalEngine) PromptPassword(prompt string) (string, error) {
	if err := t.Startup(); err != nil {
		return "", err
	}
	return t.terminal.ReadPassword(prompt)
}

func (t *TerminalEngine) Write(s string) error {
	if err := t.Startup(); err != nil {
		return err
	}
	_, err := t.terminal.Write([]byte(s))
	return err
}

func (t *TerminalEngine) Prompt(prompt string) (string, error) {
	if err := t.Startup(); err != nil {
		return "", err
	}
	if len(prompt) >= 0 {
		t.Write(prompt)
	}
	return t.terminal.ReadLine()
}

func (t *TerminalEngine) autoComp(line string, pos int, key rune) (newLine string, newPos int, ok bool) {
	// this is a hack to handle ctrl-c
	if key == 3 {
		G.Shutdown()
		G.Log.Error("interrupted")
		os.Exit(3)
	}
	return line, pos, false
}
<commit_msg>removed old terminal file (minterm replaces it)<commit_after><|endoftext|>


<commit_before>package promstats

import (
	"expvar"
	"fmt"
	"strings"
	"time"

	"github.com/golang/glog"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/youtube/vitess/go/stats"
)

// NewCollector returns a prometheus.Collector for a given stats var.
// It supports all stats var types except String, StringFunc and Rates.
// The returned collector still needs to be registered with prometheus registry.
func NewCollector(opts prometheus.Opts, v expvar.Var) prometheus.Collector {
	switch st := v.(type) {
	case *stats.Int:
		return prometheus.NewGaugeFunc(prometheus.GaugeOpts(opts), func() float64 {
			return float64(st.Get())
		})
	case stats.IntFunc:
		return prometheus.NewGaugeFunc(prometheus.GaugeOpts(opts), func() float64 {
			return float64(st())
		})
	case *stats.Duration:
		return prometheus.NewGaugeFunc(prometheus.GaugeOpts(opts), func() float64 {
			return st.Get().Seconds()
		})
	case stats.DurationFunc:
		return prometheus.NewGaugeFunc(prometheus.GaugeOpts(opts), func() float64 {
			return st().Seconds()
		})
	case *stats.Float:
		return prometheus.NewGaugeFunc(prometheus.GaugeOpts(opts), st.Get)
	case stats.FloatFunc:
		return prometheus.NewGaugeFunc(prometheus.GaugeOpts(opts), st)
	case *stats.Counters:
		return newCountersCollector(opts, st, "tag")
	case stats.CountersFunc:
		return newCountersCollector(opts, st, "tag")
	case *stats.MultiCounters:
		return newCountersCollector(opts, st, st.Labels()...)
	case *stats.MultiCountersFunc:
		return newCountersCollector(opts, st, st.Labels()...)
	case *stats.Histogram:
		return newHistogramCollector(opts, st)
	case *stats.Timings:
		return newTimingsCollector(opts, st, "category")
	case *stats.MultiTimings:
		return newTimingsCollector(opts, &st.Timings, st.Labels()...)
	case *stats.String:
		// prometheus can't collect string values
		return nil
	case stats.StringFunc:
		// prometheus can't collect string values
		return nil
	case *stats.Rates:
		// Ignore these, because monitoring tools will calculate
		// rates for us.
		return nil
	default:
		glog.Warningf("Unsupported type for %s: %T", opts.Name, v)
		return nil
	}
}

type countersCollector struct {
	desc    *prometheus.Desc
	c       stats.CountTracker
	nLabels int
}

func newCountersCollector(opts prometheus.Opts, c stats.CountTracker, labels ...string) prometheus.Collector {
	desc := prometheus.NewDesc(
		prometheus.BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
		opts.Help,
		labels,
		opts.ConstLabels,
	)
	return countersCollector{
		desc:    desc,
		c:       c,
		nLabels: len(labels),
	}
}

func (c countersCollector) Describe(ch chan<- *prometheus.Desc) {
	ch <- c.desc
}

var replacer = strings.NewReplacer(`\\`, `\`, `\.`, `.`, `.`, "\000")

func split(key string) []string {
	return strings.Split(replacer.Replace(key), "\000")
}

func (c countersCollector) Collect(ch chan<- prometheus.Metric) {
	for k, n := range c.c.Counts() {
		if c.nLabels > 1 {
			labels := split(k)
			if len(labels) != c.nLabels {
				err := fmt.Errorf("wrong number of labels in MultiCounters key: %d != %d (key=%q)", len(labels), c.nLabels, k)
				ch <- prometheus.NewInvalidMetric(c.desc, err)
				continue
			}
			ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(n), labels...)
			continue
		}
		ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(n), k)
	}
}

func newHistogram(opts prometheus.Opts, cutoffs []int64) (prometheus.Histogram, func(int64)) {
	buckets := make([]float64, len(cutoffs))
	for i := range cutoffs {
		buckets[i] = float64(cutoffs[i])
	}
	hOpts := prometheus.HistogramOpts{
		Namespace:   opts.Namespace,
		Subsystem:   opts.Subsystem,
		Name:        opts.Name,
		Help:        opts.Help,
		ConstLabels: opts.ConstLabels,
		Buckets:     buckets,
	}
	m := prometheus.NewHistogram(hOpts)
	return m, func(n int64) {
		m.Observe(float64(n))
	}
}

type histogramCollector struct {
	desc *prometheus.Desc
	h    *stats.Histogram
}

func newHistogramCollector(opts prometheus.Opts, h *stats.Histogram) histogramCollector {
	desc := prometheus.NewDesc(
		prometheus.BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
		opts.Help,
		nil,
		opts.ConstLabels,
	)
	return histogramCollector{
		desc: desc,
		h:    h,
	}
}

func histogramMetric(desc *prometheus.Desc, h *stats.Histogram, scale float64, labels ...string) prometheus.Metric {
	count := uint64(0)
	sum := float64(h.Total()) * scale
	cutoffs := h.Cutoffs()
	statBuckets := h.Buckets()
	promBuckets := make(map[float64]uint64, len(cutoffs))
	for i, cutoff := range cutoffs {
		upperBound := float64(cutoff) * scale
		count += uint64(statBuckets[i])
		promBuckets[upperBound] = count
	}
	count += uint64(statBuckets[len(statBuckets)-1])
	return prometheus.MustNewConstHistogram(desc, count, sum, promBuckets, labels...)
}

func (h histogramCollector) Describe(ch chan<- *prometheus.Desc) {
	ch <- h.desc
}

func (h histogramCollector) Collect(ch chan<- prometheus.Metric) {
	ch <- histogramMetric(h.desc, h.h, 1)
}

type timingsCollector struct {
	desc    *prometheus.Desc
	t       *stats.Timings
	nLabels int
}

func newTimingsCollector(opts prometheus.Opts, t *stats.Timings, labels ...string) prometheus.Collector {
	desc := prometheus.NewDesc(
		prometheus.BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
		opts.Help,
		labels,
		opts.ConstLabels,
	)
	return timingsCollector{
		desc:    desc,
		t:       t,
		nLabels: len(labels),
	}
}

func (c timingsCollector) Describe(ch chan<- *prometheus.Desc) {
	ch <- c.desc
}

func (c timingsCollector) Collect(ch chan<- prometheus.Metric) {
	for k, h := range c.t.Histograms() {
		if c.nLabels > 1 {
			labels := split(k)
			if len(labels) != c.nLabels {
				err := fmt.Errorf("wrong number of labels in MultiTimings key: %d != %d (key=%q)", len(labels), c.nLabels, k)
				ch <- prometheus.NewInvalidMetric(c.desc, err)
				continue
			}
			ch <- histogramMetric(c.desc, h, 1/float64(time.Second), labels...)
			continue
		}
		ch <- histogramMetric(c.desc, h, 1/float64(time.Second), k)
	}
}
<commit_msg>Add package doc to promstats<commit_after>/*
Package promstats contains adapters to publish stats variables to prometheus (http://prometheus.io)
*/
package promstats

import (
	"expvar"
	"fmt"
	"strings"
	"time"

	"github.com/golang/glog"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/youtube/vitess/go/stats"
)

// NewCollector returns a prometheus.Collector for a given stats var.
// It supports all stats var types except String, StringFunc and Rates.
// The returned collector still needs to be registered with prometheus registry.
func NewCollector(opts prometheus.Opts, v expvar.Var) prometheus.Collector {
	switch st := v.(type) {
	case *stats.Int:
		return prometheus.NewGaugeFunc(prometheus.GaugeOpts(opts), func() float64 {
			return float64(st.Get())
		})
	case stats.IntFunc:
		return prometheus.NewGaugeFunc(prometheus.GaugeOpts(opts), func() float64 {
			return float64(st())
		})
	case *stats.Duration:
		return prometheus.NewGaugeFunc(prometheus.GaugeOpts(opts), func() float64 {
			return st.Get().Seconds()
		})
	case stats.DurationFunc:
		return prometheus.NewGaugeFunc(prometheus.GaugeOpts(opts), func() float64 {
			return st().Seconds()
		})
	case *stats.Float:
		return prometheus.NewGaugeFunc(prometheus.GaugeOpts(opts), st.Get)
	case stats.FloatFunc:
		return prometheus.NewGaugeFunc(prometheus.GaugeOpts(opts), st)
	case *stats.Counters:
		return newCountersCollector(opts, st, "tag")
	case stats.CountersFunc:
		return newCountersCollector(opts, st, "tag")
	case *stats.MultiCounters:
		return newCountersCollector(opts, st, st.Labels()...)
	case *stats.MultiCountersFunc:
		return newCountersCollector(opts, st, st.Labels()...)
	case *stats.Histogram:
		return newHistogramCollector(opts, st)
	case *stats.Timings:
		return newTimingsCollector(opts, st, "category")
	case *stats.MultiTimings:
		return newTimingsCollector(opts, &st.Timings, st.Labels()...)
	case *stats.String:
		// prometheus can't collect string values
		return nil
	case stats.StringFunc:
		// prometheus can't collect string values
		return nil
	case *stats.Rates:
		// Ignore these, because monitoring tools will calculate
		// rates for us.
		return nil
	default:
		glog.Warningf("Unsupported type for %s: %T", opts.Name, v)
		return nil
	}
}

type countersCollector struct {
	desc    *prometheus.Desc
	c       stats.CountTracker
	nLabels int
}

func newCountersCollector(opts prometheus.Opts, c stats.CountTracker, labels ...string) prometheus.Collector {
	desc := prometheus.NewDesc(
		prometheus.BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
		opts.Help,
		labels,
		opts.ConstLabels,
	)
	return countersCollector{
		desc:    desc,
		c:       c,
		nLabels: len(labels),
	}
}

func (c countersCollector) Describe(ch chan<- *prometheus.Desc) {
	ch <- c.desc
}

var replacer = strings.NewReplacer(`\\`, `\`, `\.`, `.`, `.`, "\000")

func split(key string) []string {
	return strings.Split(replacer.Replace(key), "\000")
}

func (c countersCollector) Collect(ch chan<- prometheus.Metric) {
	for k, n := range c.c.Counts() {
		if c.nLabels > 1 {
			labels := split(k)
			if len(labels) != c.nLabels {
				err := fmt.Errorf("wrong number of labels in MultiCounters key: %d != %d (key=%q)", len(labels), c.nLabels, k)
				ch <- prometheus.NewInvalidMetric(c.desc, err)
				continue
			}
			ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(n), labels...)
			continue
		}
		ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(n), k)
	}
}

func newHistogram(opts prometheus.Opts, cutoffs []int64) (prometheus.Histogram, func(int64)) {
	buckets := make([]float64, len(cutoffs))
	for i := range cutoffs {
		buckets[i] = float64(cutoffs[i])
	}
	hOpts := prometheus.HistogramOpts{
		Namespace:   opts.Namespace,
		Subsystem:   opts.Subsystem,
		Name:        opts.Name,
		Help:        opts.Help,
		ConstLabels: opts.ConstLabels,
		Buckets:     buckets,
	}
	m := prometheus.NewHistogram(hOpts)
	return m, func(n int64) {
		m.Observe(float64(n))
	}
}

type histogramCollector struct {
	desc *prometheus.Desc
	h    *stats.Histogram
}

func newHistogramCollector(opts prometheus.Opts, h *stats.Histogram) histogramCollector {
	desc := prometheus.NewDesc(
		prometheus.BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
		opts.Help,
		nil,
		opts.ConstLabels,
	)
	return histogramCollector{
		desc: desc,
		h:    h,
	}
}

func histogramMetric(desc *prometheus.Desc, h *stats.Histogram, scale float64, labels ...string) prometheus.Metric {
	count := uint64(0)
	sum := float64(h.Total()) * scale
	cutoffs := h.Cutoffs()
	statBuckets := h.Buckets()
	promBuckets := make(map[float64]uint64, len(cutoffs))
	for i, cutoff := range cutoffs {
		upperBound := float64(cutoff) * scale
		count += uint64(statBuckets[i])
		promBuckets[upperBound] = count
	}
	count += uint64(statBuckets[len(statBuckets)-1])
	return prometheus.MustNewConstHistogram(desc, count, sum, promBuckets, labels...)
}

func (h histogramCollector) Describe(ch chan<- *prometheus.Desc) {
	ch <- h.desc
}

func (h histogramCollector) Collect(ch chan<- prometheus.Metric) {
	ch <- histogramMetric(h.desc, h.h, 1)
}

type timingsCollector struct {
	desc    *prometheus.Desc
	t       *stats.Timings
	nLabels int
}

func newTimingsCollector(opts prometheus.Opts, t *stats.Timings, labels ...string) prometheus.Collector {
	desc := prometheus.NewDesc(
		prometheus.BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
		opts.Help,
		labels,
		opts.ConstLabels,
	)
	return timingsCollector{
		desc:    desc,
		t:       t,
		nLabels: len(labels),
	}
}

func (c timingsCollector) Describe(ch chan<- *prometheus.Desc) {
	ch <- c.desc
}

func (c timingsCollector) Collect(ch chan<- prometheus.Metric) {
	for k, h := range c.t.Histograms() {
		if c.nLabels > 1 {
			labels := split(k)
			if len(labels) != c.nLabels {
				err := fmt.Errorf("wrong number of labels in MultiTimings key: %d != %d (key=%q)", len(labels), c.nLabels, k)
				ch <- prometheus.NewInvalidMetric(c.desc, err)
				continue
			}
			ch <- histogramMetric(c.desc, h, 1/float64(time.Second), labels...)
			continue
		}
		ch <- histogramMetric(c.desc, h, 1/float64(time.Second), k)
	}
}
<|endoftext|>


<commit_before>// Convenience utilities for testing.
package testutils

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"runtime"
	"strings"
	"sync"
	"text/template"
	"time"

	"github.com/google/uuid"
	"github.com/stretchr/testify/mock"
	"github.com/stretchr/testify/require"
	"go.skia.org/infra/go/repo_root"
	"go.skia.org/infra/go/sktest"
)

var (
	// TryAgainErr use used by TryUntil.
	TryAgainErr = errors.New("Trying Again")
)

// TestDataDir returns the path to the caller's testdata directory, which
// is assumed to be "<path to caller dir>/testdata".
func TestDataDir() (string, error) {
	_, thisFile, _, ok := runtime.Caller(0)
	if !ok {
		return "", fmt.Errorf("Could not find test data dir: runtime.Caller() failed.")
	}
	for skip := 0; ; skip++ {
		_, file, _, ok := runtime.Caller(skip)
		if !ok {
			return "", fmt.Errorf("Could not find test data dir: runtime.Caller() failed.")
		}
		if file != thisFile {
			return path.Join(path.Dir(file), "testdata"), nil
		}
	}
}

func readFile(filename string) (io.ReadCloser, error) {
	dir, err := TestDataDir()
	if err != nil {
		return nil, fmt.Errorf("Could not read %s: %v", filename, err)
	}
	f, err := os.Open(path.Join(dir, filename))
	if err != nil {
		return nil, fmt.Errorf("Could not read %s: %v", filename, err)
	}
	return f, nil
}

// ReadFileBytes reads a file from the caller's testdata directory and returns its contents as a
// slice of bytes.
func ReadFileBytes(filename string) ([]byte, error) {
	f, err := readFile(filename)
	if err != nil {
		return nil, err
	}
	b, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, fmt.Errorf("Could not read %s: %v", filename, err)
	}
	return b, nil
}

// ReadFile reads a file from the caller's testdata directory.
func ReadFile(filename string) (string, error) {
	b, err := ReadFileBytes(filename)
	if err != nil {
		return "", err
	}
	return string(b), nil
}

// MustGetReader reads a file from the caller's testdata directory and panics on
// error.
func MustGetReader(filename string) io.ReadCloser {
	r, err := readFile(filename)
	if err != nil {
		panic(err)
	}
	return r
}

// MustReadFile returns  from the caller's testdata directory and panics on
// error.
func MustReadFile(filename string) string {
	s, err := ReadFile(filename)
	if err != nil {
		panic(err)
	}
	return s
}

// ReadJsonFile reads a JSON file from the caller's testdata directory into the
// given interface.
func ReadJsonFile(filename string, dest interface{}) error {
	f, err := readFile(filename)
	if err != nil {
		return err
	}
	return json.NewDecoder(f).Decode(dest)
}

// MustReadJsonFile reads a JSON file from the caller's testdata directory into
// the given interface and panics on error.
func MustReadJsonFile(filename string, dest interface{}) {
	if err := ReadJsonFile(filename, dest); err != nil {
		panic(err)
	}
}

// WriteFile writes the given contents to the given file path, reporting any
// error.
func WriteFile(t sktest.TestingT, filename, contents string) {
	require.NoErrorf(t, ioutil.WriteFile(filename, []byte(contents), os.ModePerm), "Unable to write to file %s", filename)
}

// AssertCloses takes an ioutil.Closer and asserts that it closes. E.g.:
// frobber := NewFrobber()
// defer testutils.AssertCloses(t, frobber)
func AssertCloses(t sktest.TestingT, c io.Closer) {
	require.NoError(t, c.Close())
}

// Remove attempts to remove the given file and asserts that no error is returned.
func Remove(t sktest.TestingT, fp string) {
	require.NoError(t, os.Remove(fp))
}

// RemoveAll attempts to remove the given directory and asserts that no error is returned.
func RemoveAll(t sktest.TestingT, fp string) {
	require.NoError(t, os.RemoveAll(fp))
}

// TempDir is a wrapper for ioutil.TempDir. Returns the path to the directory and a cleanup
// function to defer.
func TempDir(t sktest.TestingT) (string, func()) {
	d, err := ioutil.TempDir("", "testutils")
	require.NoError(t, err)
	return d, func() {
		RemoveAll(t, d)
	}
}

// MarshalJSON encodes the given interface to a JSON string.
func MarshalJSON(t sktest.TestingT, i interface{}) string {
	b, err := json.Marshal(i)
	require.NoError(t, err)
	return string(b)
}

// MarshalIndentJSON encodes the given interface to an indented JSON string.
func MarshalIndentJSON(t sktest.TestingT, i interface{}) string {
	b, err := json.MarshalIndent(i, "", "  ")
	require.NoError(t, err)
	return string(b)
}

// AssertErrorContains asserts that the given error contains the given string.
func AssertErrorContains(t sktest.TestingT, err error, substr string) {
	require.NotNil(t, err)
	require.True(t, strings.Contains(err.Error(), substr))
}

// Return the path to the root of the checkout.
func GetRepoRoot(t sktest.TestingT) string {
	root, err := repo_root.Get()
	require.NoError(t, err)
	return root
}

// EventuallyConsistent tries a test repeatedly until either the test passes
// or time expires, and is used when tests are written to expect
// non-eventual consistency.
//
// Use this function sparingly.
//
// duration - The amount of time to keep trying.
// f - The func to run the tests, should return TryAgainErr if
//     we should keep trying, otherwise TryUntil will return
//     with the err that f() returns.
func EventuallyConsistent(duration time.Duration, f func() error) error {
	begin := time.Now()
	for time.Now().Sub(begin) < duration {
		if err := f(); err != TryAgainErr {
			return err
		}
	}
	return fmt.Errorf("Failed to pass test in allotted time.")
}

// MockTestingT implements sktest.TestingT by saving calls to Log and Fail. MockTestingT can
// be used to test a test helper function. See also AssertFails.
// The methods Helper, Name, Skip, SkipNow, Skipf, and Skipped are unimplemented.
// This type is not safe for concurrent use.
type MockTestingT struct {
	LogMsgs  []string
	IsFailed bool
}

func (m *MockTestingT) Error(args ...interface{}) {
	m.Log(args...)
	m.Fail()
}
func (m *MockTestingT) Errorf(format string, args ...interface{}) {
	m.Logf(format, args...)
	m.Fail()
}
func (m *MockTestingT) Fail() {
	m.IsFailed = true
}
func (m *MockTestingT) FailNow() {
	m.Fail()
	runtime.Goexit()
}
func (m *MockTestingT) Failed() bool {
	return m.IsFailed
}
func (m *MockTestingT) Fatal(args ...interface{}) {
	m.Log(args...)
	m.FailNow()
}
func (m *MockTestingT) Fatalf(format string, args ...interface{}) {
	m.Logf(format, args...)
	m.FailNow()
}
func (m *MockTestingT) Helper() {}
func (m *MockTestingT) Log(args ...interface{}) {
	m.LogMsgs = append(m.LogMsgs, fmt.Sprintln(args...))
}
func (m *MockTestingT) Logf(format string, args ...interface{}) {
	m.LogMsgs = append(m.LogMsgs, fmt.Sprintf(format, args...))
}
func (m *MockTestingT) Name() string {
	return ""
}
func (m *MockTestingT) Skip(args ...interface{}) {
	m.Log(args...)
	m.SkipNow()
}
func (m *MockTestingT) SkipNow() {
	panic("SkipNow is not implemented.")
}
func (m *MockTestingT) Skipf(format string, args ...interface{}) {
	m.Logf(format, args...)
	m.SkipNow()
}
func (m *MockTestingT) Skipped() bool {
	return false
}

// Assert that MockTestingT implements the sktest.TestingT interface:
var _ sktest.TestingT = (*MockTestingT)(nil)

// AssertFails runs testfn with a MockTestingT and asserts that the test fails and the first failure
// logged matches the regexp. The sktest.TestingT passed to testfn is not safe for concurrent use.
func AssertFails(parent sktest.TestingT, regexp string, testfn func(sktest.TestingT)) {
	mock := MockTestingT{}
	wg := sync.WaitGroup{}
	wg.Add(1)
	go func() {
		defer wg.Done()
		testfn(&mock)
	}()
	wg.Wait()
	require.True(parent, mock.Failed(), "In AssertFails, the test function did not fail.")
	require.True(parent, len(mock.LogMsgs) > 0, "In AssertFails, the test function did not produce any failure messages.")
	require.Regexp(parent, regexp, mock.LogMsgs[0])
}

// AnyContext can be used to match any Context objects e.g.
// m.On("Foo", testutils.AnyContext).Return(...)
// This is better than trying to used mock.AnythingOfTypeArgument
// because that only works for concrete types, which could be brittle
// (e.g. a "normal" context is *context.emptyCtx, but one modified by
// trace.StartSpan() could be a *context.valueCtx)
var AnyContext = mock.MatchedBy(func(c context.Context) bool {
	// if the passed in parameter does not implement the context.Context interface, the
	// wrapping MatchedBy will panic - so we can simply return true, since we
	// know it's a context.Context if execution flow makes it here.
	return true
})

// ExecTemplate parses the given string as a text template, executes it using
// the given data, and returns the result as a string.
func ExecTemplate(t sktest.TestingT, tmpl string, data interface{}) string {
	template, err := template.New(uuid.New().String()).Parse(tmpl)
	require.NoError(t, err)
	var buf bytes.Buffer
	require.NoError(t, template.Execute(&buf, data))
	return buf.String()
}
<commit_msg>[infra] Fix use of "path" where "filepath" was meant.<commit_after>// Package testutils contains convenience utilities for testing.
package testutils

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"text/template"
	"time"

	"github.com/google/uuid"
	"github.com/stretchr/testify/mock"
	"github.com/stretchr/testify/require"
	"go.skia.org/infra/go/repo_root"
	"go.skia.org/infra/go/sktest"
)

var (
	// TryAgainErr use used by TryUntil.
	TryAgainErr = errors.New("Trying Again")
)

// TestDataDir returns the path to the caller's testdata directory, which
// is assumed to be "<path to caller dir>/testdata".
func TestDataDir() (string, error) {
	_, thisFile, _, ok := runtime.Caller(0)
	if !ok {
		return "", fmt.Errorf("Could not find test data dir: runtime.Caller() failed.")
	}
	for skip := 0; ; skip++ {
		_, file, _, ok := runtime.Caller(skip)
		if !ok {
			return "", fmt.Errorf("Could not find test data dir: runtime.Caller() failed.")
		}
		if file != thisFile {
			return filepath.Join(filepath.Dir(file), "testdata"), nil
		}
	}
}

func readFile(filename string) (io.ReadCloser, error) {
	dir, err := TestDataDir()
	if err != nil {
		return nil, fmt.Errorf("Could not read %s: %v", filename, err)
	}
	f, err := os.Open(filepath.Join(dir, filename))
	if err != nil {
		return nil, fmt.Errorf("Could not read %s: %v", filename, err)
	}
	return f, nil
}

// ReadFileBytes reads a file from the caller's testdata directory and returns its contents as a
// slice of bytes.
func ReadFileBytes(filename string) ([]byte, error) {
	f, err := readFile(filename)
	if err != nil {
		return nil, err
	}
	b, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, fmt.Errorf("Could not read %s: %v", filename, err)
	}
	return b, nil
}

// ReadFile reads a file from the caller's testdata directory.
func ReadFile(filename string) (string, error) {
	b, err := ReadFileBytes(filename)
	if err != nil {
		return "", err
	}
	return string(b), nil
}

// MustGetReader reads a file from the caller's testdata directory and panics on
// error.
func MustGetReader(filename string) io.ReadCloser {
	r, err := readFile(filename)
	if err != nil {
		panic(err)
	}
	return r
}

// MustReadFile returns  from the caller's testdata directory and panics on
// error.
func MustReadFile(filename string) string {
	s, err := ReadFile(filename)
	if err != nil {
		panic(err)
	}
	return s
}

// ReadJsonFile reads a JSON file from the caller's testdata directory into the
// given interface.
func ReadJsonFile(filename string, dest interface{}) error {
	f, err := readFile(filename)
	if err != nil {
		return err
	}
	return json.NewDecoder(f).Decode(dest)
}

// MustReadJsonFile reads a JSON file from the caller's testdata directory into
// the given interface and panics on error.
func MustReadJsonFile(filename string, dest interface{}) {
	if err := ReadJsonFile(filename, dest); err != nil {
		panic(err)
	}
}

// WriteFile writes the given contents to the given file path, reporting any
// error.
func WriteFile(t sktest.TestingT, filename, contents string) {
	require.NoErrorf(t, ioutil.WriteFile(filename, []byte(contents), os.ModePerm), "Unable to write to file %s", filename)
}

// AssertCloses takes an ioutil.Closer and asserts that it closes. E.g.:
// frobber := NewFrobber()
// defer testutils.AssertCloses(t, frobber)
func AssertCloses(t sktest.TestingT, c io.Closer) {
	require.NoError(t, c.Close())
}

// Remove attempts to remove the given file and asserts that no error is returned.
func Remove(t sktest.TestingT, fp string) {
	require.NoError(t, os.Remove(fp))
}

// RemoveAll attempts to remove the given directory and asserts that no error is returned.
func RemoveAll(t sktest.TestingT, fp string) {
	require.NoError(t, os.RemoveAll(fp))
}

// TempDir is a wrapper for ioutil.TempDir. Returns the path to the directory and a cleanup
// function to defer.
func TempDir(t sktest.TestingT) (string, func()) {
	d, err := ioutil.TempDir("", "testutils")
	require.NoError(t, err)
	return d, func() {
		RemoveAll(t, d)
	}
}

// MarshalJSON encodes the given interface to a JSON string.
func MarshalJSON(t sktest.TestingT, i interface{}) string {
	b, err := json.Marshal(i)
	require.NoError(t, err)
	return string(b)
}

// MarshalIndentJSON encodes the given interface to an indented JSON string.
func MarshalIndentJSON(t sktest.TestingT, i interface{}) string {
	b, err := json.MarshalIndent(i, "", "  ")
	require.NoError(t, err)
	return string(b)
}

// AssertErrorContains asserts that the given error contains the given string.
func AssertErrorContains(t sktest.TestingT, err error, substr string) {
	require.NotNil(t, err)
	require.True(t, strings.Contains(err.Error(), substr))
}

// Return the path to the root of the checkout.
func GetRepoRoot(t sktest.TestingT) string {
	root, err := repo_root.Get()
	require.NoError(t, err)
	return root
}

// EventuallyConsistent tries a test repeatedly until either the test passes
// or time expires, and is used when tests are written to expect
// non-eventual consistency.
//
// Use this function sparingly.
//
// duration - The amount of time to keep trying.
// f - The func to run the tests, should return TryAgainErr if
//     we should keep trying, otherwise TryUntil will return
//     with the err that f() returns.
func EventuallyConsistent(duration time.Duration, f func() error) error {
	begin := time.Now()
	for time.Now().Sub(begin) < duration {
		if err := f(); err != TryAgainErr {
			return err
		}
	}
	return fmt.Errorf("Failed to pass test in allotted time.")
}

// MockTestingT implements sktest.TestingT by saving calls to Log and Fail. MockTestingT can
// be used to test a test helper function. See also AssertFails.
// The methods Helper, Name, Skip, SkipNow, Skipf, and Skipped are unimplemented.
// This type is not safe for concurrent use.
type MockTestingT struct {
	LogMsgs  []string
	IsFailed bool
}

func (m *MockTestingT) Error(args ...interface{}) {
	m.Log(args...)
	m.Fail()
}
func (m *MockTestingT) Errorf(format string, args ...interface{}) {
	m.Logf(format, args...)
	m.Fail()
}
func (m *MockTestingT) Fail() {
	m.IsFailed = true
}
func (m *MockTestingT) FailNow() {
	m.Fail()
	runtime.Goexit()
}
func (m *MockTestingT) Failed() bool {
	return m.IsFailed
}
func (m *MockTestingT) Fatal(args ...interface{}) {
	m.Log(args...)
	m.FailNow()
}
func (m *MockTestingT) Fatalf(format string, args ...interface{}) {
	m.Logf(format, args...)
	m.FailNow()
}
func (m *MockTestingT) Helper() {}
func (m *MockTestingT) Log(args ...interface{}) {
	m.LogMsgs = append(m.LogMsgs, fmt.Sprintln(args...))
}
func (m *MockTestingT) Logf(format string, args ...interface{}) {
	m.LogMsgs = append(m.LogMsgs, fmt.Sprintf(format, args...))
}
func (m *MockTestingT) Name() string {
	return ""
}
func (m *MockTestingT) Skip(args ...interface{}) {
	m.Log(args...)
	m.SkipNow()
}
func (m *MockTestingT) SkipNow() {
	panic("SkipNow is not implemented.")
}
func (m *MockTestingT) Skipf(format string, args ...interface{}) {
	m.Logf(format, args...)
	m.SkipNow()
}
func (m *MockTestingT) Skipped() bool {
	return false
}

// Assert that MockTestingT implements the sktest.TestingT interface:
var _ sktest.TestingT = (*MockTestingT)(nil)

// AssertFails runs testfn with a MockTestingT and asserts that the test fails and the first failure
// logged matches the regexp. The sktest.TestingT passed to testfn is not safe for concurrent use.
func AssertFails(parent sktest.TestingT, regexp string, testfn func(sktest.TestingT)) {
	mock := MockTestingT{}
	wg := sync.WaitGroup{}
	wg.Add(1)
	go func() {
		defer wg.Done()
		testfn(&mock)
	}()
	wg.Wait()
	require.True(parent, mock.Failed(), "In AssertFails, the test function did not fail.")
	require.True(parent, len(mock.LogMsgs) > 0, "In AssertFails, the test function did not produce any failure messages.")
	require.Regexp(parent, regexp, mock.LogMsgs[0])
}

// AnyContext can be used to match any Context objects e.g.
// m.On("Foo", testutils.AnyContext).Return(...)
// This is better than trying to used mock.AnythingOfTypeArgument
// because that only works for concrete types, which could be brittle
// (e.g. a "normal" context is *context.emptyCtx, but one modified by
// trace.StartSpan() could be a *context.valueCtx)
var AnyContext = mock.MatchedBy(func(c context.Context) bool {
	// if the passed in parameter does not implement the context.Context interface, the
	// wrapping MatchedBy will panic - so we can simply return true, since we
	// know it's a context.Context if execution flow makes it here.
	return true
})

// ExecTemplate parses the given string as a text template, executes it using
// the given data, and returns the result as a string.
func ExecTemplate(t sktest.TestingT, tmpl string, data interface{}) string {
	template, err := template.New(uuid.New().String()).Parse(tmpl)
	require.NoError(t, err)
	var buf bytes.Buffer
	require.NoError(t, template.Execute(&buf, data))
	return buf.String()
}
<|endoftext|>


<commit_before>package codegen

import (
	"bytes"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"unicode"

	"github.com/goadesign/goa/design"
	"github.com/goadesign/goa/version"
)

// CheckVersion returns an error if the ver is empty, contains an incorrect value or
// a version number that is not compatible with the version of this repo.
func CheckVersion(ver string) error {
	compat, err := version.Compatible(ver)
	if err != nil {
		return err
	}
	if !compat {
		return fmt.Errorf("version mismatch: using goagen %s to generate code that compiles with goa %s",
			ver, version.String())
	}
	return nil
}

// CommandLine return the command used to run this process.
func CommandLine() string {
	// We don't use the full path to the tool so that running goagen multiple times doesn't
	// end up creating different command line comments (because of the temporary directory it
	// runs in).
	var param string
	if len(os.Args) > 1 {
		args := make([]string, len(os.Args)-1)
		gopaths := filepath.SplitList(os.Getenv("GOPATH"))
		for i, a := range os.Args[1:] {
			for _, p := range gopaths {
				if strings.Contains(a, p) {
					args[i] = strings.Replace(a, p, "$(GOPATH)", -1)
					break
				}
			}
			if args[i] == "" {
				args[i] = a
			}
		}
		param = strings.Join(args, " ")
	}
	cmd := fmt.Sprintf("$ %s %s", filepath.Base(os.Args[0]), param)
	return strings.Replace(cmd, " --", "\n\t--", -1)
}

// Comment produces line comments by concatenating the given strings and producing 80 characters
// long lines starting with "//"
func Comment(elems ...string) string {
	var lines []string
	for _, e := range elems {
		lines = append(lines, strings.Split(e, "\n")...)
	}
	var trimmed = make([]string, len(lines))
	for i, l := range lines {
		trimmed[i] = strings.TrimLeft(l, " \t")
	}
	t := strings.Join(trimmed, "\n")

	return Indent(t, "// ")
}

// Indent inserts prefix at the beginning of each non-empty line of s. The
// end-of-line marker is NL.
func Indent(s, prefix string) string {
	return string(IndentBytes([]byte(s), []byte(prefix)))
}

// IndentBytes inserts prefix at the beginning of each non-empty line of b.
// The end-of-line marker is NL.
func IndentBytes(b, prefix []byte) []byte {
	var res []byte
	bol := true
	for _, c := range b {
		if bol && c != '\n' {
			res = append(res, prefix...)
		}
		res = append(res, c)
		bol = c == '\n'
	}
	return res
}

// Tabs returns a string made of depth tab characters.
func Tabs(depth int) string {
	var tabs string
	for i := 0; i < depth; i++ {
		tabs += "\t"
	}
	//	return fmt.Sprintf("%d%s", depth, tabs)
	return tabs
}

// Add adds two integers and returns the sum of the two.
func Add(a, b int) int { return a + b }

// CanonicalTemplate returns the resource URI template as a format string suitable for use in the
// fmt.Printf function family.
func CanonicalTemplate(r *design.ResourceDefinition) string {
	return design.WildcardRegex.ReplaceAllLiteralString(r.URITemplate(), "/%v")
}

// CanonicalParams returns the list of parameter names needed to build the canonical href to the
// resource. It returns nil if the resource does not have a canonical action.
func CanonicalParams(r *design.ResourceDefinition) []string {
	var params []string
	if ca := r.CanonicalAction(); ca != nil {
		if len(ca.Routes) > 0 {
			params = ca.Routes[0].Params()
		}
		for i, p := range params {
			params[i] = Goify(p, false)
		}
	}
	return params
}

// Casing exceptions
var toLower = map[string]string{"OAuth": "oauth"}

// SnakeCase produces the snake_case version of the given CamelCase string.
func SnakeCase(name string) string {
	for u, l := range toLower {
		name = strings.Replace(name, u, l, -1)
	}
	var b bytes.Buffer
	var lastUnderscore bool
	ln := len(name)
	if ln == 0 {
		return ""
	}
	b.WriteRune(unicode.ToLower(rune(name[0])))
	for i := 1; i < ln; i++ {
		r := rune(name[i])
		nextIsLower := false
		if i < ln-1 {
			n := rune(name[i+1])
			nextIsLower = unicode.IsLower(n) && unicode.IsLetter(n)
		}
		if unicode.IsUpper(r) {
			if !lastUnderscore && nextIsLower {
				b.WriteRune('_')
				lastUnderscore = true
			}
			b.WriteRune(unicode.ToLower(r))
		} else {
			b.WriteRune(r)
			lastUnderscore = false
		}
	}
	return b.String()
}
<commit_msg>Remove .exe suffix from goagen output (#589)<commit_after>package codegen

import (
	"bytes"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"unicode"

	"github.com/goadesign/goa/design"
	"github.com/goadesign/goa/version"
)

// CheckVersion returns an error if the ver is empty, contains an incorrect value or
// a version number that is not compatible with the version of this repo.
func CheckVersion(ver string) error {
	compat, err := version.Compatible(ver)
	if err != nil {
		return err
	}
	if !compat {
		return fmt.Errorf("version mismatch: using goagen %s to generate code that compiles with goa %s",
			ver, version.String())
	}
	return nil
}

// CommandLine return the command used to run this process.
func CommandLine() string {
	// We don't use the full path to the tool so that running goagen multiple times doesn't
	// end up creating different command line comments (because of the temporary directory it
	// runs in).
	var param string

	if len(os.Args) > 1 {
		args := make([]string, len(os.Args)-1)
		gopaths := filepath.SplitList(os.Getenv("GOPATH"))
		for i, a := range os.Args[1:] {
			for _, p := range gopaths {
				if strings.Contains(a, p) {
					args[i] = strings.Replace(a, p, "$(GOPATH)", -1)
					break
				}
			}
			if args[i] == "" {
				args[i] = a
			}
		}
		param = strings.Join(args, " ")
	}
	rawcmd := filepath.Base(os.Args[0])
	// Remove possible .exe suffix to not create different ouptut just because
	// you ran goagen on Windows.
	rawcmd = strings.TrimSuffix(rawcmd, ".exe")

	cmd := fmt.Sprintf("$ %s %s", rawcmd, param)
	return strings.Replace(cmd, " --", "\n\t--", -1)
}

// Comment produces line comments by concatenating the given strings and producing 80 characters
// long lines starting with "//"
func Comment(elems ...string) string {
	var lines []string
	for _, e := range elems {
		lines = append(lines, strings.Split(e, "\n")...)
	}
	var trimmed = make([]string, len(lines))
	for i, l := range lines {
		trimmed[i] = strings.TrimLeft(l, " \t")
	}
	t := strings.Join(trimmed, "\n")

	return Indent(t, "// ")
}

// Indent inserts prefix at the beginning of each non-empty line of s. The
// end-of-line marker is NL.
func Indent(s, prefix string) string {
	return string(IndentBytes([]byte(s), []byte(prefix)))
}

// IndentBytes inserts prefix at the beginning of each non-empty line of b.
// The end-of-line marker is NL.
func IndentBytes(b, prefix []byte) []byte {
	var res []byte
	bol := true
	for _, c := range b {
		if bol && c != '\n' {
			res = append(res, prefix...)
		}
		res = append(res, c)
		bol = c == '\n'
	}
	return res
}

// Tabs returns a string made of depth tab characters.
func Tabs(depth int) string {
	var tabs string
	for i := 0; i < depth; i++ {
		tabs += "\t"
	}
	//	return fmt.Sprintf("%d%s", depth, tabs)
	return tabs
}

// Add adds two integers and returns the sum of the two.
func Add(a, b int) int { return a + b }

// CanonicalTemplate returns the resource URI template as a format string suitable for use in the
// fmt.Printf function family.
func CanonicalTemplate(r *design.ResourceDefinition) string {
	return design.WildcardRegex.ReplaceAllLiteralString(r.URITemplate(), "/%v")
}

// CanonicalParams returns the list of parameter names needed to build the canonical href to the
// resource. It returns nil if the resource does not have a canonical action.
func CanonicalParams(r *design.ResourceDefinition) []string {
	var params []string
	if ca := r.CanonicalAction(); ca != nil {
		if len(ca.Routes) > 0 {
			params = ca.Routes[0].Params()
		}
		for i, p := range params {
			params[i] = Goify(p, false)
		}
	}
	return params
}

// Casing exceptions
var toLower = map[string]string{"OAuth": "oauth"}

// SnakeCase produces the snake_case version of the given CamelCase string.
func SnakeCase(name string) string {
	for u, l := range toLower {
		name = strings.Replace(name, u, l, -1)
	}
	var b bytes.Buffer
	var lastUnderscore bool
	ln := len(name)
	if ln == 0 {
		return ""
	}
	b.WriteRune(unicode.ToLower(rune(name[0])))
	for i := 1; i < ln; i++ {
		r := rune(name[i])
		nextIsLower := false
		if i < ln-1 {
			n := rune(name[i+1])
			nextIsLower = unicode.IsLower(n) && unicode.IsLetter(n)
		}
		if unicode.IsUpper(r) {
			if !lastUnderscore && nextIsLower {
				b.WriteRune('_')
				lastUnderscore = true
			}
			b.WriteRune(unicode.ToLower(r))
		} else {
			b.WriteRune(r)
			lastUnderscore = false
		}
	}
	return b.String()
}
<|endoftext|>


<commit_before>package main

import (
	"google.golang.org/grpc"

	pb "github.com/brotherlogic/cardserver/card"
)

// DoRegister Registers this server
func (s *Server) DoRegister(server *grpc.Server) {
	pb.RegisterCardServiceServer(server, s)
}

// ReportHealth Determines if the server is healthy
func (s *Server) ReportHealth() bool {
	return true
}

// SaveCardList stores the cardlist
func (s *Server) SaveCardList() {
	s.Save("github.com/brotherlogic/cardserver/cards", s.cards)
}

func main() {
	server := InitServer()
	server.PrepServer()
	server.RegisterServer("cardserver", false)
	server.Serve()
}
<commit_msg>Added client save<commit_after>package main

import (
	"github.com/brotherlogic/keystore/client"
	"google.golang.org/grpc"

	pb "github.com/brotherlogic/cardserver/card"
)

// DoRegister Registers this server
func (s *Server) DoRegister(server *grpc.Server) {
	pb.RegisterCardServiceServer(server, s)
}

// ReportHealth Determines if the server is healthy
func (s *Server) ReportHealth() bool {
	return true
}

// SaveCardList stores the cardlist
func (s *Server) SaveCardList() {
	s.Save("github.com/brotherlogic/cardserver/cards", s.cards)
}

func main() {
	server := InitServer()
	server.GoServer.KSclient = *keystoreclient.GetClient()
	server.PrepServer()
	server.RegisterServer("cardserver", false)
	server.Serve()
}
<|endoftext|>


<commit_before>package api

// NetworkZonesPost represents the fields of a new LXD network zone
//
// swagger:model
//
// API extension: network_dns
type NetworkZonesPost struct {
	NetworkZonePut `yaml:",inline"`

	// The name of the zone (DNS domain name)
	// Example: example.net
	Name string `json:"name" yaml:"name"`
}

// NetworkZonePut represents the modifiable fields of a LXD network zone
//
// swagger:model
//
// API extension: network_dns
type NetworkZonePut struct {
	// Description of the network zone
	// Example: Internal domain
	Description string `json:"description" yaml:"description"`

	// Zone configuration map (refer to doc/network-zones.md)
	// Example: {"user.mykey": "foo"}
	Config map[string]string `json:"config" yaml:"config"`
}

// NetworkZone represents a network zone (DNS).
//
// swagger:model
//
// API extension: network_dns
type NetworkZone struct {
	NetworkZonePut `yaml:",inline"`

	// The name of the zone (DNS domain name)
	// Example: example.net
	Name string `json:"name" yaml:"name"`

	// List of URLs of objects using this network zone
	// Read only: true
	// Example: ["/1.0/networks/foo", "/1.0/networks/bar"]
	UsedBy []string `json:"used_by" yaml:"used_by"` // Resources that use the zone.
}

// Writable converts a full NetworkZone struct into a NetworkZonePut struct (filters read-only fields).
func (f *NetworkZone) Writable() NetworkZonePut {
	return f.NetworkZonePut
}
<commit_msg>shared/api: Add network zone record structs<commit_after>package api

// NetworkZonesPost represents the fields of a new LXD network zone
//
// swagger:model
//
// API extension: network_dns
type NetworkZonesPost struct {
	NetworkZonePut `yaml:",inline"`

	// The name of the zone (DNS domain name)
	// Example: example.net
	Name string `json:"name" yaml:"name"`
}

// NetworkZonePut represents the modifiable fields of a LXD network zone
//
// swagger:model
//
// API extension: network_dns
type NetworkZonePut struct {
	// Description of the network zone
	// Example: Internal domain
	Description string `json:"description" yaml:"description"`

	// Zone configuration map (refer to doc/network-zones.md)
	// Example: {"user.mykey": "foo"}
	Config map[string]string `json:"config" yaml:"config"`
}

// NetworkZone represents a network zone (DNS).
//
// swagger:model
//
// API extension: network_dns
type NetworkZone struct {
	NetworkZonePut `yaml:",inline"`

	// The name of the zone (DNS domain name)
	// Example: example.net
	Name string `json:"name" yaml:"name"`

	// List of URLs of objects using this network zone
	// Read only: true
	// Example: ["/1.0/networks/foo", "/1.0/networks/bar"]
	UsedBy []string `json:"used_by" yaml:"used_by"` // Resources that use the zone.
}

// Writable converts a full NetworkZone struct into a NetworkZonePut struct (filters read-only fields).
func (f *NetworkZone) Writable() NetworkZonePut {
	return f.NetworkZonePut
}

// NetworkZoneRecordsPost represents the fields of a new LXD network zone record
//
// swagger:model
//
// API extension: network_dns_records
type NetworkZoneRecordsPost struct {
	NetworkZoneRecordPut `yaml:",inline"`

	// The record name in the zone
	// Example: @
	Name string `json:"name" yaml:"name"`
}

// NetworkZoneRecordPut represents the modifiable fields of a LXD network zone record
//
// swagger:model
//
// API extension: network_dns_records
type NetworkZoneRecordPut struct {
	// Description of the record
	// Example: SPF record
	Description string `json:"description" yaml:"description"`

	// Entries in the record
	Entries []NetworkZoneRecordEntry `json:"entries" yaml:"entries"`

	// Advanced configuration for the record
	// Example: {"user.mykey": "foo"}
	Config map[string]string `json:"config" yaml:"config"`
}

// NetworkZoneRecordEntry represents the fields in a record entry
//
// swagger:model
//
// API extension: network_dns_records
type NetworkZoneRecordEntry struct {
	// Type of DNS entry
	// Example: TXT
	Type string `json:"type" yaml:"type"`

	// TTL for the entry
	// Example: 3600
	TTL uint64 `json:"ttl,omitempty" yaml:"ttl,omitempty"`

	// Value for the record
	// Example: v=spf1 mx ~all
	Value string `json:"value" yaml:"value"`
}

// NetworkZoneRecord represents a network zone (DNS) record.
//
// swagger:model
//
// API extension: network_dns_records
type NetworkZoneRecord struct {
	NetworkZoneRecordPut `yaml:",inline"`

	// The name of the record
	// Example: @
	Name string `json:"name" yaml:"name"`
}

// Writable converts a full NetworkZoneRecord struct into a NetworkZoneRecordPut struct (filters read-only fields).
func (f *NetworkZoneRecord) Writable() NetworkZoneRecordPut {
	return f.NetworkZoneRecordPut
}
<|endoftext|>