<commit_before>package mstypes

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"

	"gopkg.in/jcmturner/rpc.v0/ndr"
)

// Compression format assigned numbers.
const (
	CompressionFormatNone       uint16 = 0
	CompressionFormatLZNT1      uint16 = 2
	CompressionFormatXPress     uint16 = 3
	CompressionFormatXPressHuff uint16 = 4
)

// ClaimsSourceTypeAD
const ClaimsSourceTypeAD uint16 = 1

// Claim Type assigned numbers
const (
	ClaimTypeIDInt64    uint16 = 1
	ClaimTypeIDUInt64   uint16 = 2
	ClaimTypeIDString   uint16 = 3
	ClaimsTypeIDBoolean uint16 = 6
)

// ClaimsBlob implements https://msdn.microsoft.com/en-us/library/hh554119.aspx
type ClaimsBlob struct {
	Size        uint32
	EncodedBlob []byte
}

// ReadClaimsBlob reads a ClaimsBlob from the byte slice.
func ReadClaimsBlob(b *[]byte, p *int, e *binary.ByteOrder) (c ClaimsBlob) {
	c.Size = ndr.ReadUint32(b, p, e)
	c.EncodedBlob = ndr.ReadBytes(b, p, int(c.Size), e)
	return
}

// ClaimsSetMetadata implements https://msdn.microsoft.com/en-us/library/hh554073.aspx
type ClaimsSetMetadata struct {
	claimsSetSize             uint32
	ClaimsSet                 ClaimsSet
	CompressionFormat         uint16 // Enum see constants for options
	uncompressedClaimsSetSize uint32
	ReservedType              uint16
	reservedFieldSize         uint32
	ReservedField             []byte
}

// ClaimsSet implements https://msdn.microsoft.com/en-us/library/hh554122.aspx
type ClaimsSet struct {
	ClaimsArrayCount  uint32
	ClaimsArrays      []ClaimsArray
	ReservedType      uint16
	reservedFieldSize uint32
	ReservedField     []byte
}

// ClaimsArray implements https://msdn.microsoft.com/en-us/library/hh536458.aspx
type ClaimsArray struct {
	ClaimsSourceType uint16
	ClaimsCount      uint32
	ClaimsEntries    []ClaimEntry
}

// ClaimEntry implements https://msdn.microsoft.com/en-us/library/hh536374.aspx
type ClaimEntry struct {
	ID         string //utf16string
	Type       uint16 // enums are 16 bit https://msdn.microsoft.com/en-us/library/windows/desktop/aa366818(v=vs.85).aspx
	TypeInt64  ClaimTypeInt64
	TypeUInt64 ClaimTypeUInt64
	TypeString ClaimTypeString
	TypeBool   ClaimTypeBoolean
}

// ClaimTypeInt64 is a claim of type int64
type ClaimTypeInt64 struct {
	ValueCount uint32
	Value      []int64
}

// ClaimTypeUInt64 is a claim of type uint64
type ClaimTypeUInt64 struct {
	ValueCount uint32
	Value      []uint64
}

// ClaimTypeString is a claim of type string
type ClaimTypeString struct {
	ValueCount uint32
	Value      []string
}

// ClaimTypeBoolean is a claim of type bool
type ClaimTypeBoolean struct {
	ValueCount uint32
	Value      []bool
}

// ReadClaimsSetMetadata reads a ClaimsSetMetadata from the bytes slice.
func ReadClaimsSetMetadata(b *[]byte, p *int, e *binary.ByteOrder) (c ClaimsSetMetadata, err error) {
	c.claimsSetSize = ndr.ReadUint32(b, p, e)
	*p += 4 //Move over pointer to ClaimSet array
	c.CompressionFormat = ndr.ReadUint16(b, p, e)
	// TODO Currently compression is not supported so if it is compressed we just have to return.
	if c.CompressionFormat != CompressionFormatNone {
		*p = len(*b)
		return
	}
	c.uncompressedClaimsSetSize = ndr.ReadUint32(b, p, e)
	c.ReservedType = ndr.ReadUint16(b, p, e)
	c.reservedFieldSize = ndr.ReadUint32(b, p, e)
	*p += 4 //Move over pointer to ReservedField array
	var ah ndr.ConformantArrayHeader
	if c.claimsSetSize > 0 {
		// ClaimsSet is a conformant array https://msdn.microsoft.com/en-us/library/windows/desktop/aa373603(v=vs.85).aspx
		ah, err = ndr.ReadUniDimensionalConformantArrayHeader(b, p, e)
		if err != nil {
			return
		}
		if ah.MaxCount != int(c.claimsSetSize) {
			err = errors.New("error with size of CLAIMS_SET array")
			return
		}
		csb := ndr.ReadBytes(b, p, int(c.claimsSetSize), e)
		//TODO put decompression here
		c.ClaimsSet, err = ReadClaimsSet(csb)
		if err != nil {
			return
		}
	}
	if c.reservedFieldSize > 0 {
		ah, err = ndr.ReadUniDimensionalConformantArrayHeader(b, p, e)
		if err != nil {
			return
		}
		if ah.MaxCount != int(c.reservedFieldSize) {
			err = errors.New("error with size of CLAIMS_SET_METADATA's reserved field array")
			return
		}
		c.ReservedField = ndr.ReadBytes(b, p, int(c.reservedFieldSize), e)
	}
	return
}

// ReadClaimsSet reads a ClaimsSet from the bytes slice.
func ReadClaimsSet(b []byte) (c ClaimsSet, err error) {
	ch, _, p, err := ndr.ReadHeaders(&b)
	if err != nil {
		err = fmt.Errorf("error parsing NDR byte stream headers of CLAIMS_SET: %v", err)
		return
	}
	e := &ch.Endianness
	//The next 4 bytes are an RPC unique pointer referent. We just skip these
	p += 4

	c.ClaimsArrayCount = ndr.ReadUint32(&b, &p, e)
	p += 4 //Move over pointer to claims array
	c.ReservedType = ndr.ReadUint16(&b, &p, e)
	c.reservedFieldSize = ndr.ReadUint32(&b, &p, e)
	p += 4 //Move over pointer to ReservedField array

	var ah ndr.ConformantArrayHeader
	if c.ClaimsArrayCount > 0 {
		ah, err = ndr.ReadUniDimensionalConformantArrayHeader(&b, &p, e)
		if err != nil {
			return
		}
		if ah.MaxCount != int(c.ClaimsArrayCount) {
			err = errors.New("error with size of CLAIMS_SET's claims array")
			return
		}
		c.ClaimsArrays = make([]ClaimsArray, c.ClaimsArrayCount, c.ClaimsArrayCount)
		for i := range c.ClaimsArrays {
			c.ClaimsArrays[i], err = ReadClaimsArray(&b, &p, e)
			if err != nil {
				return
			}
		}
	}
	if c.reservedFieldSize > 0 {
		ah, err = ndr.ReadUniDimensionalConformantArrayHeader(&b, &p, e)
		if err != nil {
			return
		}
		if ah.MaxCount != int(c.reservedFieldSize) {
			err = errors.New("error with size of CLAIMS_SET's reserved field array")
			return
		}
		c.ReservedField = ndr.ReadBytes(&b, &p, int(c.reservedFieldSize), e)
	}
	return c, nil
}

// ReadClaimsArray reads a ClaimsArray from the bytes slice.
func ReadClaimsArray(b *[]byte, p *int, e *binary.ByteOrder) (c ClaimsArray, err error) {
	c.ClaimsSourceType = ndr.ReadUint16(b, p, e)
	c.ClaimsCount = ndr.ReadUint32(b, p, e)
	*p += 4 //Move over pointer to claims array
	ah, err := ndr.ReadUniDimensionalConformantArrayHeader(b, p, e)
	if err != nil {
		return
	}
	if ah.MaxCount != int(c.ClaimsCount) {
		err = errors.New("error with size of CLAIMS_ARRAY's claims entries")
		return
	}
	c.ClaimsEntries = make([]ClaimEntry, c.ClaimsCount, c.ClaimsCount)
	for i := range c.ClaimsEntries {
		var vc uint32
		c.ClaimsEntries[i].Type, vc, err = ReadClaimEntriesUnionHeaders(b, p, e)
		if err != nil {
			return
		}
		switch c.ClaimsEntries[i].Type {
		case ClaimTypeIDInt64:
			c.ClaimsEntries[i].TypeInt64.ValueCount = vc
		case ClaimTypeIDUInt64:
			c.ClaimsEntries[i].TypeUInt64.ValueCount = vc
		case ClaimTypeIDString:
			c.ClaimsEntries[i].TypeString.ValueCount = vc
		case ClaimsTypeIDBoolean:
			c.ClaimsEntries[i].TypeBool.ValueCount = vc
		}
	}
	for i := range c.ClaimsEntries {
		err = FillClaimEntry(b, p, e, &c.ClaimsEntries[i])
		if err != nil {
			return
		}
	}
	return
}

// ReadClaimEntriesUnionHeaders reads the union headers from the byte stream.
func ReadClaimEntriesUnionHeaders(b *[]byte, p *int, e *binary.ByteOrder) (uint16, uint32, error) {
	*p += 4
	// This is an NDR union: http://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagfcjh_39
	// The discriminant [tag] is marshalled into the transmitted data stream twice:
	// once as the field or parameter in the procedure argument list and
	// once as the first part of the union representation [value]
	t1 := ndr.ReadUint16(b, p, e)
	t2 := ndr.ReadUint16(b, p, e)
	if t1 != t2 {
		return 0, 0, ndr.Malformed{EText: "malformed NDR encoding of CLAIM_ENTRY union"}
	}
	vc := ndr.ReadUint32(b, p, e)
	*p += 4 //Move over pointer to array of values
	return t1, vc, nil
}

// FillClaimEntry reads a ClaimEntry from the bytes slice.
func FillClaimEntry(b *[]byte, p *int, e *binary.ByteOrder, c *ClaimEntry) (err error) {
	c.ID, err = ndr.ReadConformantVaryingString(b, p, e)
	if err != nil {
		return
	}
	ah, err := ndr.ReadUniDimensionalConformantArrayHeader(b, p, e)
	if err != nil {
		return
	}
	switch c.Type {
	case ClaimTypeIDInt64:
		if ah.MaxCount != int(c.TypeInt64.ValueCount) {
			return errors.New("error with size of CLAIM_ENTRY's value")
		}
		c.TypeInt64.Value = make([]int64, c.TypeInt64.ValueCount, c.TypeInt64.ValueCount)
		for i := range c.TypeInt64.Value {
			buf := bytes.NewReader((*b)[*p : *p+8])
			err = binary.Read(buf, *e, &c.TypeInt64.Value[i])
			if err != nil {
				return
			}
			*p += 8 // progress position for a uint64
		}
	case ClaimTypeIDUInt64:
		if ah.MaxCount != int(c.TypeUInt64.ValueCount) {
			return errors.New("error with size of CLAIM_ENTRY's value")
		}
		c.TypeUInt64.Value = make([]uint64, c.TypeUInt64.ValueCount, c.TypeUInt64.ValueCount)
		for i := range c.TypeUInt64.Value {
			c.TypeUInt64.Value[i] = ndr.ReadUint64(b, p, e)
		}
	case ClaimTypeIDString:
		if ah.MaxCount != int(c.TypeString.ValueCount) {
			return errors.New("error with size of CLAIM_ENTRY's value")
		}
		c.TypeString.Value = make([]string, c.TypeString.ValueCount, c.TypeString.ValueCount)
		*p += 4 * (int(c.TypeString.ValueCount)) // Move over pointers
		for i := range c.TypeString.Value {
			c.TypeString.Value[i], err = ndr.ReadConformantVaryingString(b, p, e)
			if err != nil {
				return
			}
		}
	case ClaimsTypeIDBoolean:
		if ah.MaxCount != int(c.TypeBool.ValueCount) {
			return errors.New("error with size of CLAIM_ENTRY's value")
		}
		c.TypeBool.Value = make([]bool, c.TypeBool.ValueCount, c.TypeBool.ValueCount)
		for i := range c.TypeBool.Value {
			if ndr.ReadUint64(b, p, e) != 0 {
				c.TypeBool.Value[i] = true
			}
		}
	}
	return
}
<commit_msg>lint fix<commit_after>package mstypes

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"

	"gopkg.in/jcmturner/rpc.v0/ndr"
)

// Compression format assigned numbers.
const (
	CompressionFormatNone       uint16 = 0
	CompressionFormatLZNT1      uint16 = 2
	CompressionFormatXPress     uint16 = 3
	CompressionFormatXPressHuff uint16 = 4
)

// ClaimsSourceTypeAD https://msdn.microsoft.com/en-us/library/hh553809.aspx
const ClaimsSourceTypeAD uint16 = 1

// Claim Type assigned numbers
const (
	ClaimTypeIDInt64    uint16 = 1
	ClaimTypeIDUInt64   uint16 = 2
	ClaimTypeIDString   uint16 = 3
	ClaimsTypeIDBoolean uint16 = 6
)

// ClaimsBlob implements https://msdn.microsoft.com/en-us/library/hh554119.aspx
type ClaimsBlob struct {
	Size        uint32
	EncodedBlob []byte
}

// ReadClaimsBlob reads a ClaimsBlob from the byte slice.
func ReadClaimsBlob(b *[]byte, p *int, e *binary.ByteOrder) (c ClaimsBlob) {
	c.Size = ndr.ReadUint32(b, p, e)
	c.EncodedBlob = ndr.ReadBytes(b, p, int(c.Size), e)
	return
}

// ClaimsSetMetadata implements https://msdn.microsoft.com/en-us/library/hh554073.aspx
type ClaimsSetMetadata struct {
	claimsSetSize             uint32
	ClaimsSet                 ClaimsSet
	CompressionFormat         uint16 // Enum see constants for options
	uncompressedClaimsSetSize uint32
	ReservedType              uint16
	reservedFieldSize         uint32
	ReservedField             []byte
}

