<commit_before>package main

import (
	"errors"
	"github.com/joho/godotenv"
	"github.com/stretchr/testify/assert"
	"os"
	"testing"
)

func NewTestChatworkNotifier() *ChatworkNotifier {
	godotenv.Load()

	apiToken := os.Getenv("CHATWORK_API_TOKEN")
	roomId := os.Getenv("CHATWORK_ROOM_ID")

	if len(apiToken) == 0 || len(roomId) == 0 {
		return nil
	}
	return NewChatworkNotifier(apiToken, roomId)
}

func TestChatworkNotifier_PostStatus_True(t *testing.T) {
	notifier := NewTestChatworkNotifier()
	if notifier == nil {
		return
	}

	param := PostStatusParam{
		CheckUrl:          "https://www.google.co.jp/",
		BeforeStatusCode:  500,
		CurrentStatusCode: 200,
		HttpError:         nil,
	}

	err := notifier.PostStatus(&param)
	assert.NoError(t, err)
}

func TestChatworkNotifier_PostStatus_False(t *testing.T) {
	notifier := NewTestChatworkNotifier()
	if notifier == nil {
		return
	}

	param := PostStatusParam{
		CheckUrl:          "https://www.google.co.jp/aaa",
		BeforeStatusCode:  0,
		CurrentStatusCode: 404,
		HttpError:         nil,
	}
	err := notifier.PostStatus(&param)
	assert.NoError(t, err)
}

func TestChatworkNotifier_PostStatus_HasError(t *testing.T) {
	notifier := NewTestChatworkNotifier()
	if notifier == nil {
		return
	}

	param := PostStatusParam{
		CheckUrl:          "https://aaaaaaaaa/",
		BeforeStatusCode:  0,
		CurrentStatusCode: 0,
		HttpError:         errors.New("Test"),
	}
	err := notifier.PostStatus(&param)
	assert.NoError(t, err)
}
<commit_msg>[Resolved] var roomId should be roomID<commit_after>package main

import (
	"errors"
	"github.com/joho/godotenv"
	"github.com/stretchr/testify/assert"
	"os"
	"testing"
)

func NewTestChatworkNotifier() *ChatworkNotifier {
	godotenv.Load()

	apiToken := os.Getenv("CHATWORK_API_TOKEN")
	roomID := os.Getenv("CHATWORK_ROOM_ID")

	if len(apiToken) == 0 || len(roomID) == 0 {
		return nil
	}
	return NewChatworkNotifier(apiToken, roomID)
}

func TestChatworkNotifier_PostStatus_True(t *testing.T) {
	notifier := NewTestChatworkNotifier()
	if notifier == nil {
		return
	}

	param := PostStatusParam{
		CheckUrl:          "https://www.google.co.jp/",
		BeforeStatusCode:  500,
		CurrentStatusCode: 200,
		HttpError:         nil,
	}

	err := notifier.PostStatus(&param)
	assert.NoError(t, err)
}

func TestChatworkNotifier_PostStatus_False(t *testing.T) {
	notifier := NewTestChatworkNotifier()
	if notifier == nil {
		return
	}

	param := PostStatusParam{
		CheckUrl:          "https://www.google.co.jp/aaa",
		BeforeStatusCode:  0,
		CurrentStatusCode: 404,
		HttpError:         nil,
	}
	err := notifier.PostStatus(&param)
	assert.NoError(t, err)
}