// ClaimsSet implements https://msdn.microsoft.com/en-us/library/hh554122.aspx
type ClaimsSet struct {
	ClaimsArrayCount  uint32
	ClaimsArrays      []ClaimsArray
	ReservedType      uint16
	reservedFieldSize uint32
	ReservedField     []byte
}

// ClaimsArray implements https://msdn.microsoft.com/en-us/library/hh536458.aspx
type ClaimsArray struct {
	ClaimsSourceType uint16
	ClaimsCount      uint32
	ClaimsEntries    []ClaimEntry
}

// ClaimEntry implements https://msdn.microsoft.com/en-us/library/hh536374.aspx
type ClaimEntry struct {
	ID         string //utf16string
	Type       uint16 // enums are 16 bit https://msdn.microsoft.com/en-us/library/windows/desktop/aa366818(v=vs.85).aspx
	TypeInt64  ClaimTypeInt64
	TypeUInt64 ClaimTypeUInt64
	TypeString ClaimTypeString
	TypeBool   ClaimTypeBoolean
}

// ClaimTypeInt64 is a claim of type int64
type ClaimTypeInt64 struct {
	ValueCount uint32
	Value      []int64
}

// ClaimTypeUInt64 is a claim of type uint64
type ClaimTypeUInt64 struct {
	ValueCount uint32
	Value      []uint64
}

// ClaimTypeString is a claim of type string
type ClaimTypeString struct {
	ValueCount uint32
	Value      []string
}

// ClaimTypeBoolean is a claim of type bool
type ClaimTypeBoolean struct {
	ValueCount uint32
	Value      []bool
}

// ReadClaimsSetMetadata reads a ClaimsSetMetadata from the bytes slice.
func ReadClaimsSetMetadata(b *[]byte, p *int, e *binary.ByteOrder) (c ClaimsSetMetadata, err error) {
	c.claimsSetSize = ndr.ReadUint32(b, p, e)
	*p += 4 //Move over pointer to ClaimSet array
	c.CompressionFormat = ndr.ReadUint16(b, p, e)
	// TODO Currently compression is not supported so if it is compressed we just have to return.
	if c.CompressionFormat != CompressionFormatNone {
		*p = len(*b)
		return
	}
	c.uncompressedClaimsSetSize = ndr.ReadUint32(b, p, e)
	c.ReservedType = ndr.ReadUint16(b, p, e)
	c.reservedFieldSize = ndr.ReadUint32(b, p, e)
	*p += 4 //Move over pointer to ReservedField array
	var ah ndr.ConformantArrayHeader
	if c.claimsSetSize > 0 {
		// ClaimsSet is a conformant array https://msdn.microsoft.com/en-us/library/windows/desktop/aa373603(v=vs.85).aspx
		ah, err = ndr.ReadUniDimensionalConformantArrayHeader(b, p, e)
		if err != nil {
			return
		}
		if ah.MaxCount != int(c.claimsSetSize) {
			err = errors.New("error with size of CLAIMS_SET array")
			return
		}
		csb := ndr.ReadBytes(b, p, int(c.claimsSetSize), e)
		//TODO put decompression here
		c.ClaimsSet, err = ReadClaimsSet(csb)
		if err != nil {
			return
		}
	}
	if c.reservedFieldSize > 0 {
		ah, err = ndr.ReadUniDimensionalConformantArrayHeader(b, p, e)
		if err != nil {
			return
		}
		if ah.MaxCount != int(c.reservedFieldSize) {
			err = errors.New("error with size of CLAIMS_SET_METADATA's reserved field array")
			return
		}
		c.ReservedField = ndr.ReadBytes(b, p, int(c.reservedFieldSize), e)
	}
	return
}

// ReadClaimsSet reads a ClaimsSet from the bytes slice.
func ReadClaimsSet(b []byte) (c ClaimsSet, err error) {
	ch, _, p, err := ndr.ReadHeaders(&b)
	if err != nil {
		err = fmt.Errorf("error parsing NDR byte stream headers of CLAIMS_SET: %v", err)
		return
	}
	e := &ch.Endianness
	//The next 4 bytes are an RPC unique pointer referent. We just skip these
	p += 4

	c.ClaimsArrayCount = ndr.ReadUint32(&b, &p, e)
	p += 4 //Move over pointer to claims array
	c.ReservedType = ndr.ReadUint16(&b, &p, e)
	c.reservedFieldSize = ndr.ReadUint32(&b, &p, e)
	p += 4 //Move over pointer to ReservedField array

	var ah ndr.ConformantArrayHeader
	if c.ClaimsArrayCount > 0 {
		ah, err = ndr.ReadUniDimensionalConformantArrayHeader(&b, &p, e)
		if err != nil {
			return
		}
		if ah.MaxCount != int(c.ClaimsArrayCount) {
			err = errors.New("error with size of CLAIMS_SET's claims array")
			return
		}
		c.ClaimsArrays = make([]ClaimsArray, c.ClaimsArrayCount, c.ClaimsArrayCount)
		for i := range c.ClaimsArrays {
			c.ClaimsArrays[i], err = ReadClaimsArray(&b, &p, e)
			if err != nil {
				return
			}
		}
	}
	if c.reservedFieldSize > 0 {
		ah, err = ndr.ReadUniDimensionalConformantArrayHeader(&b, &p, e)
		if err != nil {
			return
		}
		if ah.MaxCount != int(c.reservedFieldSize) {
			err = errors.New("error with size of CLAIMS_SET's reserved field array")
			return
		}
		c.ReservedField = ndr.ReadBytes(&b, &p, int(c.reservedFieldSize), e)
	}
	return c, nil
}

// ReadClaimsArray reads a ClaimsArray from the bytes slice.
func ReadClaimsArray(b *[]byte, p *int, e *binary.ByteOrder) (c ClaimsArray, err error) {
	c.ClaimsSourceType = ndr.ReadUint16(b, p, e)
	c.ClaimsCount = ndr.ReadUint32(b, p, e)
	*p += 4 //Move over pointer to claims array
	ah, err := ndr.ReadUniDimensionalConformantArrayHeader(b, p, e)
	if err != nil {
		return
	}
	if ah.MaxCount != int(c.ClaimsCount) {
		err = errors.New("error with size of CLAIMS_ARRAY's claims entries")
		return
	}
	c.ClaimsEntries = make([]ClaimEntry, c.ClaimsCount, c.ClaimsCount)
	for i := range c.ClaimsEntries {
		var vc uint32
		c.ClaimsEntries[i].Type, vc, err = ReadClaimEntriesUnionHeaders(b, p, e)
		if err != nil {
			return
		}
		switch c.ClaimsEntries[i].Type {
		case ClaimTypeIDInt64:
			c.ClaimsEntries[i].TypeInt64.ValueCount = vc
		case ClaimTypeIDUInt64:
			c.ClaimsEntries[i].TypeUInt64.ValueCount = vc
		case ClaimTypeIDString:
			c.ClaimsEntries[i].TypeString.ValueCount = vc
		case ClaimsTypeIDBoolean:
			c.ClaimsEntries[i].TypeBool.ValueCount = vc
		}
	}
	for i := range c.ClaimsEntries {
		err = FillClaimEntry(b, p, e, &c.ClaimsEntries[i])
		if err != nil {
			return
		}
	}
	return
}

// ReadClaimEntriesUnionHeaders reads the union headers from the byte stream.
func ReadClaimEntriesUnionHeaders(b *[]byte, p *int, e *binary.ByteOrder) (uint16, uint32, error) {
	*p += 4
	// This is an NDR union: http://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagfcjh_39
	// The discriminant [tag] is marshalled into the transmitted data stream twice:
	// once as the field or parameter in the procedure argument list and
	// once as the first part of the union representation [value]
	t1 := ndr.ReadUint16(b, p, e)
	t2 := ndr.ReadUint16(b, p, e)
	if t1 != t2 {
		return 0, 0, ndr.Malformed{EText: "malformed NDR encoding of CLAIM_ENTRY union"}
	}
	vc := ndr.ReadUint32(b, p, e)
	*p += 4 //Move over pointer to array of values
	return t1, vc, nil
}

// FillClaimEntry reads a ClaimEntry from the bytes slice.
func FillClaimEntry(b *[]byte, p *int, e *binary.ByteOrder, c *ClaimEntry) (err error) {
	c.ID, err = ndr.ReadConformantVaryingString(b, p, e)
	if err != nil {
		return
	}
	ah, err := ndr.ReadUniDimensionalConformantArrayHeader(b, p, e)
	if err != nil {
		return
	}
	switch c.Type {
	case ClaimTypeIDInt64:
		if ah.MaxCount != int(c.TypeInt64.ValueCount) {
			return errors.New("error with size of CLAIM_ENTRY's value")
		}
		c.TypeInt64.Value = make([]int64, c.TypeInt64.ValueCount, c.TypeInt64.ValueCount)
		for i := range c.TypeInt64.Value {
			buf := bytes.NewReader((*b)[*p : *p+8])
			err = binary.Read(buf, *e, &c.TypeInt64.Value[i])
			if err != nil {
				return
			}
			*p += 8 // progress position for a uint64
		}
	case ClaimTypeIDUInt64:
		if ah.MaxCount != int(c.TypeUInt64.ValueCount) {
			return errors.New("error with size of CLAIM_ENTRY's value")
		}
		c.TypeUInt64.Value = make([]uint64, c.TypeUInt64.ValueCount, c.TypeUInt64.ValueCount)
		for i := range c.TypeUInt64.Value {
			c.TypeUInt64.Value[i] = ndr.ReadUint64(b, p, e)
		}
	case ClaimTypeIDString:
		if ah.MaxCount != int(c.TypeString.ValueCount) {
			return errors.New("error with size of CLAIM_ENTRY's value")
		}
		c.TypeString.Value = make([]string, c.TypeString.ValueCount, c.TypeString.ValueCount)
		*p += 4 * (int(c.TypeString.ValueCount)) // Move over pointers
		for i := range c.TypeString.Value {
			c.TypeString.Value[i], err = ndr.ReadConformantVaryingString(b, p, e)
			if err != nil {
				return
			}
		}
	case ClaimsTypeIDBoolean:
		if ah.MaxCount != int(c.TypeBool.ValueCount) {
			return errors.New("error with size of CLAIM_ENTRY's value")
		}
		c.TypeBool.Value = make([]bool, c.TypeBool.ValueCount, c.TypeBool.ValueCount)
		for i := range c.TypeBool.Value {
			if ndr.ReadUint64(b, p, e) != 0 {
				c.TypeBool.Value[i] = true
			}
		}
	}
	return
}
<|endoftext|>


<commit_before><commit_msg>Fix missing Close method on TestHandleService<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.

// +build !go1.12

package codec

import "reflect"

type mapIter struct {
	m      reflect.Value
	keys   []reflect.Value
	j      int
	values bool
}

func (t *mapIter) Next() (r bool) {
	t.j++
	return t.j < len(t.keys)
}

func (t *mapIter) Key() reflect.Value {
	return t.keys[t.j]
}

func (t *mapIter) Value() (r reflect.Value) {
	if t.values {
		return t.m.MapIndex(t.keys[t.j])
	}
	return
}

func mapRange(m, k, v reflect.Value, values bool) *mapIter {
	return &mapIter{
		m:      m,
		keys:   m.MapKeys(),
		values: values,
		j:      -1,
	}
}
<commit_msg>codec: goversion_maprange_lt_go112.go is only run in safe mode<commit_after>// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.

// +build !go1.12
// +build safe

package codec

import "reflect"

type mapIter struct {
	m      reflect.Value
	keys   []reflect.Value
	j      int
	values bool
}

func (t *mapIter) Next() (r bool) {
	t.j++
	return t.j < len(t.keys)
}

func (t *mapIter) Key() reflect.Value {
	return t.keys[t.j]
}

func (t *mapIter) Value() (r reflect.Value) {
	if t.values {
		return t.m.MapIndex(t.keys[t.j])
	}
	return
}

func mapRange(m, k, v reflect.Value, values bool) *mapIter {
	return &mapIter{
		m:      m,
		keys:   m.MapKeys(),
		values: values,
		j:      -1,
	}
}
<|endoftext|>


<commit_before>/*
This package is just a collection of use-case for the various aspects of the RIPE API.
Consider this both as an example on how to use the API and a testing tool for the API wrapper.
*/
package main

import (
	"fmt"
	"github.com/keltia/ripe-atlas"
	"github.com/urfave/cli"
	"log"
	"os"
	"sort"
)

var (
	// CLI specific options
	fDebug   bool
	fLogfile string
	fVerbose bool

	// See flag.go for details

	// Global API options
	fFieldList string
	fFormat    string
	fInclude   string
	fOptFields string
	fPageNum   string
	fPageSize  string
	fSortOrder string
	fWantMine  bool

	// Probe-specific ones
	fAllProbes bool
	fIsAnchor  bool

	// Common measurement ones
	fAllMeasurements bool
	fAsn             string
	fAsnV4           string
	fAsnV6           string
	fCountry         string
	fProtocol        string
	fMeasureType     string
	fWant4           bool
	fWant6           bool

	// Create measurements
	fBillTo    string
	fIsOneOff  bool
	fStartTime string
	fStopTime  string

	// HTTP
	fHTTPMethod  string
	fUserAgent   string
	fHTTPVersion string

	// DNS
	fBitCD         bool
	fDisableDNSSEC bool

	// Traceroute
	fMaxHops    int
	fPacketSize int

	// ProbeSet parameters
	fPoolSize  int
	fAreaType  string
	fAreaValue string

	// Our configuration file
	cnf *Config

	// All possible commands
	cliCommands []cli.Command

	client *atlas.Client

	// Our tiple-valued synthesis of fWant4/fWant6
	wantAF string
)

const (
	atlasVersion = "0.25"
	// MyName is the application name
	MyName = "ripe-atlas"

	// WantBoth is the way to ask for both IPv4 & IPv6.
	WantBoth = "64"

	// Want4 only 4
	Want4 = "4"
	// Want6 only 6
	Want6 = "6"
)

func openlog(fn string) *log.Logger {
	fh, err := os.OpenFile(fn, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		log.Fatalf("error: can not open logfile %s: %v", fn, err)
	}

	mylog := log.New(fh, "", log.LstdFlags)
	verbose("Logfile: %s %#v", fn, mylog)

	return mylog
}

// -4 & -6 are special, if neither is specified, then we turn both as true
// Check a few other things while we are here
func finalcheck(c *cli.Context) error {

	var (
		err   error
		mylog *log.Logger
	)

	// Load main configuration
	cnf, err = LoadConfig("")
	if err != nil {
		verbose("No configuration file found.")
	}

	// Logical
	if fDebug {
		fVerbose = true
		verbose("config: %#v", cnf)
	}

	// Various messages
	if cnf.APIKey != "" {
		verbose("Found API key!")
	} else {
		verbose("No API key!")
	}

	if cnf.DefaultProbe != 0 {
		verbose("Found default probe: %d\n", cnf.DefaultProbe)
	}

	// Allow overwrite of a few parameters
	if fPoolSize != 0 {
		cnf.ProbeSet.PoolSize = fPoolSize
	}
	if fAreaType != "" {
		cnf.ProbeSet.Type = fAreaType
	}
	if fAreaValue != "" {
		cnf.ProbeSet.Value = fAreaValue
	}

	// Check whether we have proxy authentication (from a separate config file)
	auth, err := setupProxyAuth()
	if err != nil {
		verbose("Invalid or no proxy auth credentials")
	}

	// If we want a logfile, open one for the API to log into
	if fLogfile != "" {
		mylog = openlog(fLogfile)
	}

	// Wondering whether to move to the Functional options pattern
	// cf. https://dave.cheney.net/2016/11/13/do-not-fear-first-class-functions
	client, err = atlas.NewClient(atlas.Config{
		APIKey:       cnf.APIKey,
		DefaultProbe: cnf.DefaultProbe,
		IsOneOff:     fIsOneOff,
		PoolSize:     cnf.ProbeSet.PoolSize,
		AreaType:     cnf.ProbeSet.Type,
		AreaValue:    cnf.ProbeSet.Value,
		ProxyAuth:    auth,
		Verbose:      fVerbose,
		Log:          mylog,
	})

	// No need to continue if this fails
	if err != nil {
		log.Fatalf("Error creating the Atlas client: %v", err)
	}

	if fWant4 {
		wantAF = Want4
	}

	if fWant6 {
		wantAF = Want6
	}

	// Both are fine
	if fWant4 && fWant6 {
		wantAF = WantBoth
	}

	// So is neither — common case
	if !fWant4 && !fWant6 {
		wantAF = WantBoth
	}

	return nil
}

// main is the starting point (and everything)
func main() {
	cli.VersionFlag = cli.BoolFlag{Name: "version, V"}

	cli.VersionPrinter = func(c *cli.Context) {
		fmt.Printf("API wrapper: %s Atlas API: %s\n", c.App.Version, atlas.GetVersion())
	}

	app := cli.NewApp()
	app.Name = "atlas"
	app.Usage = "RIPE Atlas CLI interface"
	app.Author = "Ollivier Robert <roberto@keltia.net>"
	app.Version = atlasVersion
	//app.HideVersion = true

	// General flags
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:        "format,f",
			Usage:       "specify output format (NOT IMPLEMENTED)",
			Destination: &fFormat,
		},
		cli.BoolFlag{
			Name:        "debug,D",
			Usage:       "debug mode",
			Destination: &fDebug,
		},
		cli.BoolFlag{
			Name:        "verbose,v",
			Usage:       "verbose mode",
			Destination: &fVerbose,
		},
		cli.StringFlag{
			Name:        "fields,F",
			Usage:       "specify which fields are wanted",
			Destination: &fFieldList,
		},
		cli.StringFlag{
			Name:        "include,I",
			Usage:       "specify whether objects should be expanded",
			Destination: &fInclude,
		},
		cli.StringFlag{
			Name:        "logfile,L",
			Usage:       "specify a log file",
			Destination: &fLogfile,
		},
		cli.BoolFlag{
			Name:        "mine,M",
			Usage:       "limit output to my objects",
			Destination: &fWantMine,
		},
		cli.StringFlag{
			Name:        "opt-fields,O",
			Usage:       "specify which optional fields are wanted",
			Destination: &fOptFields,
		},
		cli.StringFlag{
			Name:        "page-size,P",
			Usage:       "page size for results",
			Destination: &fPageSize,
		},

		cli.StringFlag{
			Name:        "sort,S",
			Usage:       "sort results",
			Destination: &fSortOrder,
		},
		cli.BoolTFlag{
			Name:        "1,is-oneoff",
			Usage:       "one-time measurement",
			Destination: &fIsOneOff,
		},
		cli.BoolFlag{
			Name:        "6, ipv6",
			Usage:       "Only IPv6",
			Destination: &fWant6,
		},
		cli.BoolFlag{
			Name:        "4, ipv4",
			Usage:       "Only IPv4",
			Destination: &fWant4,
		},
		// These are not global parameters but it makes sense to define them only once
		// and not in every cmd_* files.
		cli.IntFlag{
			Name:        "pool-size",
			Usage:       "Number of probes to request",
			Destination: &fPoolSize,
		},
		cli.StringFlag{
			Name:        "area-type",
			Usage:       "Set type for probes (area, country, etc.)",
			Destination: &fAreaType,
		},
		cli.StringFlag{
			Name:        "area-value",
			Usage:       "Value for the probe set (WW, West, etc.)",
			Destination: &fAreaValue,
		},
	}

	// Ensure -4 & -6 are treated properly & initialization is done
	app.Before = finalcheck

	sort.Sort(ByAlphabet(cliCommands))
	app.Commands = cliCommands
	app.Run(os.Args)
}
<commit_msg>Add -N as a short option for --pool-size=N.<commit_after>/*
This package is just a collection of use-case for the various aspects of the RIPE API.
Consider this both as an example on how to use the API and a testing tool for the API wrapper.
*/
package main

import (
	"fmt"
	"github.com/keltia/ripe-atlas"
	"github.com/urfave/cli"
	"log"
	"os"
	"sort"
)

var (
	// CLI specific options
	fDebug   bool
	fLogfile string
	fVerbose bool

	// See flag.go for details

	// Global API options
	fFieldList string
	fFormat    string
	fInclude   string
	fOptFields string
	fPageNum   string
	fPageSize  string
	fSortOrder string
	fWantMine  bool

	// Probe-specific ones
	fAllProbes bool
	fIsAnchor  bool

	// Common measurement ones
	fAllMeasurements bool
	fAsn             string
	fAsnV4           string
	fAsnV6           string
	fCountry         string
	fProtocol        string
	fMeasureType     string
	fWant4           bool
	fWant6           bool

	// Create measurements
	fBillTo    string
	fIsOneOff  bool
	fStartTime string
	fStopTime  string

	// HTTP
	fHTTPMethod  string
	fUserAgent   string
	fHTTPVersion string

	// DNS
	fBitCD         bool
	fDisableDNSSEC bool

	// Traceroute
	fMaxHops    int
	fPacketSize int

	// ProbeSet parameters
	fPoolSize  int
	fAreaType  string
	fAreaValue string

	// Our configuration file
	cnf *Config

	// All possible commands
	cliCommands []cli.Command

	client *atlas.Client

	// Our tiple-valued synthesis of fWant4/fWant6
	wantAF string
)

const (
	atlasVersion = "0.25"
	// MyName is the application name
	MyName = "ripe-atlas"

	// WantBoth is the way to ask for both IPv4 & IPv6.
	WantBoth = "64"

	// Want4 only 4
	Want4 = "4"
	// Want6 only 6
	Want6 = "6"
)

func openlog(fn string) *log.Logger {
	fh, err := os.OpenFile(fn, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		log.Fatalf("error: can not open logfile %s: %v", fn, err)
	}

	mylog := log.New(fh, "", log.LstdFlags)
	verbose("Logfile: %s %#v", fn, mylog)

	return mylog
}

// -4 & -6 are special, if neither is specified, then we turn both as true
// Check a few other things while we are here
func finalcheck(c *cli.Context) error {

	var (
		err   error
		mylog *log.Logger
	)

	// Load main configuration
	cnf, err = LoadConfig("")
	if err != nil {
		verbose("No configuration file found.")
	}

	// Logical
	if fDebug {
		fVerbose = true
		verbose("config: %#v", cnf)
	}

	// Various messages
	if cnf.APIKey != "" {
		verbose("Found API key!")
	} else {
		verbose("No API key!")
	}

	if cnf.DefaultProbe != 0 {
		verbose("Found default probe: %d\n", cnf.DefaultProbe)
	}

	// Allow overwrite of a few parameters
	if fPoolSize != 0 {
		cnf.ProbeSet.PoolSize = fPoolSize
	}
	if fAreaType != "" {
		cnf.ProbeSet.Type = fAreaType
	}
	if fAreaValue != "" {
		cnf.ProbeSet.Value = fAreaValue
	}

	// Check whether we have proxy authentication (from a separate config file)
	auth, err := setupProxyAuth()
	if err != nil {
		verbose("Invalid or no proxy auth credentials")
	}

	// If we want a logfile, open one for the API to log into
	if fLogfile != "" {
		mylog = openlog(fLogfile)
	}

	// Wondering whether to move to the Functional options pattern
	// cf. https://dave.cheney.net/2016/11/13/do-not-fear-first-class-functions
	client, err = atlas.NewClient(atlas.Config{
		APIKey:       cnf.APIKey,
		DefaultProbe: cnf.DefaultProbe,
		IsOneOff:     fIsOneOff,
		PoolSize:     cnf.ProbeSet.PoolSize,
		AreaType:     cnf.ProbeSet.Type,
		AreaValue:    cnf.ProbeSet.Value,
		ProxyAuth:    auth,
		Verbose:      fVerbose,
		Log:          mylog,
	})

	// No need to continue if this fails
	if err != nil {
		log.Fatalf("Error creating the Atlas client: %v", err)
	}

	if fWant4 {
		wantAF = Want4
	}

	if fWant6 {
		wantAF = Want6
	}

	// Both are fine
	if fWant4 && fWant6 {
		wantAF = WantBoth
	}

	// So is neither — common case
	if !fWant4 && !fWant6 {
		wantAF = WantBoth
	}

	return nil
}

// main is the starting point (and everything)
func main() {
	cli.VersionFlag = cli.BoolFlag{Name: "version, V"}

	cli.VersionPrinter = func(c *cli.Context) {
		fmt.Printf("API wrapper: %s Atlas API: %s\n", c.App.Version, atlas.GetVersion())
	}

	app := cli.NewApp()
	app.Name = "atlas"
	app.Usage = "RIPE Atlas CLI interface"
	app.Author = "Ollivier Robert <roberto@keltia.net>"
	app.Version = atlasVersion
	//app.HideVersion = true

	// General flags
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:        "format,f",
			Usage:       "specify output format (NOT IMPLEMENTED)",
			Destination: &fFormat,
		},
		cli.BoolFlag{
			Name:        "debug,D",
			Usage:       "debug mode",
			Destination: &fDebug,
		},
		cli.BoolFlag{
			Name:        "verbose,v",
			Usage:       "verbose mode",
			Destination: &fVerbose,
		},
		cli.StringFlag{
			Name:        "fields,F",
			Usage:       "specify which fields are wanted",
			Destination: &fFieldList,
		},
		cli.StringFlag{
			Name:        "include,I",
			Usage:       "specify whether objects should be expanded",
			Destination: &fInclude,
		},
		cli.StringFlag{
			Name:        "logfile,L",
			Usage:       "specify a log file",
			Destination: &fLogfile,
		},
		cli.BoolFlag{
			Name:        "mine,M",
			Usage:       "limit output to my objects",
			Destination: &fWantMine,
		},
		cli.StringFlag{
			Name:        "opt-fields,O",
			Usage:       "specify which optional fields are wanted",
			Destination: &fOptFields,
		},
		cli.StringFlag{
			Name:        "page-size,P",
			Usage:       "page size for results",
			Destination: &fPageSize,
		},

		cli.StringFlag{
			Name:        "sort,S",
			Usage:       "sort results",
			Destination: &fSortOrder,
		},
		cli.BoolTFlag{
			Name:        "1,is-oneoff",
			Usage:       "one-time measurement",
			Destination: &fIsOneOff,
		},
		cli.BoolFlag{
			Name:        "6, ipv6",
			Usage:       "Only IPv6",
			Destination: &fWant6,
		},
		cli.BoolFlag{
			Name:        "4, ipv4",
			Usage:       "Only IPv4",
			Destination: &fWant4,
		},
		// These are not global parameters but it makes sense to define them only once
		// and not in every cmd_* files.
		cli.IntFlag{
			Name:        "pool-size,N",
			Usage:       "Number of probes to request",
			Destination: &fPoolSize,
		},
		cli.StringFlag{
			Name:        "area-type",
			Usage:       "Set type for probes (area, country, etc.)",
			Destination: &fAreaType,
		},
		cli.StringFlag{
			Name:        "area-value",
			Usage:       "Value for the probe set (WW, West, etc.)",
			Destination: &fAreaValue,
		},
	}

	// Ensure -4 & -6 are treated properly & initialization is done
	app.Before = finalcheck

	sort.Sort(ByAlphabet(cliCommands))
	app.Commands = cliCommands
	app.Run(os.Args)
}
<|endoftext|>


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