func TestChatworkNotifier_PostStatus_HasError(t *testing.T) {
	notifier := NewTestChatworkNotifier()
	if notifier == nil {
		return
	}

	param := PostStatusParam{
		CheckUrl:          "https://aaaaaaaaa/",
		BeforeStatusCode:  0,
		CurrentStatusCode: 0,
		HttpError:         errors.New("Test"),
	}
	err := notifier.PostStatus(&param)
	assert.NoError(t, err)
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 Laurent Moussault. All rights reserved.
// Licensed under a simplified BSD license (see LICENSE file).

package glam

import "github.com/drakmaniso/glam/math"

//------------------------------------------------------------------------------

// `Mat4` is a single-precision matrix with 4 columns and 4 rows.
//
// Note: matrices are stored in column-major order, so when writing literals
// remember to use the transpose.
type Mat4 [4][4]float32

//------------------------------------------------------------------------------

// `NewMat4` allocates and returns a new matrix. The elements are stored in
// alphabetical order (column-major order).
func NewMat4(
	a, e, i, m,
	b, f, j, n,
	c, g, k, o,
	d, h, l, p float32,
) *Mat4 {
	return &Mat4{
		{a, b, c, d},
		{e, f, g, h},
		{i, j, k, l},
		{m, n, o, p},
	}
}

// `MakeMat4` returns (by value) a matrix. The elements are stored in
// alphabetical order (column-major order).
func MakeMat4(
	a, e, i, m,
	b, f, j, n,
	c, g, k, o,
	d, h, l, p float32,
) Mat4 {
	return Mat4{
		{a, b, c, d},
		{e, f, g, h},
		{i, j, k, l},
		{m, n, o, p},
	}
}

// `SetTo` initializes `matrix`. The elements are stored in
// alphabetical order (column-major order).
func (matrix *Mat4) SetTo(
	a, e, i, m,
	b, f, j, n,
	c, g, k, o,
	d, h, l, p float32,
) {
	matrix[0][0] = a
	matrix[0][1] = b
	matrix[0][2] = c
	matrix[0][3] = d

	matrix[1][0] = e
	matrix[1][1] = f
	matrix[1][2] = g
	matrix[1][3] = h

	matrix[2][0] = i
	matrix[2][1] = j
	matrix[2][2] = k
	matrix[2][3] = l

	matrix[3][0] = m
	matrix[3][1] = n
	matrix[3][2] = o
	matrix[3][3] = p
}

//------------------------------------------------------------------------------

// `At` returns the element at '(row, column)`.
func (m Mat4) At(row, column int) float32 {
	return m[column][row]
}

// `Set` sets the element at `(row, column)` to `value`.
func (m *Mat4) Set(row, column int, value float32) {
	m[column][row] = value
}

//------------------------------------------------------------------------------

// `Perspective` returns (by value) a perspective projection matrix.
func Perspective(fieldOfView float32, aspectRatio float32, near float32, far float32) Mat4 {
	f := float32(1.0) / math.Tan(fieldOfView/float32(2.0))

	return Mat4{
		{f / aspectRatio, 0, 0, 0},
		{0, f, 0, 0},
		{0, 0, (far + near) / (near - far), -1},
		{0, 0, (2 * far * near) / (near - far), 0},
	}
}

// `SetToPerspective` sets `m` to a perspective projection matrix.
func (m *Mat4) SetToPerspective(fieldOfView float32, aspectRatio float32, near float32, far float32) {
	f := float32(1.0) / math.Tan(fieldOfView/float32(2.0))

	m[0][0] = f / aspectRatio
	m[0][1] = 0
	m[0][2] = 0
	m[0][3] = 0

	m[0][0] = 0
	m[0][1] = f
	m[0][2] = 0
	m[0][3] = 0

	m[0][0] = 0
	m[0][1] = 0
	m[0][2] = (far + near) / (near - far)
	m[0][3] = -1

	m[0][0] = 0
	m[0][1] = 0
	m[0][2] = (2 * far * near) / (near - far)
	m[0][3] = 0
}

//------------------------------------------------------------------------------
<commit_msg>Better comments.<commit_after>// Copyright (c) 2013 Laurent Moussault. All rights reserved.
// Licensed under a simplified BSD license (see LICENSE file).

package glam

import "github.com/drakmaniso/glam/math"

//------------------------------------------------------------------------------

// `Mat4` is a single-precision matrix with 4 columns and 4 rows.
//
// Note: matrices are stored in column-major order, so when writing literals
// remember to use the transpose.
type Mat4 [4][4]float32

//------------------------------------------------------------------------------

// `NewMat4` allocates and returns a new matrix. The elements are stored in
// alphabetical order (column-major order).
// See also `MakeMat4` and `SetTo`.
func NewMat4(
	a, e, i, m,
	b, f, j, n,
	c, g, k, o,
	d, h, l, p float32,
) *Mat4 {
	return &Mat4{
		{a, b, c, d},
		{e, f, g, h},
		{i, j, k, l},
		{m, n, o, p},
	}
}

// `MakeMat4` returns a matrix. The elements are stored in
// alphabetical order (column-major order).
// See also `NewMat4` and `SetTo`.
func MakeMat4(
	a, e, i, m,
	b, f, j, n,
	c, g, k, o,
	d, h, l, p float32,
) Mat4 {
	return Mat4{
		{a, b, c, d},
		{e, f, g, h},
		{i, j, k, l},
		{m, n, o, p},
	}
}

// `SetTo` initializes `matrix`. The elements are stored in
// alphabetical order (column-major order).
// See also `NewMat4` and `SetTo`.
func (matrix *Mat4) SetTo(
	a, e, i, m,
	b, f, j, n,
	c, g, k, o,
	d, h, l, p float32,
) {
	matrix[0][0] = a
	matrix[0][1] = b
	matrix[0][2] = c
	matrix[0][3] = d

	matrix[1][0] = e
	matrix[1][1] = f
	matrix[1][2] = g
	matrix[1][3] = h

	matrix[2][0] = i
	matrix[2][1] = j
	matrix[2][2] = k
	matrix[2][3] = l

	matrix[3][0] = m
	matrix[3][1] = n
	matrix[3][2] = o
	matrix[3][3] = p
}

//------------------------------------------------------------------------------

// `At` returns the element at '(row, column)`.
func (m Mat4) At(row, column int) float32 {
	return m[column][row]
}

// `Set` sets the element at `(row, column)` to `value`.
func (m *Mat4) Set(row, column int, value float32) {
	m[column][row] = value
}

//------------------------------------------------------------------------------

// `Perspective` returns a perspective projection matrix.
func Perspective(fieldOfView float32, aspectRatio float32, near float32, far float32) Mat4 {
	f := float32(1.0) / math.Tan(fieldOfView/float32(2.0))

	return Mat4{
		{f / aspectRatio, 0, 0, 0},
		{0, f, 0, 0},
		{0, 0, (far + near) / (near - far), -1},
		{0, 0, (2 * far * near) / (near - far), 0},
	}
}

// `SetToPerspective` sets `m` to a perspective projection matrix.
func (m *Mat4) SetToPerspective(fieldOfView float32, aspectRatio float32, near float32, far float32) {
	f := float32(1.0) / math.Tan(fieldOfView/float32(2.0))

	m[0][0] = f / aspectRatio
	m[0][1] = 0
	m[0][2] = 0
	m[0][3] = 0

	m[0][0] = 0
	m[0][1] = f
	m[0][2] = 0
	m[0][3] = 0

	m[0][0] = 0
	m[0][1] = 0
	m[0][2] = (far + near) / (near - far)
	m[0][3] = -1

	m[0][0] = 0
	m[0][1] = 0
	m[0][2] = (2 * far * near) / (near - far)
	m[0][3] = 0
}

//------------------------------------------------------------------------------
<|endoftext|>


<commit_before>package main

import (
	"github.com/hashicorp/terraform/helper/schema"
	"k8s.io/kubernetes/pkg/api"
)

func buildVolumes(userVolumes []interface{}) []api.Volume {
	volumes := make([]api.Volume, len(userVolumes))
	if len(userVolumes) == 0 {
		return volumes
	}

	for index, userVolume := range userVolumes {
		volumes[index] = buildVolume(userVolume.(map[string]interface{}))
	}

	return volumes
}

func buildVolume(userVolume map[string]interface{}) api.Volume {
	volume := api.Volume{
		Name:	userVolume["name"].(string),
	}
	volume.VolumeSource.populateVolumeSource(userVolume)
}

func (volume api.VolumeSource) populateVolumeSource(userVolumeSource map[string]interface{}) {

}

func buildPodSpec(podSpecs []interface{}) api.PodSpec {
	if len(podSpecs) == 0 {
		return api.PodSpec{}
	}
	userPodSpec := podSpecs[0].(map[string]interface{})

	podSpec := api.PodSpec{
		Containers:                    buildContainers(userPodSpec["containers"].([]interface{})),
		ActiveDeadlineSeconds:         nil,
		TerminationGracePeriodSeconds: nil,
	}

	if _, ok := userPodSpec["node_selector"]; ok {
		podSpec.NodeSelector = convertMapTypeToStringMap(userPodSpec["node_selector"].(map[string]interface{}))
	}
	if _, ok := userPodSpec["node_name"]; ok {
		podSpec.NodeName = userPodSpec["node_name"].(string)
	}
	if _, ok := userPodSpec["service_account_name"]; ok {
		podSpec.ServiceAccountName = userPodSpec["service_account_name"].(string)
	}
	if _, ok := userPodSpec["host_network"]; ok {
		podSpec.HostNetwork = userPodSpec["host_network"].(bool)
	}
	if _, ok := userPodSpec["termination_grace_period"]; ok {
		helper := int64(userPodSpec["termination_grace_period"].(int))
		podSpec.TerminationGracePeriodSeconds = &helper
		if helper > 0 {
			podSpec.TerminationGracePeriodSeconds = &helper
		} else {
			podSpec.TerminationGracePeriodSeconds = nil
		}
	} else {
		podSpec.TerminationGracePeriodSeconds = nil
	}
	if _, ok := userPodSpec["active_deadline_seconds"]; ok {
		helper := int64(userPodSpec["active_deadline_seconds"].(int))
		if helper > 0 {
			podSpec.ActiveDeadlineSeconds = &helper
		} else {
			podSpec.ActiveDeadlineSeconds = nil
		}
	} else {
		podSpec.ActiveDeadlineSeconds = nil
	}
	if _, ok := userPodSpec["restart_policy"]; ok {
		podSpec.RestartPolicy = api.RestartPolicy(userPodSpec["restart_policy"].(string))
	}

	return podSpec
}
<commit_msg>more volume mapping<commit_after>package main

import (
	"github.com/hashicorp/terraform/helper/schema"
	"k8s.io/kubernetes/pkg/api"
)

func buildVolumes(userVolumes []interface{}) []api.Volume {
	volumes := make([]api.Volume, len(userVolumes))
	if len(userVolumes) == 0 {
		return volumes
	}

	for index, userVolume := range userVolumes {
		volumes[index] = *buildVolume(userVolume.(map[string]interface{}))
	}

	return volumes
}

func buildVolume(userVolume map[string]interface{}) *api.Volume {
	return populateVolumeSource(&api.Volume{
			Name:	userVolume["name"].(string),
		}.(*api.VolumeSource), userVolume).(*api.Volume)
}

func populateVolumeSource(volumeSource *api.VolumeSource, userVolumeSource map[string]interface{}) *api.VolumeSource {
	if _, ok := userVolumeSource["host_path"]; ok {
		volumeSource.HostPath = buildHostPathVolumeSource(userVolumeSource["host_path"].(map[string]interface{}))
	}

	if _, ok := userVolumeSource["empty_dir"]; ok {
		volumeSource.EmptyDir = buildEmptyDirVolumeSource(userVolumeSource["empty_dir"].(map[string]interface{}))
	}

	if _, ok := userVolumeSource["host_path"]; ok {
		volumeSource.GCEPersistentDisk = buildGCEPersistentDiskVolumeSource(userVolumeSource["host_path"].(map[string]interface{}))
	}

	if _, ok := userVolumeSource["host_path"]; ok {
		volumeSource.AWSElasticBlockStore = buildAWSElasticBlockStoreVolumeSource(userVolumeSource["host_path"].(map[string]interface{}))
	}

	if _, ok := userVolumeSource["host_path"]; ok {
		volumeSource.GitRepo = buildGitRepoVolumeSource(userVolumeSource["host_path"].(map[string]interface{}))
	}

	if _, ok := userVolumeSource["host_path"]; ok {
		volumeSource.Secret = buildSecretVolumeSource(userVolumeSource["host_path"].(map[string]interface{}))
	}

	if _, ok := userVolumeSource["host_path"]; ok {
		volumeSource.NFS = buildHNFSVolumeSource(userVolumeSource["host_path"].(map[string]interface{}))
	}

	if _, ok := userVolumeSource["host_path"]; ok {
		volumeSource.ISCSI = buildISCSIVolumeSource(userVolumeSource["host_path"].(map[string]interface{}))
	}

	if _, ok := userVolumeSource["host_path"]; ok {
		volumeSource.Glusterfs = buildGlusterfsVolumeSource(userVolumeSource["host_path"].(map[string]interface{}))
	}

	if _, ok := userVolumeSource["host_path"]; ok {
		volumeSource.PersistentVolumeClaim = buildPersistentVolumeClaimVolumeSource(userVolumeSource["host_path"].(map[string]interface{}))
	}

	if _, ok := userVolumeSource["host_path"]; ok {
		volumeSource.RBD = buildRBDVolumeSource(userVolumeSource["host_path"].(map[string]interface{}))
	}

	return volume
}
<|endoftext|>


<commit_before>// Copyright 2018 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 buildbucket

import (
	"context"
	"fmt"
	"net/url"
	"strings"

	"github.com/golang/protobuf/proto"
	"github.com/golang/protobuf/ptypes/timestamp"

	buildbucketpb "go.chromium.org/luci/buildbucket/proto"
	"go.chromium.org/luci/common/data/stringset"
	"go.chromium.org/luci/common/errors"
	"go.chromium.org/luci/common/logging"
	annotpb "go.chromium.org/luci/common/proto/milo"
	"go.chromium.org/luci/logdog/common/types"
)

// This code converts annotation steps to Buildbucket v2 steps.
// See //buildbucket/proto/step.proto, //common/proto/milo/annotations.proto

// StepSep separates parent and child steps.
const StepSep = "|"

var markdownEscaper *strings.Replacer

func init() {
	// Markdown supports escaping these chars.
	// https://spec.commonmark.org/0.28/#backslash-escapes
	const special = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
	oldNew := make([]string, 2*len(special))
	for i, c := range special {
		oldNew[i*2] = string(c)
		oldNew[i*2+1] = `\` + string(c)
	}
	markdownEscaper = strings.NewReplacer(oldNew...)
}

// ConvertBuildSteps converts a build given the root step's substeps, which must
// be the actual steps of the build, and the Logdog URL for links conversion.
// The provided context is used only for logging.
//
// Does not verify that the returned build satisfies all the constraints
// described in the proto files.
//
// Unsupported fields:
//   * Substep.annotation_stream,
//   * Step.link,
//   * Link.isolate_object,
//   * Link.dm_link.
func ConvertBuildSteps(c context.Context, annSteps []*annotpb.Step_Substep, annAddr *types.StreamAddr) ([]*buildbucketpb.Step, error) {
	prefix, _ := annAddr.Path.Split()
	sc := &stepConverter{
		defaultLogdogHost:   annAddr.Host,
		defaultLogdogPrefix: fmt.Sprintf("%s/%s", annAddr.Project, prefix),
		steps:               map[string]*buildbucketpb.Step{},
	}

	var bbSteps []*buildbucketpb.Step
	if _, err := sc.convertSubsteps(c, &bbSteps, annSteps, ""); err != nil {
		return nil, err
	}
	return bbSteps, nil
}

type stepConverter struct {
	defaultLogdogHost, defaultLogdogPrefix string

	steps map[string]*buildbucketpb.Step
}

// convertSubsteps converts substeps, which we expect to be Steps, not Logdog
// annotation streams.
func (p *stepConverter) convertSubsteps(c context.Context, bbSteps *[]*buildbucketpb.Step, annSubsteps []*annotpb.Step_Substep, stepPrefix string) ([]*buildbucketpb.Step, error) {
	bbSubsteps := make([]*buildbucketpb.Step, 0, len(annSubsteps))
	for _, annSubstep := range annSubsteps {
		annStep := annSubstep.GetStep()
		if annStep == nil {
			return nil, errors.Reason("unexpected non-Step substep %v", annSubstep).Err()
		}

		bbSubstep, err := p.convertSteps(c, bbSteps, annStep, stepPrefix)
		if err != nil {
			return nil, err
		}

		bbSubsteps = append(bbSubsteps, bbSubstep)
	}

	return bbSubsteps, nil
}

// convertSteps converts [non-root] steps.
// Mutates p.steps.
func (p *stepConverter) convertSteps(c context.Context, bbSteps *[]*buildbucketpb.Step, ann *annotpb.Step, stepPrefix string) (*buildbucketpb.Step, error) {
	// Set up Buildbucket v2 step.
	bb := &buildbucketpb.Step{
		StartTime: ann.Started,
		EndTime:   ann.Ended,
	}

	// Unlike annotation step names, buildbucket step names must be unique.
	// Choose a name.
	stripPrefix := strings.TrimSuffix(stepPrefix, StepSep) + "."
	baseName := stepPrefix + strings.TrimPrefix(ann.Name, stripPrefix)
	bb.Name = baseName
	for i := 2; p.steps[bb.Name] != nil; i++ {
		bb.Name = fmt.Sprintf("%s (%d)", baseName, i)
	}
	p.steps[bb.Name] = bb

	// summary stores a slice of paragraphs, not individual lines.
	var summary []string

	// Get any failure details.
	if fd := ann.GetFailureDetails(); fd != nil && fd.Text != "" {
		summary = append(summary, fd.Text)
	}

	// Handle text. Below description copied from
	// https://cs.chromium.org/chromium/infra/appengine/cr-buildbucket/annotations.py?l=85&rcl=ec46b5a76fd9948d43a9116051435cbccafa12f1.
	// Although annotation.proto says each line in step_text is a consecutive
	// line and should not contain newlines, in practice they are in HTML format
	// may have
s, Buildbot joins them with " " and treats the result
	// as safe HTML.
	// https://cs.chromium.org/chromium/build/third_party/buildbot_8_4p1/buildbot/status/web/build.py?sq=package:chromium&rcl=83e20043dedd1db6977c6aa818e66c1f82ff31e1&l=130
	// Preserve this semantics (except, it is not safe).
	// HTML is valid Markdown, so use it as is.
	if len(ann.Text) > 0 {
		escaped := make([]string, len(ann.Text))
		for i, text := range ann.Text {
			escaped[i] = markdownEscaper.Replace(text)
		}
		summary = append(summary, strings.Join(escaped, " "))
	}

	// Handle logs.
	logs, lines := p.convertLinks(c, ann)
	bb.Logs = logs
	if len(lines) > 0 {
		summary = append(summary, strings.Join(lines, "\n"))
	}

	// Put completed summary into current step.
	bb.SummaryMarkdown = strings.Join(summary, "\n\n")

	// Put step into list of steps.
	*bbSteps = append(*bbSteps, bb)

	// Handle substeps.
	bbSubsteps, err := p.convertSubsteps(c, bbSteps, ann.Substep, bb.Name+StepSep)
	if err != nil {
		return nil, err
	}

	// Ensure parent step start/end time is not after/before of its children.
	for _, ss := range bbSubsteps {
		if ss.StartTime != nil && (bb.StartTime == nil || cmpTs(bb.StartTime, ss.StartTime) > 0) {
			bb.StartTime = ss.StartTime
		}
		switch {
		case ss.EndTime == nil:
			bb.EndTime = nil
		case bb.EndTime != nil && cmpTs(bb.EndTime, ss.EndTime) < 0:
			bb.EndTime = ss.EndTime
		}
	}

	// Determine status.
	switch {
	// First of all, honor start/end times.

	case bb.StartTime == nil:
		bb.Status = buildbucketpb.Status_SCHEDULED

	case bb.EndTime == nil:
		bb.Status = buildbucketpb.Status_STARTED

	// Secondly, honor current status.

	case ann.Status == annotpb.Status_SUCCESS:
		bb.Status = buildbucketpb.Status_SUCCESS

	case ann.Status == annotpb.Status_FAILURE:
		if fd := ann.GetFailureDetails(); fd != nil {
			switch fd.Type {
			case annotpb.FailureDetails_GENERAL:
				bb.Status = buildbucketpb.Status_FAILURE
			case annotpb.FailureDetails_CANCELLED:
				bb.Status = buildbucketpb.Status_CANCELED
			default:
				bb.Status = buildbucketpb.Status_INFRA_FAILURE
			}
		} else {
			bb.Status = buildbucketpb.Status_FAILURE
		}

	default:
		return nil, errors.Reason("step %q has end time, but status is not terminal", bb.Name).Err()
	}

	// When parent step finishes running, compute its final status as worst
	// status, as determined by statusPrecedence map below, among direct children
	// and its own status.
	if bb.Status.Ended() {
		for _, bbSubstep := range bbSubsteps {
			substepStatusPrecedence, ok := statusPrecedence[bbSubstep.Status]
			if ok && substepStatusPrecedence < statusPrecedence[bb.Status] {
				bb.Status = bbSubstep.Status
			}
		}
	}

	maybeCloneTimestamp(&bb.StartTime)
	maybeCloneTimestamp(&bb.EndTime)
	return bb, nil
}

func maybeCloneTimestamp(ts **timestamp.Timestamp) {
	if *ts != nil {
		*ts = proto.Clone(*ts).(*timestamp.Timestamp)
	}
}

func cmpTs(a, b *timestamp.Timestamp) int {
	if a.Seconds != b.Seconds {
		return int(a.Seconds - b.Seconds)
	}
	return int(a.Nanos - b.Nanos)
}

var statusPrecedence = map[buildbucketpb.Status]int{
	buildbucketpb.Status_CANCELED:      0,
	buildbucketpb.Status_INFRA_FAILURE: 1,
	buildbucketpb.Status_FAILURE:       2,
	buildbucketpb.Status_SUCCESS:       3,
}

func (p *stepConverter) convertLinks(c context.Context, ann *annotpb.Step) ([]*buildbucketpb.Step_Log, []string) {
	aLinks := make([]*annotpb.Link, 0, len(ann.OtherLinks)+2)

	// Get stdout, stderr Logdog links.
	if ann.StdoutStream != nil {
		aLinks = append(aLinks,
			&annotpb.Link{
				Label: "stdout",
				Value: &annotpb.Link_LogdogStream{ann.StdoutStream},
			},
		)
	}
	if ann.StderrStream != nil {
		aLinks = append(aLinks,
			&annotpb.Link{
				Label: "stderr",
				Value: &annotpb.Link_LogdogStream{ann.StderrStream},
			},
		)
	}

	// Get "other" links (ann.Link is expected never to be initialized).
	if ann.GetLink() != nil {
		logging.Warningf(c, "Got unexpectedly populated link field in annotation step %v", ann)
	}
	aLinks = append(aLinks, ann.OtherLinks...)

	// Convert each link to a Buildbucket v2 log.
	bbLogs := make([]*buildbucketpb.Step_Log, 0, len(aLinks))
	summary := make([]string, 0, len(aLinks))
	logNames := stringset.New(len(aLinks))
	for _, l := range aLinks {
		switch {
		case l.GetLogdogStream() != nil:
			if logNames.Has(l.Label) {
				logging.Warningf(c, "step %q: duplicate log name %q", ann.Name, l.Label)
			} else {
				logNames.Add(l.Label)
				bbLogs = append(bbLogs,
					&buildbucketpb.Step_Log{
						Name:    l.Label,
						ViewUrl: p.convertLogdogLink(l.GetLogdogStream(), true),
						Url:     p.convertLogdogLink(l.GetLogdogStream(), false),
					},
				)
			}
		case l.GetUrl() != "":
			// Arbitrary links go into the summary.
			s := l.GetUrl() // Backslash escape all parens.
			s = strings.Replace(s, `(`, `\(`, -1)
			s = strings.Replace(s, `)`, `\)`, -1)
			summary = append(summary, fmt.Sprintf("* [%s](%s)", l.Label, s))
		default:
			logging.Warningf(c, "Got neither URL nor Logdog stream, skipping: %v", l)
		}
	}

	if len(bbLogs) == 0 {
		return nil, summary
	}
	return bbLogs, summary
}

func (p *stepConverter) convertLogdogLink(log *annotpb.LogdogStream, viewUrl bool) string {
	host, prefix := p.defaultLogdogHost, p.defaultLogdogPrefix
	if log.GetServer() != "" {
		host = log.Server
	}
	if log.GetPrefix() != "" {
		prefix = log.Prefix
	}
	path := fmt.Sprintf("%s/+/%s", prefix, log.Name)
	if viewUrl {
		return fmt.Sprintf("https://%s/v/?s=%s", host, url.QueryEscape(path))
	}
	return fmt.Sprintf("logdog://%s/%s", host, path)
}
<commit_msg>Escape only *, _ and #<commit_after>// Copyright 2018 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 buildbucket

import (
	"context"
	"fmt"
	"net/url"
	"strings"

	"github.com/golang/protobuf/proto"
	"github.com/golang/protobuf/ptypes/timestamp"

	buildbucketpb "go.chromium.org/luci/buildbucket/proto"
	"go.chromium.org/luci/common/data/stringset"
	"go.chromium.org/luci/common/errors"
	"go.chromium.org/luci/common/logging"
	annotpb "go.chromium.org/luci/common/proto/milo"
	"go.chromium.org/luci/logdog/common/types"
)

// This code converts annotation steps to Buildbucket v2 steps.
// See //buildbucket/proto/step.proto, //common/proto/milo/annotations.proto

// StepSep separates parent and child steps.
const StepSep = "|"

var markdownEscaper *strings.Replacer

func init() {
	const special = "#*_"
	oldNew := make([]string, 2*len(special))
	for i, c := range special {
		oldNew[i*2] = string(c)
		oldNew[i*2+1] = `\` + string(c)
	}
	markdownEscaper = strings.NewReplacer(oldNew...)
}

// ConvertBuildSteps converts a build given the root step's substeps, which must
// be the actual steps of the build, and the Logdog URL for links conversion.
// The provided context is used only for logging.
//
// Does not verify that the returned build satisfies all the constraints
// described in the proto files.
//
// Unsupported fields:
//   * Substep.annotation_stream,
//   * Step.link,
//   * Link.isolate_object,
//   * Link.dm_link.
func ConvertBuildSteps(c context.Context, annSteps []*annotpb.Step_Substep, annAddr *types.StreamAddr) ([]*buildbucketpb.Step, error) {
	prefix, _ := annAddr.Path.Split()
	sc := &stepConverter{
		defaultLogdogHost:   annAddr.Host,
		defaultLogdogPrefix: fmt.Sprintf("%s/%s", annAddr.Project, prefix),
		steps:               map[string]*buildbucketpb.Step{},
	}

	var bbSteps []*buildbucketpb.Step
	if _, err := sc.convertSubsteps(c, &bbSteps, annSteps, ""); err != nil {
		return nil, err
	}
	return bbSteps, nil
}

type stepConverter struct {
	defaultLogdogHost, defaultLogdogPrefix string

	steps map[string]*buildbucketpb.Step
}

// convertSubsteps converts substeps, which we expect to be Steps, not Logdog
// annotation streams.
func (p *stepConverter) convertSubsteps(c context.Context, bbSteps *[]*buildbucketpb.Step, annSubsteps []*annotpb.Step_Substep, stepPrefix string) ([]*buildbucketpb.Step, error) {
	bbSubsteps := make([]*buildbucketpb.Step, 0, len(annSubsteps))
	for _, annSubstep := range annSubsteps {
		annStep := annSubstep.GetStep()
		if annStep == nil {
			return nil, errors.Reason("unexpected non-Step substep %v", annSubstep).Err()
		}

		bbSubstep, err := p.convertSteps(c, bbSteps, annStep, stepPrefix)
		if err != nil {
			return nil, err
		}

		bbSubsteps = append(bbSubsteps, bbSubstep)
	}

	return bbSubsteps, nil
}

// convertSteps converts [non-root] steps.
// Mutates p.steps.
func (p *stepConverter) convertSteps(c context.Context, bbSteps *[]*buildbucketpb.Step, ann *annotpb.Step, stepPrefix string) (*buildbucketpb.Step, error) {
	// Set up Buildbucket v2 step.
	bb := &buildbucketpb.Step{
		StartTime: ann.Started,
		EndTime:   ann.Ended,
	}

	// Unlike annotation step names, buildbucket step names must be unique.
	// Choose a name.
	stripPrefix := strings.TrimSuffix(stepPrefix, StepSep) + "."
	baseName := stepPrefix + strings.TrimPrefix(ann.Name, stripPrefix)
	bb.Name = baseName
	for i := 2; p.steps[bb.Name] != nil; i++ {
		bb.Name = fmt.Sprintf("%s (%d)", baseName, i)
	}
	p.steps[bb.Name] = bb

	// summary stores a slice of paragraphs, not individual lines.
	var summary []string

	// Get any failure details.
	if fd := ann.GetFailureDetails(); fd != nil && fd.Text != "" {
		summary = append(summary, fd.Text)
	}

	// Handle text. Below description copied from
	// https://cs.chromium.org/chromium/infra/appengine/cr-buildbucket/annotations.py?l=85&rcl=ec46b5a76fd9948d43a9116051435cbccafa12f1.
	// Although annotation.proto says each line in step_text is a consecutive
	// line and should not contain newlines, in practice they are in HTML format
	// may have
s, Buildbot joins them with " " and treats the result
	// as safe HTML.
	// https://cs.chromium.org/chromium/build/third_party/buildbot_8_4p1/buildbot/status/web/build.py?sq=package:chromium&rcl=83e20043dedd1db6977c6aa818e66c1f82ff31e1&l=130
	// Preserve this semantics (except, it is not safe).
	// HTML is valid Markdown, so use it as is.
	if len(ann.Text) > 0 {
		escaped := make([]string, len(ann.Text))
		for i, text := range ann.Text {
			escaped[i] = markdownEscaper.Replace(text)
		}
		summary = append(summary, strings.Join(escaped, " "))
	}

	// Handle logs.
	logs, lines := p.convertLinks(c, ann)
	bb.Logs = logs
	if len(lines) > 0 {
		summary = append(summary, strings.Join(lines, "\n"))
	}

	// Put completed summary into current step.
	bb.SummaryMarkdown = strings.Join(summary, "\n\n")

	// Put step into list of steps.
	*bbSteps = append(*bbSteps, bb)

	// Handle substeps.
	bbSubsteps, err := p.convertSubsteps(c, bbSteps, ann.Substep, bb.Name+StepSep)
	if err != nil {
		return nil, err
	}

	// Ensure parent step start/end time is not after/before of its children.
	for _, ss := range bbSubsteps {
		if ss.StartTime != nil && (bb.StartTime == nil || cmpTs(bb.StartTime, ss.StartTime) > 0) {
			bb.StartTime = ss.StartTime
		}
		switch {
		case ss.EndTime == nil:
			bb.EndTime = nil
		case bb.EndTime != nil && cmpTs(bb.EndTime, ss.EndTime) < 0:
			bb.EndTime = ss.EndTime
		}
	}

	// Determine status.
	switch {
	// First of all, honor start/end times.

	case bb.StartTime == nil:
		bb.Status = buildbucketpb.Status_SCHEDULED

	case bb.EndTime == nil:
		bb.Status = buildbucketpb.Status_STARTED

	// Secondly, honor current status.

	case ann.Status == annotpb.Status_SUCCESS:
		bb.Status = buildbucketpb.Status_SUCCESS

	case ann.Status == annotpb.Status_FAILURE:
		if fd := ann.GetFailureDetails(); fd != nil {
			switch fd.Type {
			case annotpb.FailureDetails_GENERAL:
				bb.Status = buildbucketpb.Status_FAILURE
			case annotpb.FailureDetails_CANCELLED:
				bb.Status = buildbucketpb.Status_CANCELED
			default:
				bb.Status = buildbucketpb.Status_INFRA_FAILURE
			}
		} else {
			bb.Status = buildbucketpb.Status_FAILURE
		}

	default:
		return nil, errors.Reason("step %q has end time, but status is not terminal", bb.Name).Err()
	}

	// When parent step finishes running, compute its final status as worst
	// status, as determined by statusPrecedence map below, among direct children
	// and its own status.
	if bb.Status.Ended() {
		for _, bbSubstep := range bbSubsteps {
			substepStatusPrecedence, ok := statusPrecedence[bbSubstep.Status]
			if ok && substepStatusPrecedence < statusPrecedence[bb.Status] {
				bb.Status = bbSubstep.Status
			}
		}
	}

	maybeCloneTimestamp(&bb.StartTime)
	maybeCloneTimestamp(&bb.EndTime)
	return bb, nil
}

func maybeCloneTimestamp(ts **timestamp.Timestamp) {
	if *ts != nil {
		*ts = proto.Clone(*ts).(*timestamp.Timestamp)
	}
}

func cmpTs(a, b *timestamp.Timestamp) int {
	if a.Seconds != b.Seconds {
		return int(a.Seconds - b.Seconds)
	}
	return int(a.Nanos - b.Nanos)
}

var statusPrecedence = map[buildbucketpb.Status]int{
	buildbucketpb.Status_CANCELED:      0,
	buildbucketpb.Status_INFRA_FAILURE: 1,
	buildbucketpb.Status_FAILURE:       2,
	buildbucketpb.Status_SUCCESS:       3,
}

func (p *stepConverter) convertLinks(c context.Context, ann *annotpb.Step) ([]*buildbucketpb.Step_Log, []string) {
	aLinks := make([]*annotpb.Link, 0, len(ann.OtherLinks)+2)

	// Get stdout, stderr Logdog links.
	if ann.StdoutStream != nil {
		aLinks = append(aLinks,
			&annotpb.Link{
				Label: "stdout",
				Value: &annotpb.Link_LogdogStream{ann.StdoutStream},
			},
		)
	}
	if ann.StderrStream != nil {
		aLinks = append(aLinks,
			&annotpb.Link{
				Label: "stderr",
				Value: &annotpb.Link_LogdogStream{ann.StderrStream},
			},
		)
	}

	// Get "other" links (ann.Link is expected never to be initialized).
	if ann.GetLink() != nil {
		logging.Warningf(c, "Got unexpectedly populated link field in annotation step %v", ann)
	}
	aLinks = append(aLinks, ann.OtherLinks...)

	// Convert each link to a Buildbucket v2 log.
	bbLogs := make([]*buildbucketpb.Step_Log, 0, len(aLinks))
	summary := make([]string, 0, len(aLinks))
	logNames := stringset.New(len(aLinks))
	for _, l := range aLinks {
		switch {
		case l.GetLogdogStream() != nil:
			if logNames.Has(l.Label) {
				logging.Warningf(c, "step %q: duplicate log name %q", ann.Name, l.Label)
			} else {
				logNames.Add(l.Label)
				bbLogs = append(bbLogs,
					&buildbucketpb.Step_Log{
						Name:    l.Label,
						ViewUrl: p.convertLogdogLink(l.GetLogdogStream(), true),
						Url:     p.convertLogdogLink(l.GetLogdogStream(), false),
					},
				)
			}
		case l.GetUrl() != "":
			// Arbitrary links go into the summary.
			s := l.GetUrl() // Backslash escape all parens.
			s = strings.Replace(s, `(`, `\(`, -1)
			s = strings.Replace(s, `)`, `\)`, -1)
			summary = append(summary, fmt.Sprintf("* [%s](%s)", l.Label, s))
		default:
			logging.Warningf(c, "Got neither URL nor Logdog stream, skipping: %v", l)
		}
	}

	if len(bbLogs) == 0 {
		return nil, summary
	}
	return bbLogs, summary
}

func (p *stepConverter) convertLogdogLink(log *annotpb.LogdogStream, viewUrl bool) string {
	host, prefix := p.defaultLogdogHost, p.defaultLogdogPrefix
	if log.GetServer() != "" {
		host = log.Server
	}
	if log.GetPrefix() != "" {
		prefix = log.Prefix
	}
	path := fmt.Sprintf("%s/+/%s", prefix, log.Name)
	if viewUrl {
		return fmt.Sprintf("https://%s/v/?s=%s", host, url.QueryEscape(path))
	}
	return fmt.Sprintf("logdog://%s/%s", host, path)
}
<|endoftext|>


<commit_before>// Copyright 2020 OpenTelemetry 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 builder

import (
	"errors"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"text/template"
	"time"

	"github.com/open-telemetry/opentelemetry-collector-builder/internal/scaffold"
)

var (
	// ErrFailedToGenerateSourceFromTemplate indicates a failure in writing the final contents to the destination file
	ErrFailedToGenerateSourceFromTemplate = errors.New("failed to generate source from template")

	// ErrGoNotFound is returned when a Go binary hasn't been found
	ErrGoNotFound = errors.New("Go binary not found")
)

// GenerateAndCompile will generate the source files based on the given configuration, update go mod, and will compile into a binary
func GenerateAndCompile(cfg Config) error {
	if err := Generate(cfg); err != nil {
		return err
	}

	// run go get to update go.mod and go.sum files
	if err := GetModules(cfg); err != nil {
		return err
	}

	return Compile(cfg)
}

// Generate assembles a new distribution based on the given configuration
func Generate(cfg Config) error {
	// if the file does not exist, try to create it
	if _, err := os.Stat(cfg.Distribution.OutputPath); os.IsNotExist(err) {
		if err := os.Mkdir(cfg.Distribution.OutputPath, 0755); err != nil {
			return fmt.Errorf("failed to create output path: %w", err)
		}
	} else if err != nil {
		// something else happened
		return fmt.Errorf("failed to create output path: %w", err)
	}

	for _, file := range []struct {
		outFile string
		tmpl    string
	}{
		{
			"main.go",
			scaffold.Main,
		},
		// components.go
		{
			"components.go",
			scaffold.Components,
		},
		{
			"go.mod",
			scaffold.Gomod,
		},
	} {
		if err := processAndWrite(cfg, file.tmpl, file.outFile, cfg); err != nil {
			return fmt.Errorf("failed to generate source file with destination %q, source: %q: %w", file.outFile, file.tmpl, err)
		}
	}

	cfg.Logger.Info("Sources created", "path", cfg.Distribution.OutputPath)
	return nil
}

// Compile generates a binary from the sources based on the configuration
func Compile(cfg Config) error {
	// first, we test to check if we have Go at all
	goBinary, err := getGoPath(cfg)
	if err != nil {
		return err
	}

	cfg.Logger.Info("Compiling")
	cmd := exec.Command(goBinary, "build", "-ldflags=-s -w", "-trimpath", "-o", cfg.Distribution.ExeName)
	cmd.Dir = cfg.Distribution.OutputPath
	if out, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("failed to compile the OpenTelemetry Collector distribution: %w. Output: %q", err, out)
	}
	cfg.Logger.Info("Compiled", "binary", fmt.Sprintf("%s/%s", cfg.Distribution.OutputPath, cfg.Distribution.ExeName))

	return nil
}

// GetModules retrieves the go modules, updating go.mod and go.sum in the process
func GetModules(cfg Config) error {
	// first, we test to check if we have Go at all
	goBinary, err := getGoPath(cfg)
	if err != nil {
		return err
	}

	cfg.Logger.Info("Getting go modules")
	cmd := exec.Command(goBinary, "mod", "download")
	cmd.Dir = cfg.Distribution.OutputPath

	// basic retry if error from go mod command (in case of transient network error). This could be improved
	// retry 3 times with 5 second spacing interval
	retries := 3
	failReason := "unknown"
	for i := 1; i <= retries; i++ {
		if out, err := cmd.CombinedOutput(); err != nil {
			failReason = fmt.Sprintf("%s. Output: %q", err, out)
			cfg.Logger.Info("Failed modules download", "retry", fmt.Sprintf("%d/%d", i, retries))
			time.Sleep(5 * time.Second)
			continue
		}
		return nil
	}
	return fmt.Errorf("failed to download go modules: %s", failReason)
}

// getGoPath checks if go is present and correct, and returns a useable go bin location
func getGoPath(cfg Config) (string, error) {
	goBinary := cfg.Distribution.Go
	if _, err := exec.Command(goBinary, "env").CombinedOutput(); err != nil {
		path, err := exec.LookPath("go")
		if err != nil {
			return "", ErrGoNotFound
		}
		goBinary = path
		cfg.Logger.Info("Using go from PATH", "Go executable", path)
	}

	return goBinary, nil
}

func processAndWrite(cfg Config, tmpl string, outFile string, tmplParams interface{}) error {
	t, err := template.New("template").Parse(tmpl)
	if err != nil {
		return err
	}

	out, err := os.Create(filepath.Join(cfg.Distribution.OutputPath, outFile))
	if err != nil {
		return err
	}

	return t.Execute(out, tmplParams)
}
<commit_msg>Generate a warning if the builder and collector base version mismatch (#30)<commit_after>// Copyright 2020 OpenTelemetry 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 builder

import (
	"errors"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"text/template"
	"time"

	"github.com/open-telemetry/opentelemetry-collector-builder/internal/scaffold"
)

var (
	// ErrFailedToGenerateSourceFromTemplate indicates a failure in writing the final contents to the destination file
	ErrFailedToGenerateSourceFromTemplate = errors.New("failed to generate source from template")

	// ErrGoNotFound is returned when a Go binary hasn't been found
	ErrGoNotFound = errors.New("Go binary not found")
)

// GenerateAndCompile will generate the source files based on the given configuration, update go mod, and will compile into a binary
func GenerateAndCompile(cfg Config) error {
	if err := Generate(cfg); err != nil {
		return err
	}

	// run go get to update go.mod and go.sum files
	if err := GetModules(cfg); err != nil {
		return err
	}

	return Compile(cfg)
}

// Generate assembles a new distribution based on the given configuration
func Generate(cfg Config) error {
	// create a warning message for non-aligned builder and collector base
	if cfg.Distribution.OtelColVersion != defaultOtelColVersion {
		cfg.Logger.Info("You're building a distribution with non-aligned version of the builder. Compilation may fail due to API changes. Please upgrade your builder or API", "builder-version", defaultOtelColVersion)
	}
	// if the file does not exist, try to create it
	if _, err := os.Stat(cfg.Distribution.OutputPath); os.IsNotExist(err) {
		if err := os.Mkdir(cfg.Distribution.OutputPath, 0755); err != nil {
			return fmt.Errorf("failed to create output path: %w", err)
		}
	} else if err != nil {
		// something else happened
		return fmt.Errorf("failed to create output path: %w", err)
	}

	for _, file := range []struct {
		outFile string
		tmpl    string
	}{
		{
			"main.go",
			scaffold.Main,
		},
		// components.go
		{
			"components.go",
			scaffold.Components,
		},
		{
			"go.mod",
			scaffold.Gomod,
		},
	} {
		if err := processAndWrite(cfg, file.tmpl, file.outFile, cfg); err != nil {
			return fmt.Errorf("failed to generate source file with destination %q, source: %q: %w", file.outFile, file.tmpl, err)
		}
	}

	cfg.Logger.Info("Sources created", "path", cfg.Distribution.OutputPath)
	return nil
}

// Compile generates a binary from the sources based on the configuration
func Compile(cfg Config) error {
	// first, we test to check if we have Go at all
	goBinary, err := getGoPath(cfg)
	if err != nil {
		return err
	}

	cfg.Logger.Info("Compiling")
	cmd := exec.Command(goBinary, "build", "-ldflags=-s -w", "-trimpath", "-o", cfg.Distribution.ExeName)
	cmd.Dir = cfg.Distribution.OutputPath
	if out, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("failed to compile the OpenTelemetry Collector distribution: %w. Output: %q", err, out)
	}
	cfg.Logger.Info("Compiled", "binary", fmt.Sprintf("%s/%s", cfg.Distribution.OutputPath, cfg.Distribution.ExeName))

	return nil
}

// GetModules retrieves the go modules, updating go.mod and go.sum in the process
func GetModules(cfg Config) error {
	// first, we test to check if we have Go at all
	goBinary, err := getGoPath(cfg)
	if err != nil {
		return err
	}

	cfg.Logger.Info("Getting go modules")
	cmd := exec.Command(goBinary, "mod", "download")
	cmd.Dir = cfg.Distribution.OutputPath

	// basic retry if error from go mod command (in case of transient network error). This could be improved
	// retry 3 times with 5 second spacing interval
	retries := 3
	failReason := "unknown"
	for i := 1; i <= retries; i++ {
		if out, err := cmd.CombinedOutput(); err != nil {
			failReason = fmt.Sprintf("%s. Output: %q", err, out)
			cfg.Logger.Info("Failed modules download", "retry", fmt.Sprintf("%d/%d", i, retries))
			time.Sleep(5 * time.Second)
			continue
		}
		return nil
	}
	return fmt.Errorf("failed to download go modules: %s", failReason)
}

// getGoPath checks if go is present and correct, and returns a useable go bin location
func getGoPath(cfg Config) (string, error) {
	goBinary := cfg.Distribution.Go
	if _, err := exec.Command(goBinary, "env").CombinedOutput(); err != nil {
		path, err := exec.LookPath("go")
		if err != nil {
			return "", ErrGoNotFound
		}
		goBinary = path
		cfg.Logger.Info("Using go from PATH", "Go executable", path)
	}

	return goBinary, nil
}

func processAndWrite(cfg Config, tmpl string, outFile string, tmplParams interface{}) error {
	t, err := template.New("template").Parse(tmpl)
	if err != nil {
		return err
	}

	out, err := os.Create(filepath.Join(cfg.Distribution.OutputPath, outFile))
	if err != nil {
		return err
	}

	return t.Execute(out, tmplParams)
}
<|endoftext|>


<commit_before>// Copyright 2020 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 cookie is used to get and set HTTP cookies.
package cookie

import (
	"encoding/base64"
	"fmt"
	"net/http"
	"time"

	"golang.org/x/pkgsite/internal/derrors"
)

// AlternativeModuleFlash indicates the alternative module path that
// a request was redirected from.
const AlternativeModuleFlash = "tmp-redirected-from-alternative-module"

// Extract returns the value of the cookie at name and deletes the cookie.
func Extract(w http.ResponseWriter, r *http.Request, name string) (_ string, err error) {
	defer derrors.Wrap(&err, "Extract")
	c, err := r.Cookie(name)
	if err != nil && err != http.ErrNoCookie {
		return "", fmt.Errorf("r.Cookie(%q): %v", name, err)
	}
	if c == nil {
		return "", nil
	}
	val, err := Base64Value(c)
	if err != nil {
		return "", nil
	}
	http.SetCookie(w, &http.Cookie{
		Name:    name,
		Path:    r.URL.Path,
		Expires: time.Unix(0, 0),
	})
	return val, nil
}

// Base64Value decodes  the value of c using the Base64 URL encoding and returns it as a string.
func Base64Value(c *http.Cookie) (string, error) {
	val, err := base64.URLEncoding.DecodeString(c.Value)
	if err != nil {
		return "", err
	}
	return string(val), nil
}

// Set sets a cookie at the urlPath with name and val.
func Set(w http.ResponseWriter, name, val, urlPath string) {
	value := base64.URLEncoding.EncodeToString([]byte(val))
	http.SetCookie(w, &http.Cookie{Name: name, Value: value, Path: urlPath})
}
<commit_msg>internal/cookie: fix error return bug<commit_after>// Copyright 2020 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 cookie is used to get and set HTTP cookies.
package cookie

import (
	"encoding/base64"
	"fmt"
	"net/http"
	"time"

	"golang.org/x/pkgsite/internal/derrors"
)

// AlternativeModuleFlash indicates the alternative module path that
// a request was redirected from.
const AlternativeModuleFlash = "tmp-redirected-from-alternative-module"

// Extract returns the value of the cookie at name and deletes the cookie.
func Extract(w http.ResponseWriter, r *http.Request, name string) (_ string, err error) {
	defer derrors.Wrap(&err, "Extract")
	c, err := r.Cookie(name)
	if err != nil && err != http.ErrNoCookie {
		return "", fmt.Errorf("r.Cookie(%q): %v", name, err)
	}
	if c == nil {
		return "", nil
	}
	val, err := Base64Value(c)
	if err != nil {
		return "", err
	}
	http.SetCookie(w, &http.Cookie{
		Name:    name,
		Path:    r.URL.Path,
		Expires: time.Unix(0, 0),
	})
	return val, nil
}

// Base64Value decodes  the value of c using the Base64 URL encoding and returns it as a string.
func Base64Value(c *http.Cookie) (string, error) {
	val, err := base64.URLEncoding.DecodeString(c.Value)
	if err != nil {
		return "", err
	}
	return string(val), nil
}

// Set sets a cookie at the urlPath with name and val.
func Set(w http.ResponseWriter, name, val, urlPath string) {
	value := base64.URLEncoding.EncodeToString([]byte(val))
	http.SetCookie(w, &http.Cookie{Name: name, Value: value, Path: urlPath})
}
<|endoftext|>


<commit_before><commit_msg>internal/uidriver/js: Bug fix: Compile error<commit_after><|endoftext|>


<commit_before>package misc

import "fmt"
import "strings"
import "bufio"
import "os"
import "log"
import "code.google.com/p/go.crypto/ssh/terminal"

// Prompt prompts user for input and returns their response
func Prompt(prompt string) string {
	fmt.Print(prompt)
	inReader := bufio.NewReader(os.Stdin)
	text, _ := inReader.ReadString('\n')
	return text
}

// PromptYesNo returns true if user answered something that starts with "y".
// PromptYesNo returns false if user answers something that starts with "n".
// PromptYesNo returns yesIsDefault if no answer given.
func PromptYesNo(prompt string, yesIsDefault bool) bool {
	for {
		if yesIsDefault {
			fmt.Print(prompt + " [Yn]? ")
		} else {
			fmt.Print(prompt + " [yN]? ")
		}

		// Read input
		inReader := bufio.NewReader(os.Stdin)
		text, err := inReader.ReadString('\n')
		check(err, "reading stdin")

		// Trim leading and trailing spaces, and convert to lower case
		text = strings.TrimSpace(strings.ToLower(text))
		if len(text) == 0 {
			return yesIsDefault
		} else if strings.HasPrefix(text, "y") {
			return true
		} else if strings.HasPrefix(text, "n") {
			return false
		}
		fmt.Println("Invalid value.  Must be 'y' or 'n'.  Try again.")
	}
}

// ChooseOne prompts the user to enter one of n values
// Example: answer := misc.PromptOne("Continue, Quit, or Redo? [cqr]: ", ["c", "q", "r"])
func ChooseOne(prompt string, values ...string) string {
	for {
		fmt.Print(prompt)

		// Read input
		inReader := bufio.NewReader(os.Stdin)
		text, _ := inReader.ReadString('\n')

		// Trim leading and trailing spaces, and convert to lower case
		text = strings.TrimSpace(text)
		if len(text) == 0 {
			return values[0]
		}

		for _, v := range values {
			if text == v {
				return v
			}
		}

		fmt.Println("Invalid entry, try again.")
	}
}

// PromptPassword prompts user for a password that is never echoed back to the screen.
// This needs to be improved because it leaves terminal in unusable state when
// user presses Ctrl-C
func PromptPassword(prompt string) string {
	stdin := 1
	fmt.Fprintf(os.Stdin, prompt)

	// Get current state of terminal
	//s, err := terminal.MakeRaw(stdin)
	//check(err, "making raw terminal, Saving old terminal state")
	//defer terminal.Restore(stdin, s)

	// Read password from stdin
	b, err := terminal.ReadPassword(stdin)
	check(err, "reading from terminal")

	return string(b)
}

// InStrings returns true if the first argument is in the list of following arguments
// or it returns false if none match. InStrings is similar to ConstainsString which
// takes a slice of strings instead of a variable number of string arguments.
func InStrings(str string, strs ...string) bool {
	for _, s := range strs {
		if str == s {
			return true
		}
	}
	return false
}

// ContainsString returns true if the given slice contains the given string
func ContainsString(slice []string, value string) bool {
	for _, e := range slice {
		if value == e {
			return true
		}
	}
	return false
}

// CompareStrings returns negative when first string is less, positive if more, zero otherwise
func CompareStrings(s1, s2 string) int {
	if s1 == s2 {
		return 0
	} else if s1 < s2 {
		return -1
	}
	return 1
}

// ColesceStrings returns the first non-empty string value
// or, if none qualify, it returns an empty string
func CoalesceStrings(strs ...string) string {
	for _, s := range strs {
		if len(s) > 0 {
			return s
		}
	}
	return ""
}

// =================
// Private functions
// =================
func check(err error, action string) {
	if err != nil {
		log.Fatalf("Error %s: %v\n", action, err)
	}
}
<commit_msg>PromptPassword now traps Ctrl-C and restores the original terminal state<commit_after>package misc

import "fmt"
import "strings"
import "bufio"
import "os"
import "os/signal"
import "syscall"
import "log"
import "code.google.com/p/go.crypto/ssh/terminal"

// Prompt prompts user for input and returns their response
func Prompt(prompt string) string {
	fmt.Print(prompt)
	inReader := bufio.NewReader(os.Stdin)
	text, _ := inReader.ReadString('\n')
	return text
}

// PromptYesNo returns true if user answered something that starts with "y".
// PromptYesNo returns false if user answers something that starts with "n".
// PromptYesNo returns yesIsDefault if no answer given.
func PromptYesNo(prompt string, yesIsDefault bool) bool {
	for {
		if yesIsDefault {
			fmt.Print(prompt + " [Yn]? ")
		} else {
			fmt.Print(prompt + " [yN]? ")
		}

		// Read input
		inReader := bufio.NewReader(os.Stdin)
		text, err := inReader.ReadString('\n')
		check(err, "reading stdin")

		// Trim leading and trailing spaces, and convert to lower case
		text = strings.TrimSpace(strings.ToLower(text))
		if len(text) == 0 {
			return yesIsDefault
		} else if strings.HasPrefix(text, "y") {
			return true
		} else if strings.HasPrefix(text, "n") {
			return false
		}
		fmt.Println("Invalid value.  Must be 'y' or 'n'.  Try again.")
	}
}

// ChooseOne prompts the user to enter one of n values
// Example: answer := misc.PromptOne("Continue, Quit, or Redo? [cqr]: ", ["c", "q", "r"])
func ChooseOne(prompt string, values ...string) string {
	for {
		fmt.Print(prompt)

		// Read input
		inReader := bufio.NewReader(os.Stdin)
		text, _ := inReader.ReadString('\n')

		// Trim leading and trailing spaces, and convert to lower case
		text = strings.TrimSpace(text)
		if len(text) == 0 {
			return values[0]
		}

		for _, v := range values {
			if text == v {
				return v
			}
		}

		fmt.Println("Invalid entry, try again.")
	}
}

// PromptPassword prompts user for a password that is never echoed back to the screen.
// This needs to be improved because it leaves terminal in unusable state when
// user presses Ctrl-C
func PromptPassword(prompt string) string {
	stdin := 1
	fmt.Fprintf(os.Stdin, prompt)

	// Get current state of terminal
	s, err := terminal.MakeRaw(stdin)
	check(err, "making raw terminal, Saving old terminal state")
	defer terminal.Restore(stdin, s)

	// trap Ctrl-C and restore screen
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	signal.Notify(c, syscall.SIGTERM)
	go func() {
		<-c
		terminal.Restore(stdin, s)
		os.Exit(1)
	}()

	// Read password from stdin
	b, err := terminal.ReadPassword(stdin)
	check(err, "reading from terminal")

	return string(b)
}

// InStrings returns true if the first argument is in the list of following arguments
// or it returns false if none match. InStrings is similar to ConstainsString which
// takes a slice of strings instead of a variable number of string arguments.
func InStrings(str string, strs ...string) bool {
	for _, s := range strs {
		if str == s {
			return true
		}
	}
	return false
}

// ContainsString returns true if the given slice contains the given string
func ContainsString(slice []string, value string) bool {
	for _, e := range slice {
		if value == e {
			return true
		}
	}
	return false
}

// CompareStrings returns negative when first string is less, positive if more, zero otherwise
func CompareStrings(s1, s2 string) int {
	if s1 == s2 {
		return 0
	} else if s1 < s2 {
		return -1
	}
	return 1
}

// ColesceStrings returns the first non-empty string value
// or, if none qualify, it returns an empty string
func CoalesceStrings(strs ...string) string {
	for _, s := range strs {
		if len(s) > 0 {
			return s
		}
	}
	return ""
}

// =================
// Private functions
// =================
func check(err error, action string) {
	if err != nil {
		log.Fatalf("Error %s: %v\n", action, err)
	}
}
<|endoftext|>


<commit_before>package rt

import (
	"emacs/lisp"
)

type Slice struct {
	data   lisp.Object
	offset lisp.Int
	len    lisp.Int
	cap    lisp.Int
}

// MakeSlice creates a new slice with cap=len.
// All values initialized to specified zero value.
func MakeSlice(length lisp.Int, zv lisp.Object) Slice {
	return Slice{
		data: makeVec(length, zv),
		len:  length,
		cap:  length,
	}
}

// MakeSliceCap creates a new slice.
// Each value within length bounds is initialized to specified zero value.
func MakeSliceCap(length, capacity lisp.Int, zv lisp.Object) Slice {
	if length == capacity {
		return MakeSlice(length, zv)
	}
	data := makeVec(capacity, lisp.Intern("nil"))
	for i := lisp.Int(0); i < length; i++ {
		arraySet(data, i, zv)
	}
	return Slice{data: data, len: length, cap: capacity}
}

// ArrayToSlice constructs a new slice from given data vector.
// Vector is not copied.
func ArrayToSlice(data lisp.Object) Slice {
	length := seqLength(data)
	return Slice{data: data, len: length, cap: length}
}

// SliceGet extract slice value using specified index.
func SliceGet(slice Slice, index lisp.Int) lisp.Object {
	return arrayGet(slice.data, index+slice.offset)
}

// SliceSet sets slice value at specified index.
func SliceSet(slice Slice, index lisp.Int, val lisp.Object) {
	arraySet(slice.data, index+slice.offset, val)
}

// BytesToStr converts slice of bytes to string.
func BytesToStr(slice Slice) lisp.Str {
	if slice.offset == 0 {
		return arrayToStr(slice.data)
	}
	return arrayToStr(
		copyArraySpan(slice.data, slice.offset, slice.offset+slice.len),
	)
}
<commit_msg>SliceLen, SliceCap runtime functions<commit_after>package rt

import (
	"emacs/lisp"
)

type Slice struct {
	data   lisp.Object
	offset lisp.Int
	len    lisp.Int
	cap    lisp.Int
}

func SliceLen(slice Slice) lisp.Int { return slice.len }
func SliceCap(slice Slice) lisp.Int { return slice.cap }

// MakeSlice creates a new slice with cap=len.
// All values initialized to specified zero value.
func MakeSlice(length lisp.Int, zv lisp.Object) Slice {
	return Slice{
		data: makeVec(length, zv),
		len:  length,
		cap:  length,
	}
}

// MakeSliceCap creates a new slice.
// Each value within length bounds is initialized to specified zero value.
func MakeSliceCap(length, capacity lisp.Int, zv lisp.Object) Slice {
	if length == capacity {
		return MakeSlice(length, zv)
	}
	data := makeVec(capacity, lisp.Intern("nil"))
	for i := lisp.Int(0); i < length; i++ {
		arraySet(data, i, zv)
	}
	return Slice{data: data, len: length, cap: capacity}
}

// ArrayToSlice constructs a new slice from given data vector.
// Vector is not copied.
func ArrayToSlice(data lisp.Object) Slice {
	length := seqLength(data)
	return Slice{data: data, len: length, cap: length}
}

// SliceGet extract slice value using specified index.
func SliceGet(slice Slice, index lisp.Int) lisp.Object {
	return arrayGet(slice.data, slice.offset+index)
}

// SliceSet sets slice value at specified index.
func SliceSet(slice Slice, index lisp.Int, val lisp.Object) {
	arraySet(slice.data, index+slice.offset, val)
}

// BytesToStr converts slice of bytes to string.
func BytesToStr(slice Slice) lisp.Str {
	if slice.offset == 0 {
		return arrayToStr(slice.data)
	}
	return arrayToStr(
		copyArraySpan(slice.data, slice.offset, slice.offset+slice.len),
	)
}
<|endoftext|>


<commit_before>package cli

import (
	"bufio"
	"os"
	"strings"
)

type Cmd func([]string)

type Cmds struct {
	path     string
	cmds     map[string]Cmd
	children map[string]*Cmds
	help     map[string]string
}

func NewCmds() *Cmds {
	return &Cmds{"", make(map[string]Cmd), make(map[string]*Cmds), make(map[string]string)}
}

func (p *Cmds) Reg(cmd string, help string, fun func([]string)) {
	p.help[cmd] = help
	p.cmds[cmd] = fun
}

func (p *Cmds) Sub(cmd string, help string) *Cmds {
	p.help[cmd] = help
	path := p.path + "." + cmd
	if len(p.path) == 0 {
		path = cmd
	}
	child := &Cmds{path, make(map[string]Cmd), make(map[string]*Cmds), make(map[string]string)}
	p.children[cmd] = child
	return child
}

func (p *Cmds) Loop() {
	lastest := ""
	for {
		print(p.path + ">> ")
		reader := bufio.NewReader(os.Stdin)
		line, _, _ := reader.ReadLine()
		cmd := strings.Trim(string(line), " ")
		if cmd == "." {
			cmd = lastest
			println(p.path + ">> " + cmd)
		} else {
			lastest = cmd
		}

		if cmd == "" {
			continue
		}
		if cmd == ".." {
			break
		}
		if cmd == "exit" {
			os.Exit(0)
		}

		if cmd == "help" || cmd == "?" {
			p.Help(false)
			println()
			continue
		}

		p.Run(strings.Split(cmd, " "))
	}
}
func (p *Cmds) Help(simple bool) {
	display := func(mark bool, cmd string, help string) {
		if mark {
			print("* ", cmd)
		} else {
			print("  ", cmd)
		}
		println(strings.Repeat(" ", 12 - len(cmd)) + help)
	}

	if !simple {
		display(false, ".", "redo lastest cmd")
		display(false, "..", "back to uplevel")
		display(false, "help", "display help message. '?' will also do")
		display(false, "exit", "quit")
		println()
	}
	for cmd, _ := range p.children {
		help, _ := p.help[cmd]
		display(true, cmd, help)
	}
	for cmd, _ := range p.cmds {
		help, _ := p.help[cmd]
		display(false, cmd, help)
	}
}

func (p *Cmds) Run(cmds []string) {
	if len(cmds) == 0 {
		p.Loop()
		return
	}
	cmd, cmds := cmds[0], cmds[1:]
	if fun, ok := p.cmds[cmd]; ok {
		fun(cmds)
		return
	}
	if child, ok := p.children[cmd]; ok {
		child.Run(cmds)
		return
	}
	if cmd == "help" || cmd == "?" || cmd == "-help" || cmd == "--help" {
		p.Help(true)
		return
	}
	if cmd != "" {
		println("cmd not found:", cmd)
	}
	return
}
<commit_msg>Feature: cmds.Unreg<commit_after>package cli

import (
	"bufio"
	"os"
	"strings"
)

type Cmd func([]string)

type Cmds struct {
	path     string
	cmds     map[string]Cmd
	children map[string]*Cmds
	help     map[string]string
}

func NewCmds() *Cmds {
	return &Cmds{"", make(map[string]Cmd), make(map[string]*Cmds), make(map[string]string)}
}

func (p *Cmds) Reg(cmd string, help string, fun func([]string)) {
	p.help[cmd] = help
	p.cmds[cmd] = fun
}

func (p *Cmds) Unreg(cmd string) (help string, fun func([]string)) {
	help = p.help[cmd]
	delete(p.help, cmd)
	fun = p.cmds[cmd]
	delete(p.cmds, cmd)
	return
}

func (p *Cmds) Sub(cmd string, help string) *Cmds {
	p.help[cmd] = help
	path := p.path + "." + cmd
	if len(p.path) == 0 {
		path = cmd
	}
	child := &Cmds{path, make(map[string]Cmd), make(map[string]*Cmds), make(map[string]string)}
	p.children[cmd] = child
	return child
}

func (p *Cmds) Loop() {
	lastest := ""
	for {
		print(p.path + ">> ")
		reader := bufio.NewReader(os.Stdin)
		line, _, _ := reader.ReadLine()
		cmd := strings.Trim(string(line), " ")
		if cmd == "." {
			cmd = lastest
			println(p.path + ">> " + cmd)
		} else {
			lastest = cmd
		}

		if cmd == "" {
			continue
		}
		if cmd == ".." {
			break
		}
		if cmd == "exit" {
			os.Exit(0)
		}

		if cmd == "help" || cmd == "?" {
			p.Help(false)
			println()
			continue
		}

		p.Run(strings.Split(cmd, " "))
	}
}
func (p *Cmds) Help(simple bool) {
	display := func(mark bool, cmd string, help string) {
		if mark {
			print("* ", cmd)
		} else {
			print("  ", cmd)
		}
		println(strings.Repeat(" ", 12 - len(cmd)) + help)
	}

	if !simple {
		display(false, ".", "redo lastest cmd")
		display(false, "..", "back to uplevel")
		display(false, "help", "display help message. '?' will also do")
		display(false, "exit", "quit")
		println()
	}
	for cmd, _ := range p.children {
		help, _ := p.help[cmd]
		display(true, cmd, help)
	}
	for cmd, _ := range p.cmds {
		help, _ := p.help[cmd]
		display(false, cmd, help)
	}
}

func (p *Cmds) Run(cmds []string) {
	if len(cmds) == 0 {
		p.Loop()
		return
	}
	cmd, cmds := cmds[0], cmds[1:]
	if fun, ok := p.cmds[cmd]; ok {
		fun(cmds)
		return
	}
	if child, ok := p.children[cmd]; ok {
		child.Run(cmds)
		return
	}
	if cmd == "help" || cmd == "?" || cmd == "-help" || cmd == "--help" {
		p.Help(true)
		return
	}
	if cmd != "" {
		println("cmd not found:", cmd)
	}
	return
}
<|endoftext|>


<commit_before>// The version package provides a location to set the release versions for all
// packages to consume, without creating import cycles.
//
// This package should not import any other terraform packages.
package version

import (
	"fmt"

	version "github.com/hashicorp/go-version"
)

// The main version number that is being run at the moment.
var Version = "0.12.0"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
var Prerelease = "dev"

// SemVer is an instance of version.Version. This has the secondary
// benefit of verifying during tests and init time that our version is a
// proper semantic version, which should always be the case.
var SemVer *version.Version

func init() {
	SemVer = version.Must(version.NewVersion(Version))
}

// Header is the header name used to send the current terraform version
// in http requests.
const Header = "Terraform-Version"

// String returns the complete version string, including prerelease
func String() string {
	if Prerelease != "" {
		return fmt.Sprintf("%s-%s", Version, Prerelease)
	}
	return Version
}
<commit_msg>v0.12.0-beta1 release prep<commit_after>// The version package provides a location to set the release versions for all
// packages to consume, without creating import cycles.
//
// This package should not import any other terraform packages.
package version

import (
	"fmt"

	version "github.com/hashicorp/go-version"
)

// The main version number that is being run at the moment.
var Version = "0.12.0"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
var Prerelease = "beta1"

// SemVer is an instance of version.Version. This has the secondary
// benefit of verifying during tests and init time that our version is a
// proper semantic version, which should always be the case.
var SemVer *version.Version

func init() {
	SemVer = version.Must(version.NewVersion(Version))
}

// Header is the header name used to send the current terraform version
// in http requests.
const Header = "Terraform-Version"

// String returns the complete version string, including prerelease
func String() string {
	if Prerelease != "" {
		return fmt.Sprintf("%s-%s", Version, Prerelease)
	}
	return Version
}
<|endoftext|>


<commit_before>package version

// Version is the version of the build.
const Version = "0.1.38-dev"
<commit_msg>release v0.1.38<commit_after>package version

// Version is the version of the build.
const Version = "0.1.38"
<|endoftext|>


<commit_before>// Copyright 2016 The etcd-operator 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 version

var Version = "0.0.2+git"
<commit_msg>version: bump to 0.1.0<commit_after>// Copyright 2016 The etcd-operator 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 version

var Version = "0.1.0"
<|endoftext|>


<commit_before>package version

// VERSION ...
const VERSION = "0.9.2"
<commit_msg>v0.9.3 - version<commit_after>package version

// VERSION ...
const VERSION = "0.9.3"
<|endoftext|>


<commit_before>// Copyright 2017 Istio 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 version for fortio holds version information and build information.
package version // import "istio.io/fortio/version"
import (
	"fmt"
	"runtime"

	"istio.io/fortio/log"
)

const (
	major = 1
	minor = 0
	patch = 1

	debug = false // turn on to debug init()
)

var (
	// The following are set by Dockerfile during link time:
	tag       = "n/a"
	buildInfo = "unknown"
	// Number of lines in git status --porcelain; 0 means clean
	gitstatus = "0" // buildInfo default is unknown so no need to add -dirty
	// computed in init()
	version     = ""
	longVersion = ""
)

// Major returns the numerical major version number (first digit of version.Short()).
func Major() int {
	return major
}

// Minor returns the numerical minor version number (second digit of version.Short()).
func Minor() int {
	return minor
}

// Patch returns the numerical patch level (third digit of version.Short()).
func Patch() int {
	return patch
}

// Short returns the 3 digit short version string Major.Minor.Patch[-pre]
// version.Short() is the overall project version (used to version json
// output too). "-pre" is added when the version doesn't match exactly
// a git tag or the build isn't from a clean source tree. (only standard
// dockerfile based build of a clean, tagged source tree should print "X.Y.Z"
// as short version).
func Short() string {
	return version
}

// Long returns the full version and build information.
// Format is "X.Y.X[-pre] YYYY-MM-DD HH:MM SHA[-dirty]" date and time is
// the build date (UTC), sha is the git sha of the source tree.
func Long() string {
	return longVersion
}

// Carefully manually tested all the combinations in pair with Dockerfile
func init() {
	if debug {
		log.SetLogLevel(log.Debug)
	}
	version = fmt.Sprintf("%d.%d.%d", major, minor, patch)
	clean := (gitstatus == "0")
	// The docker build will pass the git tag to the build, if it is clean
	// from a tag it will look like v0.7.0
	if tag != "v"+version || !clean {
		log.Debugf("tag is %v, clean is %v marking as pre release", tag, clean)
		version += "-pre"
	}
	if !clean {
		buildInfo += "-dirty"
		log.Debugf("gitstatus is %q, marking buildinfo as dirty: %v", gitstatus, buildInfo)
	}
	longVersion = version + " " + buildInfo + " " + runtime.Version()
}
<commit_msg>Bump to next/future version to 1.1.0 (as I expect next release to have some significant change)<commit_after>// Copyright 2017 Istio 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 version for fortio holds version information and build information.
package version // import "istio.io/fortio/version"
import (
	"fmt"
	"runtime"

	"istio.io/fortio/log"
)

const (
	major = 1
	minor = 1
	patch = 0

	debug = false // turn on to debug init()
)

var (
	// The following are set by Dockerfile during link time:
	tag       = "n/a"
	buildInfo = "unknown"
	// Number of lines in git status --porcelain; 0 means clean
	gitstatus = "0" // buildInfo default is unknown so no need to add -dirty
	// computed in init()
	version     = ""
	longVersion = ""
)

// Major returns the numerical major version number (first digit of version.Short()).
func Major() int {
	return major
}

// Minor returns the numerical minor version number (second digit of version.Short()).
func Minor() int {
	return minor
}

// Patch returns the numerical patch level (third digit of version.Short()).
func Patch() int {
	return patch
}

// Short returns the 3 digit short version string Major.Minor.Patch[-pre]
// version.Short() is the overall project version (used to version json
// output too). "-pre" is added when the version doesn't match exactly
// a git tag or the build isn't from a clean source tree. (only standard
// dockerfile based build of a clean, tagged source tree should print "X.Y.Z"
// as short version).
func Short() string {
	return version
}

// Long returns the full version and build information.
// Format is "X.Y.X[-pre] YYYY-MM-DD HH:MM SHA[-dirty]" date and time is
// the build date (UTC), sha is the git sha of the source tree.
func Long() string {
	return longVersion
}

// Carefully manually tested all the combinations in pair with Dockerfile
func init() {
	if debug {
		log.SetLogLevel(log.Debug)
	}
	version = fmt.Sprintf("%d.%d.%d", major, minor, patch)
	clean := (gitstatus == "0")
	// The docker build will pass the git tag to the build, if it is clean
	// from a tag it will look like v0.7.0
	if tag != "v"+version || !clean {
		log.Debugf("tag is %v, clean is %v marking as pre release", tag, clean)
		version += "-pre"
	}
	if !clean {
		buildInfo += "-dirty"
		log.Debugf("gitstatus is %q, marking buildinfo as dirty: %v", gitstatus, buildInfo)
	}
	longVersion = version + " " + buildInfo + " " + runtime.Version()
}
<|endoftext|>


<commit_before>package version

import (
	"fmt"

	"github.com/github/hub/git"
	"github.com/github/hub/utils"
)

var Version = "2.3.0-pre2"

func FullVersion() string {
	gitVersion, err := git.Version()
	utils.Check(err)
	return fmt.Sprintf("%s\nhub version %s", gitVersion, Version)
}
<commit_msg>hub 2.3.0-pre3<commit_after>package version

import (
	"fmt"

	"github.com/github/hub/git"
	"github.com/github/hub/utils"
)

var Version = "2.3.0-pre3"

func FullVersion() string {
	gitVersion, err := git.Version()
	utils.Check(err)
	return fmt.Sprintf("%s\nhub version %s", gitVersion, Version)
}
<|endoftext|>


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

// +build windows

package ansicolor

import (
	"bytes"
	"io"
	"strings"
	"syscall"
	"unsafe"
)

type csiState int

const (
	outsideCsiCode csiState = iota
	firstCsiCode
	secondCsiCode
)

type ansiColorWriter struct {
	w             io.Writer
	state         csiState
	paramStartBuf bytes.Buffer
	paramBuf      bytes.Buffer
}

const (
	firstCsiChar   byte = '\x1b'
	secondeCsiChar byte = '['
	separatorChar  byte = ';'
	sgrCode        byte = 'm'
)

const (
	foregroundBlue      = uint16(0x0001)
	foregroundGreen     = uint16(0x0002)
	foregroundRed       = uint16(0x0004)
	foregroundIntensity = uint16(0x0008)
	backgroundBlue      = uint16(0x0010)
	backgroundGreen     = uint16(0x0020)
	backgroundRed       = uint16(0x0040)
	backgroundIntensity = uint16(0x0080)
	underscore          = uint16(0x8000)

	foregroundMask = foregroundBlue | foregroundGreen | foregroundRed | foregroundIntensity
	backgroundMask = backgroundBlue | backgroundGreen | backgroundRed | backgroundIntensity
)

const (
	ansiReset        = "0"
	ansiIntensityOn  = "1"
	ansiIntensityOff = "21"
	ansiUnderlineOn  = "4"
	ansiUnderlineOff = "24"
	ansiBlinkOn      = "5"
	ansiBlinkOff     = "25"

	ansiForegroundBlack   = "30"
	ansiForegroundRed     = "31"
	ansiForegroundGreen   = "32"
	ansiForegroundYellow  = "33"
	ansiForegroundBlue    = "34"
	ansiForegroundMagenta = "35"
	ansiForegroundCyan    = "36"
	ansiForegroundWhite   = "37"
	ansiForegroundDefault = "39"

	ansiBackgroundBlack   = "40"
	ansiBackgroundRed     = "41"
	ansiBackgroundGreen   = "42"
	ansiBackgroundYellow  = "43"
	ansiBackgroundBlue    = "44"
	ansiBackgroundMagenta = "45"
	ansiBackgroundCyan    = "46"
	ansiBackgroundWhite   = "47"
	ansiBackgroundDefault = "49"

	ansiLightForegroundGray    = "90"
	ansiLightForegroundRed     = "91"
	ansiLightForegroundGreen   = "92"
	ansiLightForegroundYellow  = "93"
	ansiLightForegroundBlue    = "94"
	ansiLightForegroundMagenta = "95"
	ansiLightForegroundCyan    = "96"
	ansiLightForegroundWhite   = "97"

	ansiLightBackgroundGray    = "100"
	ansiLightBackgroundRed     = "101"
	ansiLightBackgroundGreen   = "102"
	ansiLightBackgroundYellow  = "103"
	ansiLightBackgroundBlue    = "104"
	ansiLightBackgroundMagenta = "105"
	ansiLightBackgroundCyan    = "106"
	ansiLightBackgroundWhite   = "107"
)

type drawType int

const (
	foreground drawType = iota
	background
)

type winColor struct {
	code     uint16
	drawType drawType
}

var colorMap = map[string]winColor{
	ansiForegroundBlack:   {0, foreground},
	ansiForegroundRed:     {foregroundRed, foreground},
	ansiForegroundGreen:   {foregroundGreen, foreground},
	ansiForegroundYellow:  {foregroundRed | foregroundGreen, foreground},
	ansiForegroundBlue:    {foregroundBlue, foreground},
	ansiForegroundMagenta: {foregroundRed | foregroundBlue, foreground},
	ansiForegroundCyan:    {foregroundGreen | foregroundBlue, foreground},
	ansiForegroundWhite:   {foregroundRed | foregroundGreen | foregroundBlue, foreground},
	ansiForegroundDefault: {foregroundRed | foregroundGreen | foregroundBlue, foreground},

	ansiBackgroundBlack:   {0, background},
	ansiBackgroundRed:     {backgroundRed, background},
	ansiBackgroundGreen:   {backgroundGreen, background},
	ansiBackgroundYellow:  {backgroundRed | backgroundGreen, background},
	ansiBackgroundBlue:    {backgroundBlue, background},
	ansiBackgroundMagenta: {backgroundRed | backgroundBlue, background},
	ansiBackgroundCyan:    {backgroundGreen | backgroundBlue, background},
	ansiBackgroundWhite:   {backgroundRed | backgroundGreen | backgroundBlue, background},
	ansiBackgroundDefault: {0, background},

	ansiLightForegroundGray:    {foregroundIntensity, foreground},
	ansiLightForegroundRed:     {foregroundIntensity | foregroundRed, foreground},
	ansiLightForegroundGreen:   {foregroundIntensity | foregroundGreen, foreground},
	ansiLightForegroundYellow:  {foregroundIntensity | foregroundRed | foregroundGreen, foreground},
	ansiLightForegroundBlue:    {foregroundIntensity | foregroundBlue, foreground},
	ansiLightForegroundMagenta: {foregroundIntensity | foregroundRed | foregroundBlue, foreground},
	ansiLightForegroundCyan:    {foregroundIntensity | foregroundGreen | foregroundBlue, foreground},
	ansiLightForegroundWhite:   {foregroundIntensity | foregroundRed | foregroundGreen | foregroundBlue, foreground},

	ansiLightBackgroundGray:    {backgroundIntensity, background},
	ansiLightBackgroundRed:     {backgroundIntensity | backgroundRed, background},
	ansiLightBackgroundGreen:   {backgroundIntensity | backgroundGreen, background},
	ansiLightBackgroundYellow:  {backgroundIntensity | backgroundRed | backgroundGreen, background},
	ansiLightBackgroundBlue:    {backgroundIntensity | backgroundBlue, background},
	ansiLightBackgroundMagenta: {backgroundIntensity | backgroundRed | backgroundBlue, background},
	ansiLightBackgroundCyan:    {backgroundIntensity | backgroundGreen | backgroundBlue, background},
	ansiLightBackgroundWhite:   {backgroundIntensity | backgroundRed | backgroundGreen | backgroundBlue, background},
}

var (
	kernel32                       = syscall.NewLazyDLL("kernel32.dll")
	procSetConsoleTextAttribute    = kernel32.NewProc("SetConsoleTextAttribute")
	procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
	defaultAttr                    *textAttributes
)

func init() {
	screenInfo := getConsoleScreenBufferInfo(uintptr(syscall.Stdout))
	if screenInfo != nil {
		colorMap[ansiForegroundDefault] = winColor{
			screenInfo.WAttributes & (foregroundRed | foregroundGreen | foregroundBlue),
			foreground,
		}
		colorMap[ansiBackgroundDefault] = winColor{
			screenInfo.WAttributes & (backgroundRed | backgroundGreen | backgroundBlue),
			background,
		}
		defaultAttr = convertTextAttr(screenInfo.WAttributes)
	}
}

type coord struct {
	X, Y int16
}

type smallRect struct {
	Left, Top, Right, Bottom int16
}

type consoleScreenBufferInfo struct {
	DwSize              coord
	DwCursorPosition    coord
	WAttributes         uint16
	SrWindow            smallRect
	DwMaximumWindowSize coord
}

func getConsoleScreenBufferInfo(hConsoleOutput uintptr) *consoleScreenBufferInfo {
	var csbi consoleScreenBufferInfo
	ret, _, _ := procGetConsoleScreenBufferInfo.Call(
		hConsoleOutput,
		uintptr(unsafe.Pointer(&csbi)))
	if ret == 0 {
		return nil
	}
	return &csbi
}

func setConsoleTextAttribute(hConsoleOutput uintptr, wAttributes uint16) bool {
	ret, _, _ := procSetConsoleTextAttribute.Call(
		hConsoleOutput,
		uintptr(wAttributes))
	return ret != 0
}

type textAttributes struct {
	foregroundColor     uint16
	backgroundColor     uint16
	foregroundIntensity uint16
	backgroundIntensity uint16
	underscore          uint16
	otherAttributes     uint16
}

func convertTextAttr(winAttr uint16) *textAttributes {
	fgColor := winAttr & (foregroundRed | foregroundGreen | foregroundBlue)
	bgColor := winAttr & (backgroundRed | backgroundGreen | backgroundBlue)
	fgIntensity := winAttr & foregroundIntensity
	bgIntensity := winAttr & backgroundIntensity
	underline := winAttr & underscore
	otherAttributes := winAttr &^ (foregroundMask | backgroundMask | underscore)
	return &textAttributes{fgColor, bgColor, fgIntensity, bgIntensity, underline, otherAttributes}
}

func convertWinAttr(textAttr *textAttributes) uint16 {
	var winAttr uint16 = 0
	winAttr |= textAttr.foregroundColor
	winAttr |= textAttr.backgroundColor
	winAttr |= textAttr.foregroundIntensity
	winAttr |= textAttr.backgroundIntensity
	winAttr |= textAttr.underscore
	winAttr |= textAttr.otherAttributes
	return winAttr
}

func changeColor(param []byte) {
	if defaultAttr == nil {
		return
	}

	screenInfo := getConsoleScreenBufferInfo(uintptr(syscall.Stdout))
	if screenInfo == nil {
		return
	}

	winAttr := convertTextAttr(screenInfo.WAttributes)
	strParam := string(param)
	if len(strParam) <= 0 {
		strParam = "0"
	}
	csiParam := strings.Split(strParam, string(separatorChar))
	for _, p := range csiParam {
		c, ok := colorMap[p]
		switch {
		case !ok:
			switch p {
			case ansiReset:
				winAttr.foregroundColor = defaultAttr.foregroundColor
				winAttr.backgroundColor = defaultAttr.backgroundColor
				winAttr.foregroundIntensity = defaultAttr.foregroundIntensity
				winAttr.backgroundIntensity = defaultAttr.backgroundIntensity
				winAttr.underscore = 0
				winAttr.otherAttributes = 0
			case ansiIntensityOn:
				winAttr.foregroundIntensity = foregroundIntensity
			case ansiIntensityOff:
				winAttr.foregroundIntensity = 0
			case ansiUnderlineOn:
				winAttr.underscore = underscore
			case ansiUnderlineOff:
				winAttr.underscore = 0
			case ansiBlinkOn:
				winAttr.backgroundIntensity = backgroundIntensity
			case ansiBlinkOff:
				winAttr.backgroundIntensity = 0
			default:
				// unknown code
			}
		case c.drawType == foreground:
			winAttr.foregroundColor = c.code
		case c.drawType == background:
			winAttr.backgroundColor = c.code
		}
	}
	winTextAttribute := convertWinAttr(winAttr)
	setConsoleTextAttribute(uintptr(syscall.Stdout), winTextAttribute)
}

func parseEscapeSequence(command byte, param []byte) bool {
	switch command {
	case sgrCode:
		changeColor(param)
	default:
		return false
	}
	return true
}

func flush(cw *ansiColorWriter) (int, error) {
	return flushTo(cw, cw.w)
}
func empty(cw *ansiColorWriter) (int, error) {
	return flushTo(cw, nil)
}
func flushTo(cw *ansiColorWriter, w io.Writer) (int, error) {
	var n1, n2 int
	var err error

	startBytes := cw.paramStartBuf.Bytes()
	cw.paramStartBuf.Reset()
	if w != nil {
		n1, err = cw.w.Write(startBytes)
		if err != nil {
			return n1, err
		}
	} else {
		n1 = len(startBytes)
	}
	paramBytes := cw.paramBuf.Bytes()
	cw.paramBuf.Reset()
	if w != nil {
		n2, err = cw.w.Write(paramBytes)
		if err != nil {
			return n1 + n2, err
		}
	} else {
		n2 = len(paramBytes)
	}
	return n1 + n2, nil
}

func isParameterChar(b byte) bool {
	return ('0' <= b && b <= '9') || b == separatorChar
}

func (cw *ansiColorWriter) Write(p []byte) (int, error) {
	r, nw, first, last := 0, 0, 0, 0
	cw.state = outsideCsiCode
	empty(cw)

	var err error
	for i, ch := range p {
		switch cw.state {
		case outsideCsiCode:
			if ch == firstCsiChar {
				cw.paramStartBuf.WriteByte(ch)
				cw.state = firstCsiCode
			}
		case firstCsiCode:
			switch ch {
			case firstCsiChar:
				cw.paramStartBuf.WriteByte(ch)
				break
			case secondeCsiChar:
				cw.paramStartBuf.WriteByte(ch)
				cw.state = secondCsiCode
				last = i - 1
			default:
				empty(cw)
				cw.state = outsideCsiCode
			}
		case secondCsiCode:
			if isParameterChar(ch) {
				cw.paramBuf.WriteByte(ch)
			} else {
				nw, err = cw.w.Write(p[first:last])
				r += nw
				if err != nil {
					return r, err
				}
				first = i + 1
				if !parseEscapeSequence(ch, cw.paramBuf.Bytes()) {
					cw.paramBuf.WriteByte(ch)
					nw, err := flush(cw)
					if err != nil {
						return r, err
					}
					r += nw
				} else {
					n, _ := empty(cw)
					// Add one more to the size of the buffer for the last ch
					r += n + 1
				}

				cw.state = outsideCsiCode
			}
		default:
			cw.state = outsideCsiCode
		}
	}

	nw, err = cw.w.Write(p[first:len(p)])
	r += nw

	return r, err
}
<commit_msg>Migrate to method from function<commit_after>// Copyright 2014 shiena Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

// +build windows

package ansicolor

import (
	"bytes"
	"io"
	"strings"
	"syscall"
	"unsafe"
)

type csiState int

const (
	outsideCsiCode csiState = iota
	firstCsiCode
	secondCsiCode
)

type ansiColorWriter struct {
	w             io.Writer
	state         csiState
	paramStartBuf bytes.Buffer
	paramBuf      bytes.Buffer
}

const (
	firstCsiChar   byte = '\x1b'
	secondeCsiChar byte = '['
	separatorChar  byte = ';'
	sgrCode        byte = 'm'
)

const (
	foregroundBlue      = uint16(0x0001)
	foregroundGreen     = uint16(0x0002)
	foregroundRed       = uint16(0x0004)
	foregroundIntensity = uint16(0x0008)
	backgroundBlue      = uint16(0x0010)
	backgroundGreen     = uint16(0x0020)
	backgroundRed       = uint16(0x0040)
	backgroundIntensity = uint16(0x0080)
	underscore          = uint16(0x8000)

	foregroundMask = foregroundBlue | foregroundGreen | foregroundRed | foregroundIntensity
	backgroundMask = backgroundBlue | backgroundGreen | backgroundRed | backgroundIntensity
)

const (
	ansiReset        = "0"
	ansiIntensityOn  = "1"
	ansiIntensityOff = "21"
	ansiUnderlineOn  = "4"
	ansiUnderlineOff = "24"
	ansiBlinkOn      = "5"
	ansiBlinkOff     = "25"

	ansiForegroundBlack   = "30"
	ansiForegroundRed     = "31"
	ansiForegroundGreen   = "32"
	ansiForegroundYellow  = "33"
	ansiForegroundBlue    = "34"
	ansiForegroundMagenta = "35"
	ansiForegroundCyan    = "36"
	ansiForegroundWhite   = "37"
	ansiForegroundDefault = "39"

	ansiBackgroundBlack   = "40"
	ansiBackgroundRed     = "41"
	ansiBackgroundGreen   = "42"
	ansiBackgroundYellow  = "43"
	ansiBackgroundBlue    = "44"
	ansiBackgroundMagenta = "45"
	ansiBackgroundCyan    = "46"
	ansiBackgroundWhite   = "47"
	ansiBackgroundDefault = "49"

	ansiLightForegroundGray    = "90"
	ansiLightForegroundRed     = "91"
	ansiLightForegroundGreen   = "92"
	ansiLightForegroundYellow  = "93"
	ansiLightForegroundBlue    = "94"
	ansiLightForegroundMagenta = "95"
	ansiLightForegroundCyan    = "96"
	ansiLightForegroundWhite   = "97"

	ansiLightBackgroundGray    = "100"
	ansiLightBackgroundRed     = "101"
	ansiLightBackgroundGreen   = "102"
	ansiLightBackgroundYellow  = "103"
	ansiLightBackgroundBlue    = "104"
	ansiLightBackgroundMagenta = "105"
	ansiLightBackgroundCyan    = "106"
	ansiLightBackgroundWhite   = "107"
)

type drawType int

const (
	foreground drawType = iota
	background
)

type winColor struct {
	code     uint16
	drawType drawType
}

var colorMap = map[string]winColor{
	ansiForegroundBlack:   {0, foreground},
	ansiForegroundRed:     {foregroundRed, foreground},
	ansiForegroundGreen:   {foregroundGreen, foreground},
	ansiForegroundYellow:  {foregroundRed | foregroundGreen, foreground},
	ansiForegroundBlue:    {foregroundBlue, foreground},
	ansiForegroundMagenta: {foregroundRed | foregroundBlue, foreground},
	ansiForegroundCyan:    {foregroundGreen | foregroundBlue, foreground},
	ansiForegroundWhite:   {foregroundRed | foregroundGreen | foregroundBlue, foreground},
	ansiForegroundDefault: {foregroundRed | foregroundGreen | foregroundBlue, foreground},

	ansiBackgroundBlack:   {0, background},
	ansiBackgroundRed:     {backgroundRed, background},
	ansiBackgroundGreen:   {backgroundGreen, background},
	ansiBackgroundYellow:  {backgroundRed | backgroundGreen, background},
	ansiBackgroundBlue:    {backgroundBlue, background},
	ansiBackgroundMagenta: {backgroundRed | backgroundBlue, background},
	ansiBackgroundCyan:    {backgroundGreen | backgroundBlue, background},
	ansiBackgroundWhite:   {backgroundRed | backgroundGreen | backgroundBlue, background},
	ansiBackgroundDefault: {0, background},

	ansiLightForegroundGray:    {foregroundIntensity, foreground},
	ansiLightForegroundRed:     {foregroundIntensity | foregroundRed, foreground},
	ansiLightForegroundGreen:   {foregroundIntensity | foregroundGreen, foreground},
	ansiLightForegroundYellow:  {foregroundIntensity | foregroundRed | foregroundGreen, foreground},
	ansiLightForegroundBlue:    {foregroundIntensity | foregroundBlue, foreground},
	ansiLightForegroundMagenta: {foregroundIntensity | foregroundRed | foregroundBlue, foreground},
	ansiLightForegroundCyan:    {foregroundIntensity | foregroundGreen | foregroundBlue, foreground},
	ansiLightForegroundWhite:   {foregroundIntensity | foregroundRed | foregroundGreen | foregroundBlue, foreground},

	ansiLightBackgroundGray:    {backgroundIntensity, background},
	ansiLightBackgroundRed:     {backgroundIntensity | backgroundRed, background},
	ansiLightBackgroundGreen:   {backgroundIntensity | backgroundGreen, background},
	ansiLightBackgroundYellow:  {backgroundIntensity | backgroundRed | backgroundGreen, background},
	ansiLightBackgroundBlue:    {backgroundIntensity | backgroundBlue, background},
	ansiLightBackgroundMagenta: {backgroundIntensity | backgroundRed | backgroundBlue, background},
	ansiLightBackgroundCyan:    {backgroundIntensity | backgroundGreen | backgroundBlue, background},
	ansiLightBackgroundWhite:   {backgroundIntensity | backgroundRed | backgroundGreen | backgroundBlue, background},
}

var (
	kernel32                       = syscall.NewLazyDLL("kernel32.dll")
	procSetConsoleTextAttribute    = kernel32.NewProc("SetConsoleTextAttribute")
	procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
	defaultAttr                    *textAttributes
)

func init() {
	screenInfo := getConsoleScreenBufferInfo(uintptr(syscall.Stdout))
	if screenInfo != nil {
		colorMap[ansiForegroundDefault] = winColor{
			screenInfo.WAttributes & (foregroundRed | foregroundGreen | foregroundBlue),
			foreground,
		}
		colorMap[ansiBackgroundDefault] = winColor{
			screenInfo.WAttributes & (backgroundRed | backgroundGreen | backgroundBlue),
			background,
		}
		defaultAttr = convertTextAttr(screenInfo.WAttributes)
	}
}

type coord struct {
	X, Y int16
}

type smallRect struct {
	Left, Top, Right, Bottom int16
}

type consoleScreenBufferInfo struct {
	DwSize              coord
	DwCursorPosition    coord
	WAttributes         uint16
	SrWindow            smallRect
	DwMaximumWindowSize coord
}

func getConsoleScreenBufferInfo(hConsoleOutput uintptr) *consoleScreenBufferInfo {
	var csbi consoleScreenBufferInfo
	ret, _, _ := procGetConsoleScreenBufferInfo.Call(
		hConsoleOutput,
		uintptr(unsafe.Pointer(&csbi)))
	if ret == 0 {
		return nil
	}
	return &csbi
}

func setConsoleTextAttribute(hConsoleOutput uintptr, wAttributes uint16) bool {
	ret, _, _ := procSetConsoleTextAttribute.Call(
		hConsoleOutput,
		uintptr(wAttributes))
	return ret != 0
}

type textAttributes struct {
	foregroundColor     uint16
	backgroundColor     uint16
	foregroundIntensity uint16
	backgroundIntensity uint16
	underscore          uint16
	otherAttributes     uint16
}

func convertTextAttr(winAttr uint16) *textAttributes {
	fgColor := winAttr & (foregroundRed | foregroundGreen | foregroundBlue)
	bgColor := winAttr & (backgroundRed | backgroundGreen | backgroundBlue)
	fgIntensity := winAttr & foregroundIntensity
	bgIntensity := winAttr & backgroundIntensity
	underline := winAttr & underscore
	otherAttributes := winAttr &^ (foregroundMask | backgroundMask | underscore)
	return &textAttributes{fgColor, bgColor, fgIntensity, bgIntensity, underline, otherAttributes}
}

func convertWinAttr(textAttr *textAttributes) uint16 {
	var winAttr uint16 = 0
	winAttr |= textAttr.foregroundColor
	winAttr |= textAttr.backgroundColor
	winAttr |= textAttr.foregroundIntensity
	winAttr |= textAttr.backgroundIntensity
	winAttr |= textAttr.underscore
	winAttr |= textAttr.otherAttributes
	return winAttr
}

func changeColor(param []byte) {
	if defaultAttr == nil {
		return
	}

	screenInfo := getConsoleScreenBufferInfo(uintptr(syscall.Stdout))
	if screenInfo == nil {
		return
	}

	winAttr := convertTextAttr(screenInfo.WAttributes)
	strParam := string(param)
	if len(strParam) <= 0 {
		strParam = "0"
	}
	csiParam := strings.Split(strParam, string(separatorChar))
	for _, p := range csiParam {
		c, ok := colorMap[p]
		switch {
		case !ok:
			switch p {
			case ansiReset:
				winAttr.foregroundColor = defaultAttr.foregroundColor
				winAttr.backgroundColor = defaultAttr.backgroundColor
				winAttr.foregroundIntensity = defaultAttr.foregroundIntensity
				winAttr.backgroundIntensity = defaultAttr.backgroundIntensity
				winAttr.underscore = 0
				winAttr.otherAttributes = 0
			case ansiIntensityOn:
				winAttr.foregroundIntensity = foregroundIntensity
			case ansiIntensityOff:
				winAttr.foregroundIntensity = 0
			case ansiUnderlineOn:
				winAttr.underscore = underscore
			case ansiUnderlineOff:
				winAttr.underscore = 0
			case ansiBlinkOn:
				winAttr.backgroundIntensity = backgroundIntensity
			case ansiBlinkOff:
				winAttr.backgroundIntensity = 0
			default:
				// unknown code
			}
		case c.drawType == foreground:
			winAttr.foregroundColor = c.code
		case c.drawType == background:
			winAttr.backgroundColor = c.code
		}
	}
	winTextAttribute := convertWinAttr(winAttr)
	setConsoleTextAttribute(uintptr(syscall.Stdout), winTextAttribute)
}

func parseEscapeSequence(command byte, param []byte) bool {
	switch command {
	case sgrCode:
		changeColor(param)
	default:
		return false
	}
	return true
}

func (cw *ansiColorWriter) flushBuffer() (int, error) {
	return cw.flushTo(cw.w)
}

func (cw *ansiColorWriter) resetBuffer() (int, error) {
	return cw.flushTo(nil)
}

func (cw *ansiColorWriter) flushTo(w io.Writer) (int, error) {
	var n1, n2 int
	var err error

	startBytes := cw.paramStartBuf.Bytes()
	cw.paramStartBuf.Reset()
	if w != nil {
		n1, err = cw.w.Write(startBytes)
		if err != nil {
			return n1, err
		}
	} else {
		n1 = len(startBytes)
	}
	paramBytes := cw.paramBuf.Bytes()
	cw.paramBuf.Reset()
	if w != nil {
		n2, err = cw.w.Write(paramBytes)
		if err != nil {
			return n1 + n2, err
		}
	} else {
		n2 = len(paramBytes)
	}
	return n1 + n2, nil
}

func isParameterChar(b byte) bool {
	return ('0' <= b && b <= '9') || b == separatorChar
}

func (cw *ansiColorWriter) Write(p []byte) (int, error) {
	r, nw, first, last := 0, 0, 0, 0
	cw.state = outsideCsiCode
	cw.resetBuffer()

	var err error
	for i, ch := range p {
		switch cw.state {
		case outsideCsiCode:
			if ch == firstCsiChar {
				cw.paramStartBuf.WriteByte(ch)
				cw.state = firstCsiCode
			}
		case firstCsiCode:
			switch ch {
			case firstCsiChar:
				cw.paramStartBuf.WriteByte(ch)
				break
			case secondeCsiChar:
				cw.paramStartBuf.WriteByte(ch)
				cw.state = secondCsiCode
				last = i - 1
			default:
				cw.resetBuffer()
				cw.state = outsideCsiCode
			}
		case secondCsiCode:
			if isParameterChar(ch) {
				cw.paramBuf.WriteByte(ch)
			} else {
				nw, err = cw.w.Write(p[first:last])
				r += nw
				if err != nil {
					return r, err
				}
				first = i + 1
				if !parseEscapeSequence(ch, cw.paramBuf.Bytes()) {
					cw.paramBuf.WriteByte(ch)
					nw, err := cw.flushBuffer()
					if err != nil {
						return r, err
					}
					r += nw
				} else {
					n, _ := cw.resetBuffer()
					// Add one more to the size of the buffer for the last ch
					r += n + 1
				}

				cw.state = outsideCsiCode
			}
		default:
			cw.state = outsideCsiCode
		}
	}

	nw, err = cw.w.Write(p[first:len(p)])
	r += nw

	return r, err
}
<|endoftext|>


<commit_before><commit_msg>[notifications] further notification formatting improvements<commit_after><|endoftext|>