package main

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"

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

// builderEnv represents the environment that a Builder will run tests in.
type builderEnv interface {
	// setup sets up the builder environment and returns the directory to run the buildCmd in.
	setup(repo *Repo, workpath, hash string, envv []string) (string, error)
}

// goEnv represents the builderEnv for the main Go repo.
type goEnv struct {
	goos, goarch string
}

func (b *Builder) envv() []string {
	if runtime.GOOS == "windows" {
		return b.envvWindows()
	}

	var e []string
	if *buildTool == "go" {
		e = []string{
			"GOOS=" + b.goos,
			"GOARCH=" + b.goarch,
			"GOROOT_FINAL=/usr/local/go",
		}
		switch b.goos {
		case "android", "nacl":
			// Cross compile.
		default:
			// If we are building, for example, linux/386 on a linux/amd64 machine we want to
			// make sure that the whole build is done as a if this were compiled on a real
			// linux/386 machine. In other words, we want to not do a cross compilation build.
			// To do this we set GOHOSTOS and GOHOSTARCH to override the detection in make.bash.
			//
			// The exception to this rule is when we are doing nacl/android builds. These are by
			// definition always cross compilation, and we have support built into cmd/go to be
			// able to handle this case.
			e = append(e, "GOHOSTOS="+b.goos, "GOHOSTARCH="+b.goarch)
		}
	}

	for _, k := range extraEnv() {
		if s, ok := getenvOk(k); ok {
			e = append(e, k+"="+s)
		}
	}
	return e
}

func (b *Builder) envvWindows() []string {
	var start map[string]string
	if *buildTool == "go" {
		start = map[string]string{
			"GOOS":         b.goos,
			"GOHOSTOS":     b.goos,
			"GOARCH":       b.goarch,
			"GOHOSTARCH":   b.goarch,
			"GOROOT_FINAL": `c:\go`,
			"GOBUILDEXIT":  "1", // exit all.bat with completion status.
		}
	}

	for _, name := range extraEnv() {
		if s, ok := getenvOk(name); ok {
			start[name] = s
		}
	}
	if b.goos == "windows" {
		switch b.goarch {
		case "amd64":
			start["PATH"] = `c:\TDM-GCC-64\bin;` + start["PATH"]
		case "386":
			start["PATH"] = `c:\TDM-GCC-32\bin;` + start["PATH"]
		}
	}
	skip := map[string]bool{
		"GOBIN":   true,
		"GOPATH":  true,
		"GOROOT":  true,
		"INCLUDE": true,
		"LIB":     true,
	}
	var e []string
	for name, v := range start {
		e = append(e, name+"="+v)
		skip[name] = true
	}
	for _, kv := range os.Environ() {
		s := strings.SplitN(kv, "=", 2)
		name := strings.ToUpper(s[0])
		switch {
		case name == "":
			// variables, like "=C:=C:\", just copy them
			e = append(e, kv)
		case !skip[name]:
			e = append(e, kv)
			skip[name] = true
		}
	}
	return e
}

// setup for a goEnv clones the main go repo to workpath/go at the provided hash
// and returns the path workpath/go/src, the location of all go build scripts.
func (env *goEnv) setup(repo *Repo, workpath, hash string, envv []string) (string, error) {
	goworkpath := filepath.Join(workpath, "go")
	if err := repo.Export(goworkpath, hash); err != nil {
		return "", fmt.Errorf("error exporting repository: %s", err)
	}
	return filepath.Join(goworkpath, "src"), nil
}

// gccgoEnv represents the builderEnv for the gccgo compiler.
type gccgoEnv struct{}

// setup for a gccgoEnv clones the gofrontend repo to workpath/go at the hash
// and clones the latest GCC branch to repo.Path/gcc. The gccgo sources are
// replaced with the updated sources in the gofrontend repo and gcc gets
// gets configured and built in workpath/gcc-objdir. The path to
// workpath/gcc-objdir is returned.
func (env *gccgoEnv) setup(repo *Repo, workpath, hash string, envv []string) (string, error) {
	gccpath := filepath.Join(repo.Path, "gcc")

	// get a handle to Git vcs.Cmd for pulling down GCC from the mirror.
	git := vcs.ByCmd("git")

	// only pull down gcc if we don't have a local copy.
	if _, err := os.Stat(gccpath); err != nil {
		if err := timeout(*cmdTimeout, func() error {
			// pull down a working copy of GCC.

			cloneCmd := []string{
				"clone",
				// This is just a guess since there are ~6000 commits to
				// GCC per year. It's likely there will be enough history
				// to cross-reference the Gofrontend commit against GCC.
				// The disadvantage would be if the commit being built is more than
				// a year old; in this case, the user should make a clone that has
				// the full history.
				"--depth", "6000",
				// We only care about the master branch.
				"--branch", "master", "--single-branch",
				*gccPath,
			}

			// Clone Kind			Clone Time(Dry run)	Clone Size
			// ---------------------------------------------------------------
			// Full Clone			10 - 15 min		2.2 GiB
			// Master Branch		2 - 3 min		1.5 GiB
			// Full Clone(shallow)		1 min			900 MiB
			// Master Branch(shallow)	40 sec			900 MiB
			//
			// The shallow clones have the same size, which is expected,
			// but the full shallow clone will only have 6000 commits
			// spread across all branches.  There are ~50 branches.
			return run(exec.Command("git", cloneCmd...), runEnv(envv), allOutput(os.Stdout), runDir(repo.Path))
		}); err != nil {
			return "", err
		}
	}

	if err := git.Download(gccpath); err != nil {
		return "", err
	}

	// get the modified files for this commit.

	var buf bytes.Buffer
	if err := run(exec.Command("hg", "status", "--no-status", "--change", hash),
		allOutput(&buf), runDir(repo.Path), runEnv(envv)); err != nil {
		return "", fmt.Errorf("Failed to find the modified files for %s: %s", hash, err)
	}
	modifiedFiles := strings.Split(buf.String(), "\n")
	var isMirrored bool
	for _, f := range modifiedFiles {
		if strings.HasPrefix(f, "go/") || strings.HasPrefix(f, "libgo/") {
			isMirrored = true
			break
		}
	}

	// use git log to find the corresponding commit to sync to in the gcc mirror.
	// If the files modified in the gofrontend are mirrored to gcc, we expect a
	// commit with a similar description in the gcc mirror. If the files modified are
	// not mirrored, e.g. in support/, we can sync to the most recent gcc commit that
	// occurred before those files were modified to verify gccgo's status at that point.
	logCmd := []string{
		"log",
		"-1",
		"--format=%H",
	}
	var errMsg string
	if isMirrored {
		commitDesc, err := repo.Master.VCS.LogAtRev(repo.Path, hash, "{desc|firstline|escape}")
		if err != nil {
			return "", err
		}

		quotedDesc := regexp.QuoteMeta(string(commitDesc))
		logCmd = append(logCmd, "--grep", quotedDesc, "--regexp-ignore-case", "--extended-regexp")
		errMsg = fmt.Sprintf("Failed to find a commit with a similar description to '%s'", string(commitDesc))
	} else {
		commitDate, err := repo.Master.VCS.LogAtRev(repo.Path, hash, "{date|rfc3339date}")
		if err != nil {
			return "", err
		}

		logCmd = append(logCmd, "--before", string(commitDate))
		errMsg = fmt.Sprintf("Failed to find a commit before '%s'", string(commitDate))
	}

	buf.Reset()
	if err := run(exec.Command("git", logCmd...), runEnv(envv), allOutput(&buf), runDir(gccpath)); err != nil {
		return "", fmt.Errorf("%s: %s", errMsg, err)
	}
	gccRev := buf.String()
	if gccRev == "" {
		return "", fmt.Errorf(errMsg)
	}

	// checkout gccRev
	// TODO(cmang): Fix this to work in parallel mode.
	if err := run(exec.Command("git", "reset", "--hard", strings.TrimSpace(gccRev)), runEnv(envv), runDir(gccpath)); err != nil {
		return "", fmt.Errorf("Failed to checkout commit at revision %s: %s", gccRev, err)
	}

	// make objdir to work in
	gccobjdir := filepath.Join(workpath, "gcc-objdir")
	if err := os.Mkdir(gccobjdir, mkdirPerm); err != nil {
		return "", err
	}

	// configure GCC with substituted gofrontend and libgo
	if err := run(exec.Command(filepath.Join(gccpath, "configure"),
		"--enable-languages=c,c++,go",
		"--disable-bootstrap",
		"--disable-multilib",
	), runEnv(envv), runDir(gccobjdir)); err != nil {
		return "", fmt.Errorf("Failed to configure GCC: %v", err)
	}

	// build gcc
	if err := run(exec.Command("make", *gccOpts), runTimeout(*buildTimeout), runEnv(envv), runDir(gccobjdir)); err != nil {
		return "", fmt.Errorf("Failed to build GCC: %s", err)
	}

	return gccobjdir, nil
}

func getenvOk(k string) (v string, ok bool) {
	v = os.Getenv(k)
	if v != "" {
		return v, true
	}
	keq := k + "="
	for _, kv := range os.Environ() {
		if kv == keq {
			return "", true
		}
	}
	return "", false
}

// extraEnv returns environment variables that need to be copied from
// the gobuilder's environment to the envv of its subprocesses.
func extraEnv() []string {
	extra := []string{
		"GOARM",
		"GO386",
		"GOROOT_BOOTSTRAP", // See https://golang.org/s/go15bootstrap
		"CGO_ENABLED",
		"CC",
		"CC_FOR_TARGET",
		"PATH",
		"TMPDIR",
		"USER",
	}
	if runtime.GOOS == "plan9" {
		extra = append(extra, "objtype", "cputype", "path")
	}
	return extra
}
<commit_msg>cmd/builder: do not set GOROOT_FINAL<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"

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

// builderEnv represents the environment that a Builder will run tests in.
type builderEnv interface {
	// setup sets up the builder environment and returns the directory to run the buildCmd in.
	setup(repo *Repo, workpath, hash string, envv []string) (string, error)
}

// goEnv represents the builderEnv for the main Go repo.
type goEnv struct {
	goos, goarch string
}

func (b *Builder) envv() []string {
	if runtime.GOOS == "windows" {
		return b.envvWindows()
	}

	var e []string
	if *buildTool == "go" {
		e = []string{
			"GOOS=" + b.goos,
			"GOARCH=" + b.goarch,
		}
		switch b.goos {
		case "android", "nacl":
			// Cross compile.
		default:
			// If we are building, for example, linux/386 on a linux/amd64 machine we want to
			// make sure that the whole build is done as a if this were compiled on a real
			// linux/386 machine. In other words, we want to not do a cross compilation build.
			// To do this we set GOHOSTOS and GOHOSTARCH to override the detection in make.bash.
			//
			// The exception to this rule is when we are doing nacl/android builds. These are by
			// definition always cross compilation, and we have support built into cmd/go to be
			// able to handle this case.
			e = append(e, "GOHOSTOS="+b.goos, "GOHOSTARCH="+b.goarch)
		}
	}

	for _, k := range extraEnv() {
		if s, ok := getenvOk(k); ok {
			e = append(e, k+"="+s)
		}
	}
	return e
}

func (b *Builder) envvWindows() []string {
	var start map[string]string
	if *buildTool == "go" {
		start = map[string]string{
			"GOOS":        b.goos,
			"GOHOSTOS":    b.goos,
			"GOARCH":      b.goarch,
			"GOHOSTARCH":  b.goarch,
			"GOBUILDEXIT": "1", // exit all.bat with completion status.
		}
	}

	for _, name := range extraEnv() {
		if s, ok := getenvOk(name); ok {
			start[name] = s
		}
	}
	if b.goos == "windows" {
		switch b.goarch {
		case "amd64":
			start["PATH"] = `c:\TDM-GCC-64\bin;` + start["PATH"]
		case "386":
			start["PATH"] = `c:\TDM-GCC-32\bin;` + start["PATH"]
		}
	}
	skip := map[string]bool{
		"GOBIN":   true,
		"GOPATH":  true,
		"GOROOT":  true,
		"INCLUDE": true,
		"LIB":     true,
	}
	var e []string
	for name, v := range start {
		e = append(e, name+"="+v)
		skip[name] = true
	}
	for _, kv := range os.Environ() {
		s := strings.SplitN(kv, "=", 2)
		name := strings.ToUpper(s[0])
		switch {
		case name == "":
			// variables, like "=C:=C:\", just copy them
			e = append(e, kv)
		case !skip[name]:
			e = append(e, kv)
			skip[name] = true
		}
	}
	return e
}

// setup for a goEnv clones the main go repo to workpath/go at the provided hash
// and returns the path workpath/go/src, the location of all go build scripts.
func (env *goEnv) setup(repo *Repo, workpath, hash string, envv []string) (string, error) {
	goworkpath := filepath.Join(workpath, "go")
	if err := repo.Export(goworkpath, hash); err != nil {
		return "", fmt.Errorf("error exporting repository: %s", err)
	}
	return filepath.Join(goworkpath, "src"), nil
}

// gccgoEnv represents the builderEnv for the gccgo compiler.
type gccgoEnv struct{}

// setup for a gccgoEnv clones the gofrontend repo to workpath/go at the hash
// and clones the latest GCC branch to repo.Path/gcc. The gccgo sources are
// replaced with the updated sources in the gofrontend repo and gcc gets
// gets configured and built in workpath/gcc-objdir. The path to
// workpath/gcc-objdir is returned.
func (env *gccgoEnv) setup(repo *Repo, workpath, hash string, envv []string) (string, error) {
	gccpath := filepath.Join(repo.Path, "gcc")

	// get a handle to Git vcs.Cmd for pulling down GCC from the mirror.
	git := vcs.ByCmd("git")

	// only pull down gcc if we don't have a local copy.
	if _, err := os.Stat(gccpath); err != nil {
		if err := timeout(*cmdTimeout, func() error {
			// pull down a working copy of GCC.

			cloneCmd := []string{
				"clone",
				// This is just a guess since there are ~6000 commits to
				// GCC per year. It's likely there will be enough history
				// to cross-reference the Gofrontend commit against GCC.
				// The disadvantage would be if the commit being built is more than
				// a year old; in this case, the user should make a clone that has
				// the full history.
				"--depth", "6000",
				// We only care about the master branch.
				"--branch", "master", "--single-branch",
				*gccPath,
			}

			// Clone Kind			Clone Time(Dry run)	Clone Size
			// ---------------------------------------------------------------
			// Full Clone			10 - 15 min		2.2 GiB
			// Master Branch		2 - 3 min		1.5 GiB
			// Full Clone(shallow)		1 min			900 MiB
			// Master Branch(shallow)	40 sec			900 MiB
			//
			// The shallow clones have the same size, which is expected,
			// but the full shallow clone will only have 6000 commits
			// spread across all branches.  There are ~50 branches.
			return run(exec.Command("git", cloneCmd...), runEnv(envv), allOutput(os.Stdout), runDir(repo.Path))
		}); err != nil {
			return "", err
		}
	}

	if err := git.Download(gccpath); err != nil {
		return "", err
	}

	// get the modified files for this commit.

	var buf bytes.Buffer
	if err := run(exec.Command("hg", "status", "--no-status", "--change", hash),
		allOutput(&buf), runDir(repo.Path), runEnv(envv)); err != nil {
		return "", fmt.Errorf("Failed to find the modified files for %s: %s", hash, err)
	}
	modifiedFiles := strings.Split(buf.String(), "\n")
	var isMirrored bool
	for _, f := range modifiedFiles {
		if strings.HasPrefix(f, "go/") || strings.HasPrefix(f, "libgo/") {
			isMirrored = true
			break
		}
	}

	// use git log to find the corresponding commit to sync to in the gcc mirror.
	// If the files modified in the gofrontend are mirrored to gcc, we expect a
	// commit with a similar description in the gcc mirror. If the files modified are
	// not mirrored, e.g. in support/, we can sync to the most recent gcc commit that
	// occurred before those files were modified to verify gccgo's status at that point.
	logCmd := []string{
		"log",
		"-1",
		"--format=%H",
	}
	var errMsg string
	if isMirrored {
		commitDesc, err := repo.Master.VCS.LogAtRev(repo.Path, hash, "{desc|firstline|escape}")
		if err != nil {
			return "", err
		}

		quotedDesc := regexp.QuoteMeta(string(commitDesc))
		logCmd = append(logCmd, "--grep", quotedDesc, "--regexp-ignore-case", "--extended-regexp")
		errMsg = fmt.Sprintf("Failed to find a commit with a similar description to '%s'", string(commitDesc))
	} else {
		commitDate, err := repo.Master.VCS.LogAtRev(repo.Path, hash, "{date|rfc3339date}")
		if err != nil {
			return "", err
		}

		logCmd = append(logCmd, "--before", string(commitDate))
		errMsg = fmt.Sprintf("Failed to find a commit before '%s'", string(commitDate))
	}

	buf.Reset()
	if err := run(exec.Command("git", logCmd...), runEnv(envv), allOutput(&buf), runDir(gccpath)); err != nil {
		return "", fmt.Errorf("%s: %s", errMsg, err)
	}
	gccRev := buf.String()
	if gccRev == "" {
		return "", fmt.Errorf(errMsg)
	}

	// checkout gccRev
	// TODO(cmang): Fix this to work in parallel mode.
	if err := run(exec.Command("git", "reset", "--hard", strings.TrimSpace(gccRev)), runEnv(envv), runDir(gccpath)); err != nil {
		return "", fmt.Errorf("Failed to checkout commit at revision %s: %s", gccRev, err)
	}

	// make objdir to work in
	gccobjdir := filepath.Join(workpath, "gcc-objdir")
	if err := os.Mkdir(gccobjdir, mkdirPerm); err != nil {
		return "", err
	}

	// configure GCC with substituted gofrontend and libgo
	if err := run(exec.Command(filepath.Join(gccpath, "configure"),
		"--enable-languages=c,c++,go",
		"--disable-bootstrap",
		"--disable-multilib",
	), runEnv(envv), runDir(gccobjdir)); err != nil {
		return "", fmt.Errorf("Failed to configure GCC: %v", err)
	}

	// build gcc
	if err := run(exec.Command("make", *gccOpts), runTimeout(*buildTimeout), runEnv(envv), runDir(gccobjdir)); err != nil {
		return "", fmt.Errorf("Failed to build GCC: %s", err)
	}

	return gccobjdir, nil
}

func getenvOk(k string) (v string, ok bool) {
	v = os.Getenv(k)
	if v != "" {
		return v, true
	}
	keq := k + "="
	for _, kv := range os.Environ() {
		if kv == keq {
			return "", true
		}
	}
	return "", false
}

// extraEnv returns environment variables that need to be copied from
// the gobuilder's environment to the envv of its subprocesses.
func extraEnv() []string {
	extra := []string{
		"GOARM",
		"GO386",
		"GOROOT_BOOTSTRAP", // See https://golang.org/s/go15bootstrap
		"CGO_ENABLED",
		"CC",
		"CC_FOR_TARGET",
		"PATH",
		"TMPDIR",
		"USER",
	}
	if runtime.GOOS == "plan9" {
		extra = append(extra, "objtype", "cputype", "path")
	}
	return extra
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The Kubernetes Authors.

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

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

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

package main

import (
	"context"
	"flag"
	"fmt"
	"os"

	// TODO: Use k/release/pkg/log instead
	"k8s.io/klog/v2"
	reg "sigs.k8s.io/k8s-container-image-promoter/pkg/dockerregistry"
)

func main() {
	ctx := context.Background()

	if err := run(ctx); err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		// nolint[gomnd]
		os.Exit(1)
	}
}

// nolint[lll]
func run(ctx context.Context) error {
	klog.InitFlags(nil)

	baseDir := ""
	flag.StringVar(
		&baseDir,
		"base_dir",
		baseDir,
		"the manifest directory to look at and modify")
	stagingRepo := ""
	flag.StringVar(
		&stagingRepo,
		"staging_repo",
		stagingRepo,
		"the staging repo which we want to read from")
	filterImage := ""
	flag.StringVar(
		&filterImage,
		"filter_image",
		filterImage,
		"filter staging repo by this image name")
	filterDigest := ""
	flag.StringVar(
		&filterDigest,
		"filter_digest",
		filterDigest,
		"filter images by this digest")
	filterTag := ""
	flag.StringVar(
		&filterTag,
		"filter_tag",
		filterTag,
		"filter images by this tag")

	flag.Parse()

	opt := reg.GrowManifestOptions{}
	if err := opt.Populate(
		baseDir,
		stagingRepo,
		filterImage,
		filterDigest,
		filterTag); err != nil {
		return err
	}

	if err := opt.Validate(); err != nil {
		return err
	}

	return reg.GrowManifest(ctx, opt)
}
<commit_msg>Cobrify cip-mm<commit_after>/*
Copyright 2020 The Kubernetes Authors.

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

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

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

package main

import (
	"context"
	"flag"

	// TODO: Use k/release/pkg/log instead

	"github.com/spf13/cobra"
	"k8s.io/klog/v2"
	reg "sigs.k8s.io/k8s-container-image-promoter/pkg/dockerregistry"
)

var cmd = &cobra.Command{
	Short: "cip-mm → Container Image Promoter - Manifest Modificator",
	Long: `cip-mm → Container Image Promoter - Manifest Modificator

This tool **m**odifies promoter **m**anifests. For now it dumps some filtered
subset of a staging GCR and merges those contents back into a given promoter
manifest.`,
	Use:           "cip-mm",
	SilenceUsage:  true,
	SilenceErrors: true,
	RunE: func(cmd *cobra.Command, args []string) error {
		return run(commandLineOpts)
	},
}

type commandLineOptions struct {
	baseDir      string
	stagingRepo  string
	filterImage  string
	filterDigest string
	filterTag    string
}

var commandLineOpts = &commandLineOptions{}

func init() {
	cmd.PersistentFlags().StringVar(
		&commandLineOpts.baseDir,
		"base_dir",
		"",
		"the manifest directory to look at and modify",
	)
	cmd.PersistentFlags().StringVar(
		&commandLineOpts.stagingRepo,
		"staging_repo",
		"",
		"the staging repo which we want to read from",
	)
	cmd.PersistentFlags().StringVar(
		&commandLineOpts.filterImage,
		"filter_image",
		"",
		"filter staging repo by this image name",
	)
	cmd.PersistentFlags().StringVar(
		&commandLineOpts.filterDigest,
		"filter_digest",
		"",
		"filter images by this digest",
	)
	cmd.PersistentFlags().StringVar(
		&commandLineOpts.filterTag,
		"filter_tag",
		"",
		"filter images by this tag",
	)

	// Add the flags from klog
	flagsCompat := &flag.FlagSet{}
	klog.InitFlags(flagsCompat)
	cmd.PersistentFlags().AddGoFlagSet(flagsCompat)
}

func main() {
	if err := cmd.Execute(); err != nil {
		klog.Fatal(err)
	}
}

// nolint[lll]
func run(cmdOpts *commandLineOptions) error {
	opt := reg.GrowManifestOptions{}
	if err := opt.Populate(
		cmdOpts.baseDir, cmdOpts.stagingRepo,
		cmdOpts.filterImage, cmdOpts.filterDigest,
		cmdOpts.filterTag); err != nil {
		return err
	}

	if err := opt.Validate(); err != nil {
		return err
	}

	ctx := context.Background()
	return reg.GrowManifest(ctx, opt)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/itsankoff/gotcha/client"
	"log"
)

func main() {
	ws := client.NewWebSocketClient()
	c := client.New(ws)
	err := c.Connect("ws://127.0.0.1:9000/websocket")
	log.Println("connected", err)
	userId, err := c.Register("pesho", "123")
	log.Println("registered", err)

	err = c.Authenticate(userId, "123")
	log.Println("authenticated", err)

	if err == nil {
		c.StartInteractiveMode()
	}
}
<commit_msg>Add cmd arguments for client cmd tool<commit_after>package main

import (
	"flag"
	"github.com/itsankoff/gotcha/client"
	"log"
)

func main() {
	var host string
	flag.StringVar(&host, "host",
		"ws://0.0.0.0:9000/websocket", "remote server host")

	flag.Parse()

	ws := client.NewWebSocketClient()
	c := client.New(ws)
	err := c.Connect(host)
	log.Println("connected", err)
	userId, err := c.Register("pesho", "123")
	log.Println("registered", err)

	err = c.Authenticate(userId, "123")
	log.Println("authenticated", err)

	if err == nil {
		c.StartInteractiveMode()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net/url"
	"os"
	"runtime/pprof"
	"time"

	"github.com/prometheus/common/config"
	"github.com/prometheus/common/version"
	"gopkg.in/alecthomas/kingpin.v2"

	_ "github.com/grafana/loki/pkg/build"
	"github.com/grafana/loki/pkg/logcli/client"
	"github.com/grafana/loki/pkg/logcli/labelquery"
	"github.com/grafana/loki/pkg/logcli/output"
	"github.com/grafana/loki/pkg/logcli/query"
	"github.com/grafana/loki/pkg/logcli/seriesquery"
)

var (
	app        = kingpin.New("logcli", "A command-line for loki.").Version(version.Print("logcli"))
	quiet      = app.Flag("quiet", "Suppress query metadata").Default("false").Short('q').Bool()
	statistics = app.Flag("stats", "Show query statistics").Default("false").Bool()
	outputMode = app.Flag("output", "Specify output mode [default, raw, jsonl]. raw suppresses log labels and timestamp.").Default("default").Short('o').Enum("default", "raw", "jsonl")
	timezone   = app.Flag("timezone", "Specify the timezone to use when formatting output timestamps [Local, UTC]").Default("Local").Short('z').Enum("Local", "UTC")
	cpuProfile = app.Flag("cpuprofile", "Specify the location for writing a CPU profile.").Default("").String()
	memProfile = app.Flag("memprofile", "Specify the location for writing a memory profile.").Default("").String()

	queryClient = newQueryClient(app)

	queryCmd = app.Command("query", `Run a LogQL query.

The "query" command is useful for querying for logs. Logs can be
returned in a few output modes:

	raw: log line
	default: log timestamp + log labels + log line
	jsonl: JSON response from Loki API of log line

The output of the log can be specified with the "-o" flag, for
example, "-o raw" for the raw output format.

The "query" command will output extra information about the query
and its results, such as the API URL, set of common labels, and set
of excluded labels. This extra information can be suppressed with the
--quiet flag.

By default we look over the last hour of data; use --since to modify
or provide specific start and end times with --start and --end.
The output is limited to 30 entries by default; use --limit to increase.

While "query" does support metrics queries, its output contains multiple
data points between the start and end query time. This output is used to
build graphs, similar to what is seen in the Grafana Explore graph view.
If you are querying metrics and just want the most recent data point
(like what is seen in the Grafana Explore table view), then you should use
the "instant-query" command instead.`)
	rangeQuery = newQuery(false, queryCmd)
	tail       = queryCmd.Flag("tail", "Tail the logs").Short('t').Default("false").Bool()
	delayFor   = queryCmd.Flag("delay-for", "Delay in tailing by number of seconds to accumulate logs for re-ordering").Default("0").Int()

	instantQueryCmd = app.Command("instant-query", `Run an instant LogQL query.

The "instant-query" command is useful for evaluating a metric query for
a single point in time. This is equivalent to the Grafana Explore table
view; if you want a metrics query that is used to build a Grafana graph,
you should use the "query" command instead.

This command does not produce useful output when querying for log lines;
you should always use the "query" command when you are running log queries.

For more information about log queries and metric queries, refer to the
LogQL documentation:

https://github.com/grafana/loki/blob/master/docs/logql.md`)
	instantQuery = newQuery(true, instantQueryCmd)

	labelsCmd   = app.Command("labels", "Find values for a given label.")
	labelsQuery = newLabelQuery(labelsCmd)

	seriesCmd = app.Command("series", `Run series query.

The "series" command will take the provided label matcher
and return all the log streams found in the time window.

It is possible to send an empty label matcher '{}' to return all streams.

Use the --analyze-labels flag to get a summary of the labels found in all streams.
This is helpful to find high cardinality labels.
`)
	seriesQuery = newSeriesQuery(seriesCmd)
)

func main() {
	log.SetOutput(os.Stderr)

	cmd := kingpin.MustParse(app.Parse(os.Args[1:]))

	if cpuProfile != nil && *cpuProfile != "" {
		cpuFile, err := os.Create(*cpuProfile)
		if err != nil {
			log.Fatal("could not create CPU profile: ", err)
		}
		defer cpuFile.Close()
		if err := pprof.StartCPUProfile(cpuFile); err != nil {
			log.Fatal("could not start CPU profile: ", err)
		}
		defer pprof.StopCPUProfile()
	}

	if memProfile != nil && *memProfile != "" {
		memFile, err := os.Create(*memProfile)
		if err != nil {
			log.Fatal("could not create memory profile: ", err)
		}
		defer memFile.Close()
		defer func() {
			if err := pprof.WriteHeapProfile(memFile); err != nil {
				log.Fatal("could not write memory profile: ", err)
			}
		}()
	}

	switch cmd {
	case queryCmd.FullCommand():
		location, err := time.LoadLocation(*timezone)
		if err != nil {
			log.Fatalf("Unable to load timezone '%s': %s", *timezone, err)
		}

		outputOptions := &output.LogOutputOptions{
			Timezone:      location,
			NoLabels:      rangeQuery.NoLabels,
			ColoredOutput: rangeQuery.ColoredOutput,
		}

		out, err := output.NewLogOutput(os.Stdout, *outputMode, outputOptions)
		if err != nil {
			log.Fatalf("Unable to create log output: %s", err)
		}

		if *tail {
			rangeQuery.TailQuery(*delayFor, queryClient, out)
		} else {
			rangeQuery.DoQuery(queryClient, out, *statistics)
		}
	case instantQueryCmd.FullCommand():
		location, err := time.LoadLocation(*timezone)
		if err != nil {
			log.Fatalf("Unable to load timezone '%s': %s", *timezone, err)
		}

		outputOptions := &output.LogOutputOptions{
			Timezone:      location,
			NoLabels:      instantQuery.NoLabels,
			ColoredOutput: instantQuery.ColoredOutput,
		}

		out, err := output.NewLogOutput(os.Stdout, *outputMode, outputOptions)
		if err != nil {
			log.Fatalf("Unable to create log output: %s", err)
		}

		instantQuery.DoQuery(queryClient, out, *statistics)
	case labelsCmd.FullCommand():
		labelsQuery.DoLabels(queryClient)
	case seriesCmd.FullCommand():
		seriesQuery.DoSeries(queryClient)
	}
}

func newQueryClient(app *kingpin.Application) client.Client {

	client := &client.DefaultClient{
		TLSConfig: config.TLSConfig{},
	}

	// extract host
	addressAction := func(c *kingpin.ParseContext) error {
		u, err := url.Parse(client.Address)
		if err != nil {
			return err
		}
		client.TLSConfig.ServerName = u.Host
		return nil
	}

	app.Flag("addr", "Server address. Can also be set using LOKI_ADDR env var.").Default("http://localhost:3100").Envar("LOKI_ADDR").Action(addressAction).StringVar(&client.Address)
	app.Flag("username", "Username for HTTP basic auth. Can also be set using LOKI_USERNAME env var.").Default("").Envar("LOKI_USERNAME").StringVar(&client.Username)
	app.Flag("password", "Password for HTTP basic auth. Can also be set using LOKI_PASSWORD env var.").Default("").Envar("LOKI_PASSWORD").StringVar(&client.Password)
	app.Flag("ca-cert", "Path to the server Certificate Authority. Can also be set using LOKI_CA_CERT_PATH env var.").Default("").Envar("LOKI_CA_CERT_PATH").StringVar(&client.TLSConfig.CAFile)
	app.Flag("tls-skip-verify", "Server certificate TLS skip verify.").Default("false").Envar("LOKI_TLS_SKIP_VERIFY").BoolVar(&client.TLSConfig.InsecureSkipVerify)
	app.Flag("cert", "Path to the client certificate. Can also be set using LOKI_CLIENT_CERT_PATH env var.").Default("").Envar("LOKI_CLIENT_CERT_PATH").StringVar(&client.TLSConfig.CertFile)
	app.Flag("key", "Path to the client certificate key. Can also be set using LOKI_CLIENT_KEY_PATH env var.").Default("").Envar("LOKI_CLIENT_KEY_PATH").StringVar(&client.TLSConfig.KeyFile)
	app.Flag("org-id", "adds X-Scope-OrgID to API requests for representing tenant ID. Useful for requesting tenant data when bypassing an auth gateway.").Default("").Envar("LOKI_ORG_ID").StringVar(&client.OrgID)

	return client
}

func newLabelQuery(cmd *kingpin.CmdClause) *labelquery.LabelQuery {
	var labelName, from, to string
	var since time.Duration

	q := &labelquery.LabelQuery{}

	// executed after all command flags are parsed
	cmd.Action(func(c *kingpin.ParseContext) error {

		defaultEnd := time.Now()
		defaultStart := defaultEnd.Add(-since)

		q.Start = mustParse(from, defaultStart)
		q.End = mustParse(to, defaultEnd)
		q.LabelName = labelName
		q.Quiet = *quiet
		return nil
	})

	cmd.Arg("label", "The name of the label.").Default("").StringVar(&labelName)
	cmd.Flag("since", "Lookback window.").Default("1h").DurationVar(&since)
	cmd.Flag("from", "Start looking for labels at this absolute time (inclusive)").StringVar(&from)
	cmd.Flag("to", "Stop looking for labels at this absolute time (exclusive)").StringVar(&to)

	return q
}

func newSeriesQuery(cmd *kingpin.CmdClause) *seriesquery.SeriesQuery {
	// calculate series range from cli params
	var from, to string
	var since time.Duration

	q := &seriesquery.SeriesQuery{}

	// executed after all command flags are parsed
	cmd.Action(func(c *kingpin.ParseContext) error {

		defaultEnd := time.Now()
		defaultStart := defaultEnd.Add(-since)

		q.Start = mustParse(from, defaultStart)
		q.End = mustParse(to, defaultEnd)
		q.Quiet = *quiet
		return nil
	})

	cmd.Arg("matcher", "eg '{foo=\"bar\",baz=~\".*blip\"}'").Required().StringVar(&q.Matcher)
	cmd.Flag("since", "Lookback window.").Default("1h").DurationVar(&since)
	cmd.Flag("from", "Start looking for logs at this absolute time (inclusive)").StringVar(&from)
	cmd.Flag("to", "Stop looking for logs at this absolute time (exclusive)").StringVar(&to)
	cmd.Flag("analyze-labels", "Printout a summary of labels including count of label value combinations, useful for debugging high cardinality series").BoolVar(&q.AnalyzeLabels)

	return q
}

func newQuery(instant bool, cmd *kingpin.CmdClause) *query.Query {
	// calculate query range from cli params
	var now, from, to string
	var since time.Duration

	q := &query.Query{}

	// executed after all command flags are parsed
	cmd.Action(func(c *kingpin.ParseContext) error {

		if instant {
			q.SetInstant(mustParse(now, time.Now()))
		} else {
			defaultEnd := time.Now()
			defaultStart := defaultEnd.Add(-since)

			q.Start = mustParse(from, defaultStart)
			q.End = mustParse(to, defaultEnd)
		}
		q.Quiet = *quiet
		return nil
	})

	cmd.Flag("limit", "Limit on number of entries to print.").Default("30").IntVar(&q.Limit)
	if instant {
		cmd.Arg("query", "eg 'rate({foo=\"bar\"} |~ \".*error.*\" [5m])'").Required().StringVar(&q.QueryString)
		cmd.Flag("now", "Time at which to execute the instant query.").StringVar(&now)
	} else {
		cmd.Arg("query", "eg '{foo=\"bar\",baz=~\".*blip\"} |~ \".*error.*\"'").Required().StringVar(&q.QueryString)
		cmd.Flag("since", "Lookback window.").Default("1h").DurationVar(&since)
		cmd.Flag("from", "Start looking for logs at this absolute time (inclusive)").StringVar(&from)
		cmd.Flag("to", "Stop looking for logs at this absolute time (exclusive)").StringVar(&to)
		cmd.Flag("step", "Query resolution step width, for metric queries. Evaluate the query at the specified step over the time range.").DurationVar(&q.Step)
		cmd.Flag("interval", "Query interval, for log queries. Return entries at the specified interval, ignoring those between. **This parameter is experimental, please see Issue 1779**").DurationVar(&q.Interval)
		cmd.Flag("batch", "Query batch size to use until 'limit' is reached").Default("1000").IntVar(&q.BatchSize)
	}

	cmd.Flag("forward", "Scan forwards through logs.").Default("false").BoolVar(&q.Forward)
	cmd.Flag("no-labels", "Do not print any labels").Default("false").BoolVar(&q.NoLabels)
	cmd.Flag("exclude-label", "Exclude labels given the provided key during output.").StringsVar(&q.IgnoreLabelsKey)
	cmd.Flag("include-label", "Include labels given the provided key during output.").StringsVar(&q.ShowLabelsKey)
	cmd.Flag("labels-length", "Set a fixed padding to labels").Default("0").IntVar(&q.FixedLabelsLen)
	cmd.Flag("store-config", "Execute the current query using a configured storage from a given Loki configuration file.").Default("").StringVar(&q.LocalConfig)
	cmd.Flag("colored-output", "Show output with colored labels").Default("false").BoolVar(&q.ColoredOutput)

	return q
}

func mustParse(t string, defaultTime time.Time) time.Time {
	if t == "" {
		return defaultTime
	}

	ret, err := time.Parse(time.RFC3339Nano, t)

	if err != nil {
		log.Fatalf("Unable to parse time %v", err)
	}

	return ret
}
<commit_msg>Fix logcli logql document url (#2968)<commit_after>package main

import (
	"log"
	"net/url"
	"os"
	"runtime/pprof"
	"time"

	"github.com/prometheus/common/config"
	"github.com/prometheus/common/version"
	"gopkg.in/alecthomas/kingpin.v2"

	_ "github.com/grafana/loki/pkg/build"
	"github.com/grafana/loki/pkg/logcli/client"
	"github.com/grafana/loki/pkg/logcli/labelquery"
	"github.com/grafana/loki/pkg/logcli/output"
	"github.com/grafana/loki/pkg/logcli/query"
	"github.com/grafana/loki/pkg/logcli/seriesquery"
)

var (
	app        = kingpin.New("logcli", "A command-line for loki.").Version(version.Print("logcli"))
	quiet      = app.Flag("quiet", "Suppress query metadata").Default("false").Short('q').Bool()
	statistics = app.Flag("stats", "Show query statistics").Default("false").Bool()
	outputMode = app.Flag("output", "Specify output mode [default, raw, jsonl]. raw suppresses log labels and timestamp.").Default("default").Short('o').Enum("default", "raw", "jsonl")
	timezone   = app.Flag("timezone", "Specify the timezone to use when formatting output timestamps [Local, UTC]").Default("Local").Short('z').Enum("Local", "UTC")
	cpuProfile = app.Flag("cpuprofile", "Specify the location for writing a CPU profile.").Default("").String()
	memProfile = app.Flag("memprofile", "Specify the location for writing a memory profile.").Default("").String()

	queryClient = newQueryClient(app)

	queryCmd = app.Command("query", `Run a LogQL query.

The "query" command is useful for querying for logs. Logs can be
returned in a few output modes:

	raw: log line
	default: log timestamp + log labels + log line
	jsonl: JSON response from Loki API of log line

The output of the log can be specified with the "-o" flag, for
example, "-o raw" for the raw output format.

The "query" command will output extra information about the query
and its results, such as the API URL, set of common labels, and set
of excluded labels. This extra information can be suppressed with the
--quiet flag.

By default we look over the last hour of data; use --since to modify
or provide specific start and end times with --start and --end.
The output is limited to 30 entries by default; use --limit to increase.

While "query" does support metrics queries, its output contains multiple
data points between the start and end query time. This output is used to
build graphs, similar to what is seen in the Grafana Explore graph view.
If you are querying metrics and just want the most recent data point
(like what is seen in the Grafana Explore table view), then you should use
the "instant-query" command instead.`)
	rangeQuery = newQuery(false, queryCmd)
	tail       = queryCmd.Flag("tail", "Tail the logs").Short('t').Default("false").Bool()
	delayFor   = queryCmd.Flag("delay-for", "Delay in tailing by number of seconds to accumulate logs for re-ordering").Default("0").Int()

	instantQueryCmd = app.Command("instant-query", `Run an instant LogQL query.

The "instant-query" command is useful for evaluating a metric query for
a single point in time. This is equivalent to the Grafana Explore table
view; if you want a metrics query that is used to build a Grafana graph,
you should use the "query" command instead.

This command does not produce useful output when querying for log lines;
you should always use the "query" command when you are running log queries.

For more information about log queries and metric queries, refer to the
LogQL documentation:

https://grafana.com/docs/loki/latest/logql/`)
	instantQuery = newQuery(true, instantQueryCmd)

	labelsCmd   = app.Command("labels", "Find values for a given label.")
	labelsQuery = newLabelQuery(labelsCmd)

	seriesCmd = app.Command("series", `Run series query.

The "series" command will take the provided label matcher
and return all the log streams found in the time window.

It is possible to send an empty label matcher '{}' to return all streams.

Use the --analyze-labels flag to get a summary of the labels found in all streams.
This is helpful to find high cardinality labels.
`)
	seriesQuery = newSeriesQuery(seriesCmd)
)

func main() {
	log.SetOutput(os.Stderr)

	cmd := kingpin.MustParse(app.Parse(os.Args[1:]))

	if cpuProfile != nil && *cpuProfile != "" {
		cpuFile, err := os.Create(*cpuProfile)
		if err != nil {
			log.Fatal("could not create CPU profile: ", err)
		}
		defer cpuFile.Close()
		if err := pprof.StartCPUProfile(cpuFile); err != nil {
			log.Fatal("could not start CPU profile: ", err)
		}
		defer pprof.StopCPUProfile()
	}

	if memProfile != nil && *memProfile != "" {
		memFile, err := os.Create(*memProfile)
		if err != nil {
			log.Fatal("could not create memory profile: ", err)
		}
		defer memFile.Close()
		defer func() {
			if err := pprof.WriteHeapProfile(memFile); err != nil {
				log.Fatal("could not write memory profile: ", err)
			}
		}()
	}

	switch cmd {
	case queryCmd.FullCommand():
		location, err := time.LoadLocation(*timezone)
		if err != nil {
			log.Fatalf("Unable to load timezone '%s': %s", *timezone, err)
		}

		outputOptions := &output.LogOutputOptions{
			Timezone:      location,
			NoLabels:      rangeQuery.NoLabels,
			ColoredOutput: rangeQuery.ColoredOutput,
		}

		out, err := output.NewLogOutput(os.Stdout, *outputMode, outputOptions)
		if err != nil {
			log.Fatalf("Unable to create log output: %s", err)
		}

		if *tail {
			rangeQuery.TailQuery(*delayFor, queryClient, out)
		} else {
			rangeQuery.DoQuery(queryClient, out, *statistics)
		}
	case instantQueryCmd.FullCommand():
		location, err := time.LoadLocation(*timezone)
		if err != nil {
			log.Fatalf("Unable to load timezone '%s': %s", *timezone, err)
		}

		outputOptions := &output.LogOutputOptions{
			Timezone:      location,
			NoLabels:      instantQuery.NoLabels,
			ColoredOutput: instantQuery.ColoredOutput,
		}

		out, err := output.NewLogOutput(os.Stdout, *outputMode, outputOptions)
		if err != nil {
			log.Fatalf("Unable to create log output: %s", err)
		}

		instantQuery.DoQuery(queryClient, out, *statistics)
	case labelsCmd.FullCommand():
		labelsQuery.DoLabels(queryClient)
	case seriesCmd.FullCommand():
		seriesQuery.DoSeries(queryClient)
	}
}

func newQueryClient(app *kingpin.Application) client.Client {

	client := &client.DefaultClient{
		TLSConfig: config.TLSConfig{},
	}

	// extract host
	addressAction := func(c *kingpin.ParseContext) error {
		u, err := url.Parse(client.Address)
		if err != nil {
			return err
		}
		client.TLSConfig.ServerName = u.Host
		return nil
	}

	app.Flag("addr", "Server address. Can also be set using LOKI_ADDR env var.").Default("http://localhost:3100").Envar("LOKI_ADDR").Action(addressAction).StringVar(&client.Address)
	app.Flag("username", "Username for HTTP basic auth. Can also be set using LOKI_USERNAME env var.").Default("").Envar("LOKI_USERNAME").StringVar(&client.Username)
	app.Flag("password", "Password for HTTP basic auth. Can also be set using LOKI_PASSWORD env var.").Default("").Envar("LOKI_PASSWORD").StringVar(&client.Password)
	app.Flag("ca-cert", "Path to the server Certificate Authority. Can also be set using LOKI_CA_CERT_PATH env var.").Default("").Envar("LOKI_CA_CERT_PATH").StringVar(&client.TLSConfig.CAFile)
	app.Flag("tls-skip-verify", "Server certificate TLS skip verify.").Default("false").Envar("LOKI_TLS_SKIP_VERIFY").BoolVar(&client.TLSConfig.InsecureSkipVerify)
	app.Flag("cert", "Path to the client certificate. Can also be set using LOKI_CLIENT_CERT_PATH env var.").Default("").Envar("LOKI_CLIENT_CERT_PATH").StringVar(&client.TLSConfig.CertFile)
	app.Flag("key", "Path to the client certificate key. Can also be set using LOKI_CLIENT_KEY_PATH env var.").Default("").Envar("LOKI_CLIENT_KEY_PATH").StringVar(&client.TLSConfig.KeyFile)
	app.Flag("org-id", "adds X-Scope-OrgID to API requests for representing tenant ID. Useful for requesting tenant data when bypassing an auth gateway.").Default("").Envar("LOKI_ORG_ID").StringVar(&client.OrgID)

	return client
}

func newLabelQuery(cmd *kingpin.CmdClause) *labelquery.LabelQuery {
	var labelName, from, to string
	var since time.Duration

	q := &labelquery.LabelQuery{}

	// executed after all command flags are parsed
	cmd.Action(func(c *kingpin.ParseContext) error {

		defaultEnd := time.Now()
		defaultStart := defaultEnd.Add(-since)

		q.Start = mustParse(from, defaultStart)
		q.End = mustParse(to, defaultEnd)
		q.LabelName = labelName
		q.Quiet = *quiet
		return nil
	})

	cmd.Arg("label", "The name of the label.").Default("").StringVar(&labelName)
	cmd.Flag("since", "Lookback window.").Default("1h").DurationVar(&since)
	cmd.Flag("from", "Start looking for labels at this absolute time (inclusive)").StringVar(&from)
	cmd.Flag("to", "Stop looking for labels at this absolute time (exclusive)").StringVar(&to)

	return q
}

func newSeriesQuery(cmd *kingpin.CmdClause) *seriesquery.SeriesQuery {
	// calculate series range from cli params
	var from, to string
	var since time.Duration

	q := &seriesquery.SeriesQuery{}

	// executed after all command flags are parsed
	cmd.Action(func(c *kingpin.ParseContext) error {

		defaultEnd := time.Now()
		defaultStart := defaultEnd.Add(-since)

		q.Start = mustParse(from, defaultStart)
		q.End = mustParse(to, defaultEnd)
		q.Quiet = *quiet
		return nil
	})

	cmd.Arg("matcher", "eg '{foo=\"bar\",baz=~\".*blip\"}'").Required().StringVar(&q.Matcher)
	cmd.Flag("since", "Lookback window.").Default("1h").DurationVar(&since)
	cmd.Flag("from", "Start looking for logs at this absolute time (inclusive)").StringVar(&from)
	cmd.Flag("to", "Stop looking for logs at this absolute time (exclusive)").StringVar(&to)
	cmd.Flag("analyze-labels", "Printout a summary of labels including count of label value combinations, useful for debugging high cardinality series").BoolVar(&q.AnalyzeLabels)

	return q
}

func newQuery(instant bool, cmd *kingpin.CmdClause) *query.Query {
	// calculate query range from cli params
	var now, from, to string
	var since time.Duration

	q := &query.Query{}

	// executed after all command flags are parsed
	cmd.Action(func(c *kingpin.ParseContext) error {

		if instant {
			q.SetInstant(mustParse(now, time.Now()))
		} else {
			defaultEnd := time.Now()
			defaultStart := defaultEnd.Add(-since)

			q.Start = mustParse(from, defaultStart)
			q.End = mustParse(to, defaultEnd)
		}
		q.Quiet = *quiet
		return nil
	})

	cmd.Flag("limit", "Limit on number of entries to print.").Default("30").IntVar(&q.Limit)
	if instant {
		cmd.Arg("query", "eg 'rate({foo=\"bar\"} |~ \".*error.*\" [5m])'").Required().StringVar(&q.QueryString)
		cmd.Flag("now", "Time at which to execute the instant query.").StringVar(&now)
	} else {
		cmd.Arg("query", "eg '{foo=\"bar\",baz=~\".*blip\"} |~ \".*error.*\"'").Required().StringVar(&q.QueryString)
		cmd.Flag("since", "Lookback window.").Default("1h").DurationVar(&since)
		cmd.Flag("from", "Start looking for logs at this absolute time (inclusive)").StringVar(&from)
		cmd.Flag("to", "Stop looking for logs at this absolute time (exclusive)").StringVar(&to)
		cmd.Flag("step", "Query resolution step width, for metric queries. Evaluate the query at the specified step over the time range.").DurationVar(&q.Step)
		cmd.Flag("interval", "Query interval, for log queries. Return entries at the specified interval, ignoring those between. **This parameter is experimental, please see Issue 1779**").DurationVar(&q.Interval)
		cmd.Flag("batch", "Query batch size to use until 'limit' is reached").Default("1000").IntVar(&q.BatchSize)
	}

	cmd.Flag("forward", "Scan forwards through logs.").Default("false").BoolVar(&q.Forward)
	cmd.Flag("no-labels", "Do not print any labels").Default("false").BoolVar(&q.NoLabels)
	cmd.Flag("exclude-label", "Exclude labels given the provided key during output.").StringsVar(&q.IgnoreLabelsKey)
	cmd.Flag("include-label", "Include labels given the provided key during output.").StringsVar(&q.ShowLabelsKey)
	cmd.Flag("labels-length", "Set a fixed padding to labels").Default("0").IntVar(&q.FixedLabelsLen)
	cmd.Flag("store-config", "Execute the current query using a configured storage from a given Loki configuration file.").Default("").StringVar(&q.LocalConfig)
	cmd.Flag("colored-output", "Show output with colored labels").Default("false").BoolVar(&q.ColoredOutput)

	return q
}

func mustParse(t string, defaultTime time.Time) time.Time {
	if t == "" {
		return defaultTime
	}

	ret, err := time.Parse(time.RFC3339Nano, t)

	if err != nil {
		log.Fatalf("Unable to parse time %v", err)
	}

	return ret
}
<|endoftext|>


<commit_before>package main

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

	"github.com/Sirupsen/logrus"
	"github.com/docker/notary/passphrase"
	"github.com/docker/notary/version"
	homedir "github.com/mitchellh/go-homedir"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

const (
	configDir        = ".notary/"
	defaultServerURL = "https://notary-server:4443"
)

type usageTemplate struct {
	Use   string
	Short string
	Long  string
}

type cobraRunE func(cmd *cobra.Command, args []string) error

func (u usageTemplate) ToCommand(run cobraRunE) *cobra.Command {
	c := cobra.Command{
		Use:   u.Use,
		Short: u.Short,
		Long:  u.Long,
	}
	if run != nil {
		// newer versions of cobra support a run function that returns an error,
		// but in the meantime, this should help ease the transition
		c.RunE = run
	}
	return &c
}

func pathRelativeToCwd(path string) string {
	if path == "" || filepath.IsAbs(path) {
		return path
	}
	cwd, err := os.Getwd()
	if err != nil {
		return filepath.Clean(path)
	}
	return filepath.Clean(filepath.Join(cwd, path))
}

type notaryCommander struct {
	// this needs to be set
	getRetriever func() passphrase.Retriever

	// these are for command line parsing - no need to set
	debug             bool
	verbose           bool
	trustDir          string
	configFile        string
	remoteTrustServer string

	tlsCAFile   string
	tlsCertFile string
	tlsKeyFile  string
}

func (n *notaryCommander) parseConfig() (*viper.Viper, error) {
	n.setVerbosityLevel()

	// Get home directory for current user
	homeDir, err := homedir.Dir()
	if err != nil {
		return nil, fmt.Errorf("cannot get current user home directory: %v", err)
	}
	if homeDir == "" {
		return nil, fmt.Errorf("cannot get current user home directory")
	}

	config := viper.New()

	// By default our trust directory (where keys are stored) is in ~/.notary/
	defaultTrustDir := filepath.Join(homeDir, filepath.Dir(configDir))

	// If there was a commandline configFile set, we parse that.
	// If there wasn't we attempt to find it on the default location ~/.notary/config.json
	if n.configFile != "" {
		config.SetConfigFile(n.configFile)
	} else {
		config.SetConfigFile(filepath.Join(defaultTrustDir, "config.json"))
	}

	// Setup the configuration details into viper
	config.SetDefault("trust_dir", defaultTrustDir)
	config.SetDefault("remote_server", map[string]string{"url": defaultServerURL})

	// Find and read the config file
	if err := config.ReadInConfig(); err != nil {
		logrus.Debugf("Configuration file not found, using defaults")

		// If we were passed in a configFile via command linen flags, bail if it doesn't exist,
		// otherwise ignore it: we can use the defaults
		if n.configFile != "" || !os.IsNotExist(err) {
			return nil, fmt.Errorf("error opening config file: %v", err)
		}
	}

	// At this point we either have the default value or the one set by the config.
	// Either way, some command-line flags have precedence and overwrites the value
	if n.trustDir != "" {
		config.Set("trust_dir", pathRelativeToCwd(n.trustDir))
	}
	if n.tlsCAFile != "" {
		config.Set("remote_server.root_ca", pathRelativeToCwd(n.tlsCAFile))
	}
	if n.tlsCertFile != "" {
		config.Set("remote_server.tls_client_cert", pathRelativeToCwd(n.tlsCertFile))
	}
	if n.tlsKeyFile != "" {
		config.Set("remote_server.tls_client_key", pathRelativeToCwd(n.tlsKeyFile))
	}
	if n.remoteTrustServer != "" {
		config.Set("remote_server.url", n.remoteTrustServer)
	}

	// Expands all the possible ~/ that have been given, either through -d or config
	// If there is no error, use it, if not, just attempt to use whatever the user gave us
	expandedTrustDir, err := homedir.Expand(config.GetString("trust_dir"))
	if err == nil {
		config.Set("trust_dir", expandedTrustDir)
	}
	logrus.Debugf("Using the following trust directory: %s", config.GetString("trust_dir"))

	return config, nil
}

func (n *notaryCommander) GetCommand() *cobra.Command {
	notaryCmd := cobra.Command{
		Use:           "notary",
		Short:         "Notary allows the creation of trusted collections.",
		Long:          "Notary allows the creation and management of collections of signed targets, allowing the signing and validation of arbitrary content.",
		SilenceUsage:  true, // we don't want to print out usage for EVERY error
		SilenceErrors: true, // we do our own error reporting with fatalf
		Run:           func(cmd *cobra.Command, args []string) { cmd.Usage() },
	}
	notaryCmd.SetOutput(os.Stdout)
	notaryCmd.AddCommand(&cobra.Command{
		Use:   "version",
		Short: "Print the version number of notary",
		Long:  `print the version number of notary`,
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Printf("notary\n Version:    %s\n Git commit: %s\n", version.NotaryVersion, version.GitCommit)
		},
	})

	notaryCmd.PersistentFlags().StringVarP(
		&n.trustDir, "trustDir", "d", "", "Directory where the trust data is persisted to")
	notaryCmd.PersistentFlags().StringVarP(
		&n.configFile, "configFile", "c", "", "Path to the configuration file to use")
	notaryCmd.PersistentFlags().BoolVarP(&n.verbose, "verbose", "v", false, "Verbose output")
	notaryCmd.PersistentFlags().BoolVarP(&n.debug, "debug", "D", false, "Debug output")
	notaryCmd.PersistentFlags().StringVarP(&n.remoteTrustServer, "server", "s", "", "Remote trust server location")
	notaryCmd.PersistentFlags().StringVar(&n.tlsCAFile, "tlscacert", "", "Trust certs signed only by this CA")
	notaryCmd.PersistentFlags().StringVar(&n.tlsCertFile, "tlscert", "", "Path to TLS certificate file")
	notaryCmd.PersistentFlags().StringVar(&n.tlsKeyFile, "tlskey", "", "Path to TLS key file")

	cmdKeyGenerator := &keyCommander{
		configGetter: n.parseConfig,
		getRetriever: n.getRetriever,
	}

	cmdDelegationGenerator := &delegationCommander{
		configGetter: n.parseConfig,
		retriever:    n.getRetriever(),
	}

	cmdCertGenerator := &certCommander{
		configGetter: n.parseConfig,
		retriever:    n.getRetriever(),
	}

	cmdTufGenerator := &tufCommander{
		configGetter: n.parseConfig,
		retriever:    n.getRetriever(),
	}

	notaryCmd.AddCommand(cmdKeyGenerator.GetCommand())
	notaryCmd.AddCommand(cmdDelegationGenerator.GetCommand())
	notaryCmd.AddCommand(cmdCertGenerator.GetCommand())

	cmdTufGenerator.AddToCommand(&notaryCmd)

	return &notaryCmd
}

func main() {
	notaryCommander := &notaryCommander{getRetriever: getPassphraseRetriever}
	notaryCmd := notaryCommander.GetCommand()
	if err := notaryCmd.Execute(); err != nil {
		notaryCmd.Println("")
		fatalf(err.Error())
	}
}

func fatalf(format string, args ...interface{}) {
	fmt.Printf("* fatal: "+format+"\n", args...)
	os.Exit(1)
}

func askConfirm() bool {
	var res string
	_, err := fmt.Scanln(&res)
	if err != nil {
		return false
	}
	if strings.EqualFold(res, "y") || strings.EqualFold(res, "yes") {
		return true
	}
	return false
}

func getPassphraseRetriever() passphrase.Retriever {
	baseRetriever := passphrase.PromptRetriever()
	env := map[string]string{
		"root":     os.Getenv("NOTARY_ROOT_PASSPHRASE"),
		"targets":  os.Getenv("NOTARY_TARGETS_PASSPHRASE"),
		"snapshot": os.Getenv("NOTARY_SNAPSHOT_PASSPHRASE"),
	}

	return func(keyName string, alias string, createNew bool, numAttempts int) (string, bool, error) {
		if v := env[alias]; v != "" {
			return v, numAttempts > 1, nil
		}
		return baseRetriever(keyName, alias, createNew, numAttempts)
	}
}

// Set the logging level to fatal on default, or the most specific level the user specified (debug or error)
func (n *notaryCommander) setVerbosityLevel() {
	if n.debug {
		logrus.SetLevel(logrus.DebugLevel)
	} else if n.verbose {
		logrus.SetLevel(logrus.ErrorLevel)
	} else {
		logrus.SetLevel(logrus.FatalLevel)
	}
	logrus.SetOutput(os.Stderr)
}
<commit_msg>Add delegation passphrase env var<commit_after>package main

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

	"github.com/Sirupsen/logrus"
	"github.com/docker/notary/passphrase"
	"github.com/docker/notary/tuf/data"
	"github.com/docker/notary/version"
	homedir "github.com/mitchellh/go-homedir"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

const (
	configDir        = ".notary/"
	defaultServerURL = "https://notary-server:4443"
)

type usageTemplate struct {
	Use   string
	Short string
	Long  string
}

type cobraRunE func(cmd *cobra.Command, args []string) error

func (u usageTemplate) ToCommand(run cobraRunE) *cobra.Command {
	c := cobra.Command{
		Use:   u.Use,
		Short: u.Short,
		Long:  u.Long,
	}
	if run != nil {
		// newer versions of cobra support a run function that returns an error,
		// but in the meantime, this should help ease the transition
		c.RunE = run
	}
	return &c
}

func pathRelativeToCwd(path string) string {
	if path == "" || filepath.IsAbs(path) {
		return path
	}
	cwd, err := os.Getwd()
	if err != nil {
		return filepath.Clean(path)
	}
	return filepath.Clean(filepath.Join(cwd, path))
}

type notaryCommander struct {
	// this needs to be set
	getRetriever func() passphrase.Retriever

	// these are for command line parsing - no need to set
	debug             bool
	verbose           bool
	trustDir          string
	configFile        string
	remoteTrustServer string

	tlsCAFile   string
	tlsCertFile string
	tlsKeyFile  string
}

func (n *notaryCommander) parseConfig() (*viper.Viper, error) {
	n.setVerbosityLevel()

	// Get home directory for current user
	homeDir, err := homedir.Dir()
	if err != nil {
		return nil, fmt.Errorf("cannot get current user home directory: %v", err)
	}
	if homeDir == "" {
		return nil, fmt.Errorf("cannot get current user home directory")
	}

	config := viper.New()

	// By default our trust directory (where keys are stored) is in ~/.notary/
	defaultTrustDir := filepath.Join(homeDir, filepath.Dir(configDir))

	// If there was a commandline configFile set, we parse that.
	// If there wasn't we attempt to find it on the default location ~/.notary/config.json
	if n.configFile != "" {
		config.SetConfigFile(n.configFile)
	} else {
		config.SetConfigFile(filepath.Join(defaultTrustDir, "config.json"))
	}

	// Setup the configuration details into viper
	config.SetDefault("trust_dir", defaultTrustDir)
	config.SetDefault("remote_server", map[string]string{"url": defaultServerURL})

	// Find and read the config file
	if err := config.ReadInConfig(); err != nil {
		logrus.Debugf("Configuration file not found, using defaults")

		// If we were passed in a configFile via command linen flags, bail if it doesn't exist,
		// otherwise ignore it: we can use the defaults
		if n.configFile != "" || !os.IsNotExist(err) {
			return nil, fmt.Errorf("error opening config file: %v", err)
		}
	}

	// At this point we either have the default value or the one set by the config.
	// Either way, some command-line flags have precedence and overwrites the value
	if n.trustDir != "" {
		config.Set("trust_dir", pathRelativeToCwd(n.trustDir))
	}
	if n.tlsCAFile != "" {
		config.Set("remote_server.root_ca", pathRelativeToCwd(n.tlsCAFile))
	}
	if n.tlsCertFile != "" {
		config.Set("remote_server.tls_client_cert", pathRelativeToCwd(n.tlsCertFile))
	}
	if n.tlsKeyFile != "" {
		config.Set("remote_server.tls_client_key", pathRelativeToCwd(n.tlsKeyFile))
	}
	if n.remoteTrustServer != "" {
		config.Set("remote_server.url", n.remoteTrustServer)
	}

	// Expands all the possible ~/ that have been given, either through -d or config
	// If there is no error, use it, if not, just attempt to use whatever the user gave us
	expandedTrustDir, err := homedir.Expand(config.GetString("trust_dir"))
	if err == nil {
		config.Set("trust_dir", expandedTrustDir)
	}
	logrus.Debugf("Using the following trust directory: %s", config.GetString("trust_dir"))

	return config, nil
}

func (n *notaryCommander) GetCommand() *cobra.Command {
	notaryCmd := cobra.Command{
		Use:           "notary",
		Short:         "Notary allows the creation of trusted collections.",
		Long:          "Notary allows the creation and management of collections of signed targets, allowing the signing and validation of arbitrary content.",
		SilenceUsage:  true, // we don't want to print out usage for EVERY error
		SilenceErrors: true, // we do our own error reporting with fatalf
		Run:           func(cmd *cobra.Command, args []string) { cmd.Usage() },
	}
	notaryCmd.SetOutput(os.Stdout)
	notaryCmd.AddCommand(&cobra.Command{
		Use:   "version",
		Short: "Print the version number of notary",
		Long:  `print the version number of notary`,
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Printf("notary\n Version:    %s\n Git commit: %s\n", version.NotaryVersion, version.GitCommit)
		},
	})

	notaryCmd.PersistentFlags().StringVarP(
		&n.trustDir, "trustDir", "d", "", "Directory where the trust data is persisted to")
	notaryCmd.PersistentFlags().StringVarP(
		&n.configFile, "configFile", "c", "", "Path to the configuration file to use")
	notaryCmd.PersistentFlags().BoolVarP(&n.verbose, "verbose", "v", false, "Verbose output")
	notaryCmd.PersistentFlags().BoolVarP(&n.debug, "debug", "D", false, "Debug output")
	notaryCmd.PersistentFlags().StringVarP(&n.remoteTrustServer, "server", "s", "", "Remote trust server location")
	notaryCmd.PersistentFlags().StringVar(&n.tlsCAFile, "tlscacert", "", "Trust certs signed only by this CA")
	notaryCmd.PersistentFlags().StringVar(&n.tlsCertFile, "tlscert", "", "Path to TLS certificate file")
	notaryCmd.PersistentFlags().StringVar(&n.tlsKeyFile, "tlskey", "", "Path to TLS key file")

	cmdKeyGenerator := &keyCommander{
		configGetter: n.parseConfig,
		getRetriever: n.getRetriever,
	}

	cmdDelegationGenerator := &delegationCommander{
		configGetter: n.parseConfig,
		retriever:    n.getRetriever(),
	}

	cmdCertGenerator := &certCommander{
		configGetter: n.parseConfig,
		retriever:    n.getRetriever(),
	}

	cmdTufGenerator := &tufCommander{
		configGetter: n.parseConfig,
		retriever:    n.getRetriever(),
	}

	notaryCmd.AddCommand(cmdKeyGenerator.GetCommand())
	notaryCmd.AddCommand(cmdDelegationGenerator.GetCommand())
	notaryCmd.AddCommand(cmdCertGenerator.GetCommand())

	cmdTufGenerator.AddToCommand(&notaryCmd)

	return &notaryCmd
}

func main() {
	notaryCommander := &notaryCommander{getRetriever: getPassphraseRetriever}
	notaryCmd := notaryCommander.GetCommand()
	if err := notaryCmd.Execute(); err != nil {
		notaryCmd.Println("")
		fatalf(err.Error())
	}
}

func fatalf(format string, args ...interface{}) {
	fmt.Printf("* fatal: "+format+"\n", args...)
	os.Exit(1)
}

func askConfirm() bool {
	var res string
	_, err := fmt.Scanln(&res)
	if err != nil {
		return false
	}
	if strings.EqualFold(res, "y") || strings.EqualFold(res, "yes") {
		return true
	}
	return false
}

func getPassphraseRetriever() passphrase.Retriever {
	baseRetriever := passphrase.PromptRetriever()
	env := map[string]string{
		"root":       os.Getenv("NOTARY_ROOT_PASSPHRASE"),
		"targets":    os.Getenv("NOTARY_TARGETS_PASSPHRASE"),
		"snapshot":   os.Getenv("NOTARY_SNAPSHOT_PASSPHRASE"),
		"delegation": os.Getenv("NOTARY_DELEGATION_PASSPHRASE"),
	}

	return func(keyName string, alias string, createNew bool, numAttempts int) (string, bool, error) {
		if v := env[alias]; v != "" {
			return v, numAttempts > 1, nil
		}
		// For delegation roles, we can also try the "delegation" alias if it is specified
		if v := env["delegation"]; v != "" && data.IsDelegation(alias) {
			return v, numAttempts > 1, nil
		}
		return baseRetriever(keyName, alias, createNew, numAttempts)
	}
}

// Set the logging level to fatal on default, or the most specific level the user specified (debug or error)
func (n *notaryCommander) setVerbosityLevel() {
	if n.debug {
		logrus.SetLevel(logrus.DebugLevel)
	} else if n.verbose {
		logrus.SetLevel(logrus.ErrorLevel)
	} else {
		logrus.SetLevel(logrus.FatalLevel)
	}
	logrus.SetOutput(os.Stderr)
}
<|endoftext|>