<commit_before>package dtf

import (
	"testing"
	"time"
)

func TestParse(t *testing.T) {
	var expected, result time.Time

	expected = time.Date(2015, time.January, 1, 0, 0, 0, 0, time.UTC)
	result, _ = Parse("2015")
	if result != expected {
		t.Error("Parse return unexpected time object:" + result.String())
	}

	expected = time.Date(2015, time.January, 1, 0, 0, 0, 0, time.UTC)
	result, _ = Parse("2015-01")
	if result != expected {
		t.Error("Parse return unexpected time object:" + result.String())
	}

	expected = time.Date(2015, time.January, 15, 0, 0, 0, 0, time.UTC)
	result, _ = Parse("2015-01-15")
	if result != expected {
		t.Error("Parse return unexpected time object:" + result.String())
	}

	expected = time.Date(2015, time.January, 15, 18, 30, 0, 0, time.UTC)
	result, _ = Parse("2015-01-15T18:30Z")
	if result.UnixNano() != expected.UnixNano() {
		t.Error("Parse return unexpected time object:" + result.String())
	}

	expected = time.Date(2015, time.January, 15, 18, 30, 20, 0, time.UTC)
	result, _ = Parse("2015-01-15T18:30:20+00:00")
	if result.UnixNano() != expected.UnixNano() {
		t.Error("Parse return unexpected time object:" + result.String())
	}

	expected = time.Date(2015, time.January, 15, 18, 30, 20, 123456789, time.UTC)
	result, _ = Parse("2015-01-15T18:30:20.123456789+00:00")
	if result.UnixNano() != expected.UnixNano() {
		t.Error("Parse return unexpected time object:" + result.String())
	}
}

func TestParseYear(t *testing.T) {
	expected := time.Date(2015, time.January, 1, 0, 0, 0, 0, time.UTC)
	result, err := ParseYear("2015")

	if err != nil {
		t.Error(err)
	}

	if result != expected {
		t.Error("ParseYear return unexpected time object:" + result.String())
	}
}

func TestParseYearAndMonth(t *testing.T) {
	expected := time.Date(2015, time.December, 1, 0, 0, 0, 0, time.UTC)
	result, err := ParseYearAndMonth("2015-12")

	if err != nil {
		t.Error(err)
	}

	if result != expected {
		t.Error("ParseYearAndMonth return unexpected time object:" + result.String())
	}
}

func TestParseCompleteDate(t *testing.T) {
	expected := time.Date(2015, time.December, 19, 0, 0, 0, 0, time.UTC)
	result, err := ParseCompleteDate("2015-12-19")

	if err != nil {
		t.Error(err)
	}

	if result != expected {
		t.Error("ParseCompleteDate return unexpected time object:" + result.String())
	}
}

func TestParseCompleteDateWithMinutes(t *testing.T) {
	location, _ := time.LoadLocation("Asia/Tokyo")
	expected := time.Date(2015, time.December, 19, 18, 30, 0, 0, location)
	result, err := ParseCompleteDateWithMinutes("2015-12-19T18:30+09:00")

	if err != nil {
		t.Error(err)
	}

	if result.String() != expected.String() {
		t.Error("ParseCompleteDateWithMinutes return unexpected time object:" + result.String())
	}
}

func TestParseCompleteDateWithMinutesContainsUTC(t *testing.T) {
	expected := time.Date(2015, time.December, 19, 18, 30, 0, 0, time.UTC)
	result, err := ParseCompleteDateWithMinutes("2015-12-19T18:30+00:00")

	if err != nil {
		t.Error(err)
	}

	if result.UnixNano() != expected.UnixNano() {
		t.Error("ParseCompleteDateWithMinutes return unexpected time object:" + result.String())
	}
}

func TestParseCompleteDateWithSeconds(t *testing.T) {
	location, _ := time.LoadLocation("Asia/Tokyo")
	expected := time.Date(2015, time.December, 19, 18, 30, 22, 0, location)
	result, err := ParseCompleteDateWithSeconds("2015-12-19T18:30:22+09:00")

	if err != nil {
		t.Error(err)
	}

	if result.String() != expected.String() {
		t.Error("ParseCompleteDateWithMinutes return unexpected time object:" + result.String())
	}
}

func TestParseCompleteDateWithFractionOfSecond(t *testing.T) {
	location, _ := time.LoadLocation("Asia/Tokyo")
	expected := time.Date(2015, time.December, 19, 18, 30, 22, 123456789, location)
	result, err := ParseCompleteDateWithSeconds("2015-12-19T18:30:22.123456789+09:00")

	if err != nil {
		t.Error(err)
	}

	if result.String() != expected.String() {
		t.Error("ParseCompleteDateWithFractionOfSecond return unexpected time object:" + result.String())
	}
}
<commit_msg>Update parse test<commit_after>package dtf

import (
	"testing"
	"time"
)

func TestParse(t *testing.T) {
	var expected, result time.Time

	expected = time.Date(2015, time.January, 1, 0, 0, 0, 0, time.UTC)
	result, _ = Parse("2015")
	if result != expected {
		t.Error("Parse return unexpected time object:" + result.String())
	}

	expected = time.Date(2015, time.January, 1, 0, 0, 0, 0, time.UTC)
	result, _ = Parse("2015-01")
	if result != expected {
		t.Error("Parse return unexpected time object:" + result.String())
	}

	expected = time.Date(2015, time.January, 15, 0, 0, 0, 0, time.UTC)
	result, _ = Parse("2015-01-15")
	if result != expected {
		t.Error("Parse return unexpected time object:" + result.String())
	}

	expected = time.Date(2015, time.January, 15, 18, 30, 0, 0, time.UTC)
	result, _ = Parse("2015-01-15T18:30+00:00")
	if result.UnixNano() != expected.UnixNano() {
		t.Error("Parse return unexpected time object:" + result.String())
	}

	expected = time.Date(2015, time.January, 15, 18, 30, 0, 0, time.UTC)
	result, _ = Parse("2015-01-15T18:30Z")
	if result.UnixNano() != expected.UnixNano() {
		t.Error("Parse return unexpected time object:" + result.String())
	}

	expected = time.Date(2015, time.January, 15, 18, 30, 20, 0, time.UTC)
	result, _ = Parse("2015-01-15T18:30:20+00:00")
	if result.UnixNano() != expected.UnixNano() {
		t.Error("Parse return unexpected time object:" + result.String())
	}

	expected = time.Date(2015, time.January, 15, 18, 30, 20, 0, time.UTC)
	result, _ = Parse("2015-01-15T18:30:20Z")
	if result.UnixNano() != expected.UnixNano() {
		t.Error("Parse return unexpected time object:" + result.String())
	}

	expected = time.Date(2015, time.January, 15, 18, 30, 20, 123456789, time.UTC)
	result, _ = Parse("2015-01-15T18:30:20.123456789+00:00")
	if result.UnixNano() != expected.UnixNano() {
		t.Error("Parse return unexpected time object:" + result.String())
	}

	expected = time.Date(2015, time.January, 15, 18, 30, 20, 123456789, time.UTC)
	result, _ = Parse("2015-01-15T18:30:20.123456789Z")
	if result.UnixNano() != expected.UnixNano() {
		t.Error("Parse return unexpected time object:" + result.String())
	}
}

func TestParseYear(t *testing.T) {
	expected := time.Date(2015, time.January, 1, 0, 0, 0, 0, time.UTC)
	result, err := ParseYear("2015")

	if err != nil {
		t.Error(err)
	}

	if result != expected {
		t.Error("ParseYear return unexpected time object:" + result.String())
	}
}

func TestParseYearAndMonth(t *testing.T) {
	expected := time.Date(2015, time.December, 1, 0, 0, 0, 0, time.UTC)
	result, err := ParseYearAndMonth("2015-12")

	if err != nil {
		t.Error(err)
	}

	if result != expected {
		t.Error("ParseYearAndMonth return unexpected time object:" + result.String())
	}
}

func TestParseCompleteDate(t *testing.T) {
	expected := time.Date(2015, time.December, 19, 0, 0, 0, 0, time.UTC)
	result, err := ParseCompleteDate("2015-12-19")

	if err != nil {
		t.Error(err)
	}

	if result != expected {
		t.Error("ParseCompleteDate return unexpected time object:" + result.String())
	}
}

func TestParseCompleteDateWithMinutes(t *testing.T) {
	location, _ := time.LoadLocation("Asia/Tokyo")
	expected := time.Date(2015, time.December, 19, 18, 30, 0, 0, location)
	result, err := ParseCompleteDateWithMinutes("2015-12-19T18:30+09:00")

	if err != nil {
		t.Error(err)
	}

	if result.UnixNano() != expected.UnixNano() {
		t.Error("ParseCompleteDateWithMinutes return unexpected time object:" + result.String())
	}
}

func TestParseCompleteDateWithMinutesContainsUTC(t *testing.T) {
	expected := time.Date(2015, time.December, 19, 18, 30, 0, 0, time.UTC)
	result1, err1 := ParseCompleteDateWithMinutes("2015-12-19T18:30+00:00")
	result2, err2 := ParseCompleteDateWithMinutes("2015-12-19T18:30Z")

	if err1 != nil {
		t.Error(err1)
	}

	if result1.UnixNano() != expected.UnixNano() {
		t.Error("ParseCompleteDateWithMinutes return unexpected time object:" + result1.String())
	}

	if err2 != nil {
		t.Error(err1)
	}

	if result2.UnixNano() != expected.UnixNano() {
		t.Error("ParseCompleteDateWithMinutes return unexpected time object:" + result2.String())
	}
}

func TestParseCompleteDateWithSeconds(t *testing.T) {
	location, _ := time.LoadLocation("Asia/Tokyo")
	expected := time.Date(2015, time.December, 19, 18, 30, 22, 0, location)
	result, err := ParseCompleteDateWithSeconds("2015-12-19T18:30:22+09:00")

	if err != nil {
		t.Error(err)
	}

	if result.UnixNano() != expected.UnixNano() {
		t.Error("ParseCompleteDateWithMinutes return unexpected time object:" + result.String())
	}
}

func TestParseCompleteDateWithSecondsContainsUTC(t *testing.T) {
	expected := time.Date(2015, time.December, 19, 18, 30, 22, 0, time.UTC)
	result1, err1 := ParseCompleteDateWithSeconds("2015-12-19T18:30:22+00:00")
	result2, err2 := ParseCompleteDateWithSeconds("2015-12-19T18:30:22Z")

	if err1 != nil {
		t.Error(err1)
	}

	if result1.UnixNano() != expected.UnixNano() {
		t.Error("ParseCompleteDateWithMinutes return unexpected time object:" + result1.String())
	}

	if err2 != nil {
		t.Error(err2)
	}

	if result2.UnixNano() != expected.UnixNano() {
		t.Error("ParseCompleteDateWithMinutes return unexpected time object:" + result2.String())
	}
}

func TestParseCompleteDateWithFractionOfSecond(t *testing.T) {
	location, _ := time.LoadLocation("Asia/Tokyo")
	expected := time.Date(2015, time.December, 19, 18, 30, 22, 123456789, location)
	result, err := ParseCompleteDateWithSeconds("2015-12-19T18:30:22.123456789+09:00")

	if err != nil {
		t.Error(err)
	}

	if result.UnixNano() != expected.UnixNano() {
		t.Error("ParseCompleteDateWithFractionOfSecond return unexpected time object:" + result.String())
	}
}

func TestParseCompleteDateWithFractionOfSecondContainsUTC(t *testing.T) {
	expected := time.Date(2015, time.December, 19, 18, 30, 22, 123456789, time.UTC)
	result1, err1 := ParseCompleteDateWithSeconds("2015-12-19T18:30:22.123456789+00:00")
	result2, err2 := ParseCompleteDateWithSeconds("2015-12-19T18:30:22.123456789Z")

	if err1 != nil {
		t.Error(err1)
	}

	if result1.UnixNano() != expected.UnixNano() {
		t.Error("ParseCompleteDateWithFractionOfSecond return unexpected time object:" + result1.String())
	}

	if err2 != nil {
		t.Error(err2)
	}

	if result2.UnixNano() != expected.UnixNano() {
		t.Error("ParseCompleteDateWithFractionOfSecond return unexpected time object:" + result2.String())
	}
}
<|endoftext|>


<commit_before>package otp

import (
	"bytes"
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/base32"
	"fmt"
	"strings"
	"text/template"
)

// These are acceptable inputs for `Key.Method`.
var METHODS = []string{"totp", "hotp"}

// There are supported hash algorithms for `Key.Algo`.
var HASHES = []Hash{sha1.New, sha256.New, sha512.New, md5.New}

// Custom error type for Key related errors. Generally refers to validation errors.
type KeyError struct {
	param string
	msg   string
}

// Renders the error string.
func (e KeyError) Error() string {
	return fmt.Sprintf("KeyError - %v - %v", e.param, e.msg)
}

// Defines all parameter required for code generation, including useful metadata.
type Key struct {
	Method  string // Initialization method. Acceptable values are either 'totp' or 'hotp' for time-based or counter-based, respectively.
	Label   string // Label for the key.
	Secret  string // String representation of base32 encoded integer.
	Issuer  string // The issuer of the key.
	Algo    Hash   // The hash algorithm used in the HMAC. SHA1, SHA256, SHA512, and MD5 are supported.
	Digits  int    // The length of the code. 6 or 8 are acceptable.
	Period  int    // The number of seconds the code is valid for. Applies only to 'totp'.
	Counter int    // The initial counter value. Applies only to 'hotp'.
}

// Given an initialization value, returns the proscribed HMAC one-time password.
func (k Key) GetHOTPCode(iv int64) (string, error) {
	code, err := GetCode(k.Secret, iv, k.Algo, k.Digits)
	return code, err
}

// Using the current time and parameters defined by the key, returns the one-time password based on Unix system time.
func (k Key) GetTOTPCode() (string, error) {
	iv := GetInterval(int64(k.Period))
	code, err := k.GetHOTPCode(iv)
	return code, err
}

func (k Key) HasValidMethod() error {
	if !stringInSlice(k.Method, METHODS) {
		return KeyError{"Method", "Invalid value"}
	}
	return nil
}

func (k Key) HasValidLabel() error {
	if len(k.Label) == 0 {
		return KeyError{"Label", "Missing value"}
	}

	if strings.ContainsRune(k.Label, '/') {
		return KeyError{"Label", "Contains '/'"}
	}

	return nil
}

func (k Key) HasValidSecret() error {
	if len(k.Secret) == 0 {
		return KeyError{"Secret", "Missing value"}
	}

	if _, err := base32.StdEncoding.DecodeString(k.Secret); err != nil {
		return KeyError{"Secret", "Invalid Base32"}
	}

	return nil
}

func (k Key) HasValidIssuer() error {
	if strings.ContainsRune(k.Issuer, '/') {
		return KeyError{"Issuer", "Contains '/'"}
	}
	return nil
}

func (k Key) HasValidAlgo() error {
	if !hashInSlice(k.Algo, HASHES) {
		return KeyError{"Algo", "Invalid hashing algorithm"}
	}
	return nil
}

func (k Key) HasValidDigits() error {
	if !(k.Digits == 6 || k.Digits == 8) {
		return KeyError{"Digits", "Not equal to 6 or 8"}
	}
	return nil
}

func (k Key) HasValidPeriod() error {
	if k.Method == "totp" && k.Period < 1 {
		return KeyError{"Period", "Negative value"}
	}
	return nil
}

func (k Key) IsValid() (bool, error) {

	// check method
	if err := k.HasValidMethod(); err != nil {
		return false, err
	}

	//check label
	if err := k.HasValidLabel(); err != nil {
		return false, err
	}

	// check secret
	if err := k.HasValidSecret(); err != nil {
		return false, err
	}

	// check issuer
	if err := k.HasValidIssuer(); err != nil {
		return false, err
	}

	// check algo
	if err := k.HasValidAlgo(); err != nil {
		return false, err
	}

	// check digits
	if err := k.HasValidDigits(); err != nil {
		return false, err
	}

	// check period
	if err := k.HasValidPeriod(); err != nil {
		return false, err
	}

	return true, nil
}

// Returns the string representation of the Key according to the Google Authenticator KeyUriFormat. See https://code.google.com/p/google-authenticator/wiki/KeyUriFormat for more detail.
func (k Key) String() string {
	markup := "otpauth://{{.Method}}/{{.Label}}?Secret={{.Secret}}"
	if len(k.Issuer) > 0 {
		markup = markup + "&Issuer={{.Issuer}}"
	}

	// reflect out the name of the hash function
	hashName := strings.Split(strings.Split(getFuncName(k.Algo), ".")[0], "/")[1]
	markup = markup + "&Algo=" + strings.ToUpper(hashName)

	markup = markup + "&Digits={{.Digits}}"

	if k.Method == "totp" {
		markup = markup + "&Period={{.Period}}"
	}

	if k.Method == "hotp" {
		markup = markup + "&Counter={{.Counter}}"
	}

	tmpl, _ := template.New("uri").Parse(markup)
	var uri bytes.Buffer
	tmpl.Execute(&uri, k)
	return uri.String()
}
<commit_msg>limiting scope<commit_after>package otp

import (
	"bytes"
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/base32"
	"fmt"
	"strings"
	"text/template"
)

// These are acceptable inputs for `Key.Method`.
var METHODS = []string{"totp", "hotp"}

// There are supported hash algorithms for `Key.Algo`.
var HASHES = []Hash{sha1.New, sha256.New, sha512.New, md5.New}

// Custom error type for Key related errors. Generally refers to validation errors.
type KeyError struct {
	param string
	msg   string
}

// Renders the error string.
func (e KeyError) Error() string {
	return fmt.Sprintf("KeyError - %v - %v", e.param, e.msg)
}

// Defines all parameter required for code generation, including useful metadata.
type Key struct {
	Method  string // Initialization method. Acceptable values are either 'totp' or 'hotp' for time-based or counter-based, respectively.
	Label   string // Label for the key.
	Secret  string // String representation of base32 encoded integer.
	Issuer  string // The issuer of the key.
	Algo    Hash   // The hash algorithm used in the HMAC. SHA1, SHA256, SHA512, and MD5 are supported.
	Digits  int    // The length of the code. 6 or 8 are acceptable.
	Period  int    // The number of seconds the code is valid for. Applies only to 'totp'.
	Counter int    // The initial counter value. Applies only to 'hotp'.
}

// Given an initialization value, returns the proscribed HMAC one-time password.
func (k Key) GetHOTPCode(iv int64) (string, error) {
	code, err := GetCode(k.Secret, iv, k.Algo, k.Digits)
	return code, err
}

// Using the current time and parameters defined by the key, returns the one-time password based on Unix system time.
func (k Key) GetTOTPCode() (string, error) {
	iv := GetInterval(int64(k.Period))
	code, err := k.GetHOTPCode(iv)
	return code, err
}

func (k Key) hasValidMethod() error {
	if !stringInSlice(k.Method, METHODS) {
		return KeyError{"Method", "Invalid value"}
	}
	return nil
}

func (k Key) hasValidLabel() error {
	if len(k.Label) == 0 {
		return KeyError{"Label", "Missing value"}
	}

	if strings.ContainsRune(k.Label, '/') {
		return KeyError{"Label", "Contains '/'"}
	}

	return nil
}

func (k Key) hasValidSecret() error {
	if len(k.Secret) == 0 {
		return KeyError{"Secret", "Missing value"}
	}

	if _, err := base32.StdEncoding.DecodeString(k.Secret); err != nil {
		return KeyError{"Secret", "Invalid Base32"}
	}

	return nil
}

func (k Key) hasValidIssuer() error {
	if strings.ContainsRune(k.Issuer, '/') {
		return KeyError{"Issuer", "Contains '/'"}
	}
	return nil
}

func (k Key) hasValidAlgo() error {
	if !hashInSlice(k.Algo, HASHES) {
		return KeyError{"Algo", "Invalid hashing algorithm"}
	}
	return nil
}

func (k Key) hasValidDigits() error {
	if !(k.Digits == 6 || k.Digits == 8) {
		return KeyError{"Digits", "Not equal to 6 or 8"}
	}
	return nil
}

func (k Key) hasValidPeriod() error {
	if k.Method == "totp" && k.Period < 1 {
		return KeyError{"Period", "Negative value"}
	}
	return nil
}

func (k Key) IsValid() (bool, error) {

	// check method
	if err := k.hasValidMethod(); err != nil {
		return false, err
	}

	//check label
	if err := k.hasValidLabel(); err != nil {
		return false, err
	}

	// check secret
	if err := k.hasValidSecret(); err != nil {
		return false, err
	}

	// check issuer
	if err := k.hasValidIssuer(); err != nil {
		return false, err
	}

	// check algo
	if err := k.hasValidAlgo(); err != nil {
		return false, err
	}

	// check digits
	if err := k.hasValidDigits(); err != nil {
		return false, err
	}

	// check period
	if err := k.hasValidPeriod(); err != nil {
		return false, err
	}

	return true, nil
}

// Returns the string representation of the Key according to the Google Authenticator KeyUriFormat. See https://code.google.com/p/google-authenticator/wiki/KeyUriFormat for more detail.
func (k Key) String() string {
	markup := "otpauth://{{.Method}}/{{.Label}}?Secret={{.Secret}}"
	if len(k.Issuer) > 0 {
		markup = markup + "&Issuer={{.Issuer}}"
	}

	// reflect out the name of the hash function
	hashName := strings.Split(strings.Split(getFuncName(k.Algo), ".")[0], "/")[1]
	markup = markup + "&Algo=" + strings.ToUpper(hashName)

	markup = markup + "&Digits={{.Digits}}"

	if k.Method == "totp" {
		markup = markup + "&Period={{.Period}}"
	}

	if k.Method == "hotp" {
		markup = markup + "&Counter={{.Counter}}"
	}

	tmpl, _ := template.New("uri").Parse(markup)
	var uri bytes.Buffer
	tmpl.Execute(&uri, k)
	return uri.String()
}
<|endoftext|>


<commit_before>package fat

import (
	"errors"
	"fmt"
	"github.com/mitchellh/go-fs"
	"math"
)

// The first cluster that can really hold user data is always 2
const FirstCluster = 2

// FAT is the actual file allocation table data structure that is
// stored on disk to describe the various clusters on the disk.
type FAT struct {
	bs      *BootSectorCommon
	entries []uint32
}

func DecodeFAT(device fs.BlockDevice, bs *BootSectorCommon, n int) (*FAT, error) {
	if n > int(bs.NumFATs) {
		return nil, fmt.Errorf("FAT #%d greater than total FATs: %d", n, bs.NumFATs)
	}

	data := make([]byte, bs.SectorsPerFat*uint32(bs.BytesPerSector))
	if _, err := device.ReadAt(data, int64(bs.FATOffset(n))); err != nil {
		return nil, err
	}

	result := &FAT{
		bs:      bs,
		entries: make([]uint32, FATEntryCount(bs)),
	}

	fatType := bs.FATType()
	for i := 0; i < int(FATEntryCount(bs)); i++ {
		var entryData uint32
		switch fatType {
		case FAT12:
			entryData = fatReadEntry12(data, i)
		case FAT16:
			entryData = fatReadEntry16(data, i)
		default:
			entryData = fatReadEntry32(data, i)
		}

		result.entries[i] = entryData
	}

	return result, nil
}

// NewFAT creates a new FAT data structure, properly initialized.
func NewFAT(bs *BootSectorCommon) (*FAT, error) {
	result := &FAT{
		bs:      bs,
		entries: make([]uint32, FATEntryCount(bs)),
	}

	// Set the initial two entries according to spec
	result.entries[0] = (uint32(bs.Media) & 0xFF) |
		(0xFFFFFF00 & result.entryMask())
	result.entries[1] = 0xFFFFFFFF & result.entryMask()

	return result, nil
}

// Bytes returns the raw bytes for the FAT that should be written to
// the block device.
func (f *FAT) Bytes() []byte {
	result := make([]byte, f.bs.SectorsPerFat*uint32(f.bs.BytesPerSector))

	for i, entry := range f.entries {
		switch f.bs.FATType() {
		case FAT12:
			f.writeEntry12(result, i, entry)
		case FAT16:
			f.writeEntry16(result, i, entry)
		default:
			f.writeEntry32(result, i, entry)
		}
	}

	return result
}

func (f *FAT) AllocChain() (uint32, error) {
	return f.allocNew()
}

func (f *FAT) allocNew() (uint32, error) {
	dataSize := (f.bs.TotalSectors * uint32(f.bs.BytesPerSector))
	dataSize -= f.bs.DataOffset()
	clusterCount := dataSize / f.bs.BytesPerCluster()
	lastClusterIndex := clusterCount + FirstCluster

	var availIdx uint32
	found := false
	for i := uint32(FirstCluster); i < lastClusterIndex; i++ {
		if f.entries[i] == 0 {
			availIdx = i
			found = true
			break
		}
	}

	if !found {
		return 0, errors.New("FAT FULL")
	}

	// Mark that this is now in use
	f.entries[availIdx] = 0xFFFFFFFF & f.entryMask()

	return availIdx, nil
}

// Chain returns the chain of clusters starting at a certain cluster.
func (f *FAT) Chain(start uint32) []uint32 {
	chain := make([]uint32, 0, 2)

	cluster := start
	for {
		chain = append(chain, cluster)
		cluster = f.entries[cluster]

		if f.isEofCluster(cluster) || cluster == 0 {
			break
		}
	}

	return chain
}

// ResizeChain takes a given cluster number and resizes the chain
// to the given length. It returns the new chain of clusters.
func (f *FAT) ResizeChain(start uint32, length int) ([]uint32, error) {
	chain := f.Chain(start)
	if len(chain) == length {
		return chain, nil
	}

	change := int(math.Abs(float64(length - len(chain))))
	if length > len(chain) {
		var lastCluster uint32

		lastCluster = chain[0]
		for i := 1; i < len(chain); i++ {
			if f.isEofCluster(f.entries[lastCluster]) {
				break
			}

			lastCluster = chain[i]
		}

		for i := 0; i < change; i++ {
			newCluster, err := f.allocNew()
			if err != nil {
				return nil, err
			}

			f.entries[lastCluster] = newCluster
			lastCluster = newCluster
		}
	} else {
		panic("making chains smaller not implemented yet")
	}

	return f.Chain(start), nil
}

func (f *FAT) WriteToDevice(device fs.BlockDevice) error {
	fatBytes := f.Bytes()
	for i := 0; i < int(f.bs.NumFATs); i++ {
		offset := int64(f.bs.FATOffset(i))
		if _, err := device.WriteAt(fatBytes, offset); err != nil {
			return err
		}
	}

	return nil
}

func (f *FAT) entryMask() uint32 {
	switch f.bs.FATType() {
	case FAT12:
		return 0x0FFF
	case FAT16:
		return 0xFFFF
	default:
		return 0x0FFFFFFF
	}
}

func (f *FAT) isEofCluster(cluster uint32) bool {
	return cluster >= (0xFFFFFF8 & f.entryMask())
}

func (f *FAT) writeEntry12(data []byte, idx int, entry uint32) {
	idx += idx / 2

	if idx%2 == 0 {
		// Cluster number is EVEN
		data[idx] = byte(entry & 0xFF)
		data[idx+1] = byte((entry >> 8) & 0x0F)
	} else {
		// Cluster number is ODD
		data[idx] |= byte((entry & 0x0F) << 4)
		data[idx+1] = byte((entry >> 4) & 0xFF)
	}
}

func (f *FAT) writeEntry16(data []byte, idx int, entry uint32) {
	idx <<= 1
	data[idx] = byte(entry & 0xFF)
	data[idx+1] = byte((entry >> 8) & 0xFF)
}

func (f *FAT) writeEntry32(data []byte, idx int, entry uint32) {
	idx <<= 2
	data[idx] = byte(entry & 0xFF)
	data[idx+1] = byte((entry >> 8) & 0xFF)
	data[idx+2] = byte((entry >> 16) & 0xFF)
	data[idx+3] = byte((entry >> 24) & 0xFF)
}

// FATEntryCount returns the number of entries per fat for the given
// boot sector.
func FATEntryCount(bs *BootSectorCommon) uint32 {
	// Determine the number of entries that'll go in the FAT.
	var entryCount uint32 = bs.SectorsPerFat * uint32(bs.BytesPerSector)
	switch bs.FATType() {
	case FAT12:
		entryCount = uint32((uint64(entryCount) * 8) / 12)
	case FAT16:
		entryCount /= 2
	case FAT32:
		entryCount /= 4
	default:
		panic("impossible fat type")
	}

	return entryCount
}

func fatReadEntry12(data []byte, idx int) uint32 {
	idx += idx / 2

	var result uint32 = (uint32(data[idx+1]) << 8) | uint32(data[idx])
	if idx%2 == 0 {
		return result & 0xFFF
	} else {
		return result >> 4
	}
}

func fatReadEntry16(data []byte, idx int) uint32 {
	idx <<= 1
	return (uint32(data[idx+1]) << 8) | uint32(data[idx])
}

func fatReadEntry32(data []byte, idx int) uint32 {
	idx <<= 2
	return (uint32(data[idx+3]) << 24) |
		(uint32(data[idx+2]) << 16) |
		(uint32(data[idx+1]) << 8) |
		uint32(data[idx+0])
}
<commit_msg>fat: calculate the proper FAT12 entry values<commit_after>package fat

import (
	"errors"
	"fmt"
	"github.com/mitchellh/go-fs"
	"math"
)

// The first cluster that can really hold user data is always 2
const FirstCluster = 2

// FAT is the actual file allocation table data structure that is
// stored on disk to describe the various clusters on the disk.
type FAT struct {
	bs      *BootSectorCommon
	entries []uint32
}

func DecodeFAT(device fs.BlockDevice, bs *BootSectorCommon, n int) (*FAT, error) {
	if n > int(bs.NumFATs) {
		return nil, fmt.Errorf("FAT #%d greater than total FATs: %d", n, bs.NumFATs)
	}

	data := make([]byte, bs.SectorsPerFat*uint32(bs.BytesPerSector))
	if _, err := device.ReadAt(data, int64(bs.FATOffset(n))); err != nil {
		return nil, err
	}

	result := &FAT{
		bs:      bs,
		entries: make([]uint32, FATEntryCount(bs)),
	}

	fatType := bs.FATType()
	for i := 0; i < int(FATEntryCount(bs)); i++ {
		var entryData uint32
		switch fatType {
		case FAT12:
			entryData = fatReadEntry12(data, i)
		case FAT16:
			entryData = fatReadEntry16(data, i)
		default:
			entryData = fatReadEntry32(data, i)
		}

		result.entries[i] = entryData
	}

	return result, nil
}

// NewFAT creates a new FAT data structure, properly initialized.
func NewFAT(bs *BootSectorCommon) (*FAT, error) {
	result := &FAT{
		bs:      bs,
		entries: make([]uint32, FATEntryCount(bs)),
	}

	// Set the initial two entries according to spec
	result.entries[0] = (uint32(bs.Media) & 0xFF) |
		(0xFFFFFF00 & result.entryMask())
	result.entries[1] = 0xFFFFFFFF & result.entryMask()

	return result, nil
}

// Bytes returns the raw bytes for the FAT that should be written to
// the block device.
func (f *FAT) Bytes() []byte {
	result := make([]byte, f.bs.SectorsPerFat*uint32(f.bs.BytesPerSector))

	for i, entry := range f.entries {
		switch f.bs.FATType() {
		case FAT12:
			f.writeEntry12(result, i, entry)
		case FAT16:
			f.writeEntry16(result, i, entry)
		default:
			f.writeEntry32(result, i, entry)
		}
	}

	return result
}

func (f *FAT) AllocChain() (uint32, error) {
	return f.allocNew()
}

func (f *FAT) allocNew() (uint32, error) {
	dataSize := (f.bs.TotalSectors * uint32(f.bs.BytesPerSector))
	dataSize -= f.bs.DataOffset()
	clusterCount := dataSize / f.bs.BytesPerCluster()
	lastClusterIndex := clusterCount + FirstCluster

	var availIdx uint32
	found := false
	for i := uint32(FirstCluster); i < lastClusterIndex; i++ {
		if f.entries[i] == 0 {
			availIdx = i
			found = true
			break
		}
	}

	if !found {
		return 0, errors.New("FAT FULL")
	}

	// Mark that this is now in use
	f.entries[availIdx] = 0xFFFFFFFF & f.entryMask()

	return availIdx, nil
}

// Chain returns the chain of clusters starting at a certain cluster.
func (f *FAT) Chain(start uint32) []uint32 {
	chain := make([]uint32, 0, 2)

	cluster := start
	for {
		chain = append(chain, cluster)
		cluster = f.entries[cluster]

		if f.isEofCluster(cluster) || cluster == 0 {
			break
		}
	}

	return chain
}

// ResizeChain takes a given cluster number and resizes the chain
// to the given length. It returns the new chain of clusters.
func (f *FAT) ResizeChain(start uint32, length int) ([]uint32, error) {
	chain := f.Chain(start)
	if len(chain) == length {
		return chain, nil
	}

	change := int(math.Abs(float64(length - len(chain))))
	if length > len(chain) {
		var lastCluster uint32

		lastCluster = chain[0]
		for i := 1; i < len(chain); i++ {
			if f.isEofCluster(f.entries[lastCluster]) {
				break
			}

			lastCluster = chain[i]
		}

		for i := 0; i < change; i++ {
			newCluster, err := f.allocNew()
			if err != nil {
				return nil, err
			}

			f.entries[lastCluster] = newCluster
			lastCluster = newCluster
		}
	} else {
		panic("making chains smaller not implemented yet")
	}

	return f.Chain(start), nil
}

func (f *FAT) WriteToDevice(device fs.BlockDevice) error {
	fatBytes := f.Bytes()
	for i := 0; i < int(f.bs.NumFATs); i++ {
		offset := int64(f.bs.FATOffset(i))
		if _, err := device.WriteAt(fatBytes, offset); err != nil {
			return err
		}
	}

	return nil
}

func (f *FAT) entryMask() uint32 {
	switch f.bs.FATType() {
	case FAT12:
		return 0x0FFF
	case FAT16:
		return 0xFFFF
	default:
		return 0x0FFFFFFF
	}
}

func (f *FAT) isEofCluster(cluster uint32) bool {
	return cluster >= (0xFFFFFF8 & f.entryMask())
}

func (f *FAT) writeEntry12(data []byte, idx int, entry uint32) {
	dataIdx := idx + (idx / 2)
	data = data[dataIdx : dataIdx+2]

	if idx%2 == 1 {
		// ODD
		data[0] |= byte((entry & 0x0F) << 4)
		data[1] = byte((entry >> 4) & 0xFF)
	} else {
		// Even
		data[0] = byte(entry & 0xFF)
		data[1] = byte((entry >> 8) & 0x0F)
	}
}

func (f *FAT) writeEntry16(data []byte, idx int, entry uint32) {
	idx <<= 1
	data[idx] = byte(entry & 0xFF)
	data[idx+1] = byte((entry >> 8) & 0xFF)
}

func (f *FAT) writeEntry32(data []byte, idx int, entry uint32) {
	idx <<= 2
	data[idx] = byte(entry & 0xFF)
	data[idx+1] = byte((entry >> 8) & 0xFF)
	data[idx+2] = byte((entry >> 16) & 0xFF)
	data[idx+3] = byte((entry >> 24) & 0xFF)
}

// FATEntryCount returns the number of entries per fat for the given
// boot sector.
func FATEntryCount(bs *BootSectorCommon) uint32 {
	// Determine the number of entries that'll go in the FAT.
	var entryCount uint32 = bs.SectorsPerFat * uint32(bs.BytesPerSector)
	switch bs.FATType() {
	case FAT12:
		entryCount = uint32((uint64(entryCount) * 8) / 12)
	case FAT16:
		entryCount /= 2
	case FAT32:
		entryCount /= 4
	default:
		panic("impossible fat type")
	}

	return entryCount
}

func fatReadEntry12(data []byte, idx int) uint32 {
	idx += idx / 2

	var result uint32 = (uint32(data[idx+1]) << 8) | uint32(data[idx])
	if idx%2 == 0 {
		return result & 0xFFF
	} else {
		return result >> 4
	}
}

func fatReadEntry16(data []byte, idx int) uint32 {
	idx <<= 1
	return (uint32(data[idx+1]) << 8) | uint32(data[idx])
}

func fatReadEntry32(data []byte, idx int) uint32 {
	idx <<= 2
	return (uint32(data[idx+3]) << 24) |
		(uint32(data[idx+2]) << 16) |
		(uint32(data[idx+1]) << 8) |
		uint32(data[idx+0])
}
<|endoftext|>


<commit_before>package log

import (
	"encoding/json"
	"io"
)

// 默认 debug 级别，方便调试，生产环境可以调用 LevelSet 设置 log 级别
var v Level = Ldebug

// 默认实现，输出到 os.Std 中，可以重定向到文件中，也可以调用 SetPrinter 其他方式输出
var std Printer

// SetLevel 设置日志级别
func SetLevel(l Level) { v = l }

// Colorized 输出日志是否着色，默认不着色
func Colorized(c bool) { std.Colorized(c) }

// GetLevel 返回设置的日志级别
func GetLevel() (l Level) { return v }

// SetPrinter 切换 Printer 实现
func SetPrinter(p Printer) { std = p }

// SetWriter 改变输出位置，通过这个接口，可以实现日志文件按时间或按大小滚动
func SetWriter(w io.Writer) { std.SetWriter(w) }

// SetFormat 改变日志格式
func SetFormat(format string) { std.SetFormat(format) }

// 判断各种级别的日志是否会被输出
func IsTraceEnabled() bool { return v <= Ltrace }
func IsDebugEnabled() bool { return v <= Ldebug }
func IsInfoEnabled() bool  { return v <= Linfo }
func IsWarnEnabled() bool  { return v <= Lwarn }
func IsErrorEnabled() bool { return v <= Lerror }
func IsPanicEnabled() bool { return v <= Lpanic }
func IsFatalEnabled() bool { return v <= Lfatal }
func IsPrintEnabled() bool { return v <= Lprint }
func IsStackEnabled() bool { return v <= Lstack }

// 打印日志
func Trace(m ...interface{}) { std.Tprintf(Ltrace, "", "", m...) }
func Debug(m ...interface{}) { std.Tprintf(Ldebug, "", "", m...) }
func Info(m ...interface{})  { std.Tprintf(Linfo, "", "", m...) }
func Warn(m ...interface{})  { std.Tprintf(Lwarn, "", "", m...) }
func Error(m ...interface{}) { std.Tprintf(Lerror, "", "", m...) }
func Panic(m ...interface{}) { std.Tprintf(Lpanic, "", "", m...) }
func Fatal(m ...interface{}) { std.Tprintf(Lfatal, "", "", m...) }
func Print(m ...interface{}) { std.Tprintf(Lprint, "", "", m...) }
func Stack(m ...interface{}) { std.Tprintf(Lstack, "", "", m...) }

var nilerr = (error)(nil)

// Errorn check last argument, if error but nil, no print log
func Errorn(m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lerror, "", "", m...)
}

// 按一定格式打印日志
func Tracef(format string, m ...interface{}) { std.Tprintf(Ltrace, "", format, m...) }
func Debugf(format string, m ...interface{}) { std.Tprintf(Ldebug, "", format, m...) }
func Infof(format string, m ...interface{})  { std.Tprintf(Linfo, "", format, m...) }
func Warnf(format string, m ...interface{})  { std.Tprintf(Lwarn, "", format, m...) }
func Errorf(format string, m ...interface{}) { std.Tprintf(Lerror, "", format, m...) }
func Panicf(format string, m ...interface{}) { std.Tprintf(Lpanic, "", format, m...) }
func Fatalf(format string, m ...interface{}) { std.Tprintf(Lfatal, "", format, m...) }
func Printf(format string, m ...interface{}) { std.Tprintf(Lprint, "", format, m...) }
func Stackf(format string, m ...interface{}) { std.Tprintf(Lstack, "", format, m...) }

// Errorn check last argument, if error but nil, no print log
func Errornf(format string, m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lerror, "", format, m...)
}

// 打印日志时带上 tag
func Ttrace(tag string, m ...interface{}) { std.Tprintf(Ltrace, tag, "", m...) }
func Tdebug(tag string, m ...interface{}) { std.Tprintf(Ldebug, tag, "", m...) }
func Tinfo(tag string, m ...interface{})  { std.Tprintf(Linfo, tag, "", m...) }
func Twarn(tag string, m ...interface{})  { std.Tprintf(Lwarn, tag, "", m...) }
func Terror(tag string, m ...interface{}) { std.Tprintf(Lerror, tag, "", m...) }
func Tpanic(tag string, m ...interface{}) { std.Tprintf(Lpanic, tag, "", m...) }
func Tfatal(tag string, m ...interface{}) { std.Tprintf(Lfatal, tag, "", m...) }
func Tprint(tag string, m ...interface{}) { std.Tprintf(Lprint, tag, "", m...) }
func Tstack(tag string, m ...interface{}) { std.Tprintf(Lstack, tag, "", m...) }

// Errorn check last argument, if error but nil, no print log
func Terrorn(tag string, m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lerror, tag, "", m...)
}

// 按一定格式打印日志，并在打印日志时带上 tag
func Ttracef(tag string, format string, m ...interface{}) {
	std.Tprintf(Ltrace, tag, format, m...)
}
func Tdebugf(tag string, format string, m ...interface{}) {
	std.Tprintf(Ldebug, tag, format, m...)
}
func Tinfof(tag string, format string, m ...interface{}) { std.Tprintf(Linfo, tag, format, m...) }
func Twarnf(tag string, format string, m ...interface{}) { std.Tprintf(Lwarn, tag, format, m...) }
func Terrorf(tag string, format string, m ...interface{}) {
	std.Tprintf(Lerror, tag, format, m...)
}
func Tpanicf(tag string, format string, m ...interface{}) {
	std.Tprintf(Lpanic, tag, format, m...)
}
func Tfatalf(tag string, format string, m ...interface{}) {
	std.Tprintf(Lfatal, tag, format, m...)
}
func Tprintf(tag string, format string, m ...interface{}) {
	std.Tprintf(Lprint, tag, format, m...)
}
func Tstackf(tag string, format string, m ...interface{}) {
	std.Tprintf(Lstack, tag, format, m...)
}

// Errorn check last argument, if error but nil, no print log
func Terrornf(tag string, format string, m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lerror, tag, format, m...)
}

func Json(m ...interface{}) {
	if v > Ldebug {
		return
	}
	js, err := json.Marshal(m)
	if err != nil {
		std.Tprintf(Ldebug, "", "%s", err)
	} else {
		std.Tprintf(Ldebug, "", "%s", js[1:len(js)-1])
	}
}

// 先转换成 JSON 格式，然后打印
func JSON(m ...interface{}) {
	if v > Ldebug {
		return
	}
	js, err := json.Marshal(m)
	if err != nil {
		std.Tprintf(Ldebug, "", "%s", err)
	} else {
		std.Tprintf(Ldebug, "", "%s", js[1:len(js)-1])
	}
}
func JsonIndent(m ...interface{}) {
	if v > Ldebug {
		return
	}
	js, err := json.MarshalIndent(m, "", "    ")
	if err != nil {
		std.Tprintf(Ldebug, "", "%s", err)
	} else {
		std.Tprintf(Ldebug, "", "%s", js)
	}
}

func JSONIndent(m ...interface{}) {
	if v > Ldebug {
		return
	}
	js, err := json.MarshalIndent(m, "", "    ")
	if err != nil {
		std.Tprintf(Ldebug, "", "%s", err)
	} else {
		std.Tprintf(Ldebug, "", "%s", js)
	}
}
<commit_msg>add log.Fataln function<commit_after>package log

import (
	"encoding/json"
	"io"
)

// 默认 debug 级别，方便调试，生产环境可以调用 LevelSet 设置 log 级别
var v Level = Ldebug

// 默认实现，输出到 os.Std 中，可以重定向到文件中，也可以调用 SetPrinter 其他方式输出
var std Printer

// SetLevel 设置日志级别
func SetLevel(l Level) { v = l }

// Colorized 输出日志是否着色，默认不着色
func Colorized(c bool) { std.Colorized(c) }

// GetLevel 返回设置的日志级别
func GetLevel() (l Level) { return v }

// SetPrinter 切换 Printer 实现
func SetPrinter(p Printer) { std = p }

// SetWriter 改变输出位置，通过这个接口，可以实现日志文件按时间或按大小滚动
func SetWriter(w io.Writer) { std.SetWriter(w) }

// SetFormat 改变日志格式
func SetFormat(format string) { std.SetFormat(format) }

// 判断各种级别的日志是否会被输出
func IsTraceEnabled() bool { return v <= Ltrace }
func IsDebugEnabled() bool { return v <= Ldebug }
func IsInfoEnabled() bool  { return v <= Linfo }
func IsWarnEnabled() bool  { return v <= Lwarn }
func IsErrorEnabled() bool { return v <= Lerror }
func IsPanicEnabled() bool { return v <= Lpanic }
func IsFatalEnabled() bool { return v <= Lfatal }
func IsPrintEnabled() bool { return v <= Lprint }
func IsStackEnabled() bool { return v <= Lstack }

// 打印日志
func Trace(m ...interface{}) { std.Tprintf(Ltrace, "", "", m...) }
func Debug(m ...interface{}) { std.Tprintf(Ldebug, "", "", m...) }
func Info(m ...interface{})  { std.Tprintf(Linfo, "", "", m...) }
func Warn(m ...interface{})  { std.Tprintf(Lwarn, "", "", m...) }
func Error(m ...interface{}) { std.Tprintf(Lerror, "", "", m...) }
func Panic(m ...interface{}) { std.Tprintf(Lpanic, "", "", m...) }
func Fatal(m ...interface{}) { std.Tprintf(Lfatal, "", "", m...) }
func Print(m ...interface{}) { std.Tprintf(Lprint, "", "", m...) }
func Stack(m ...interface{}) { std.Tprintf(Lstack, "", "", m...) }

var nilerr = (error)(nil)

// Errorn check last argument, if error but nil, no print log
func Errorn(m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lerror, "", "", m...)
}
func Fataln(m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lfatal, "", "", m...)
}

// 按一定格式打印日志
func Tracef(format string, m ...interface{}) { std.Tprintf(Ltrace, "", format, m...) }
func Debugf(format string, m ...interface{}) { std.Tprintf(Ldebug, "", format, m...) }
func Infof(format string, m ...interface{})  { std.Tprintf(Linfo, "", format, m...) }
func Warnf(format string, m ...interface{})  { std.Tprintf(Lwarn, "", format, m...) }
func Errorf(format string, m ...interface{}) { std.Tprintf(Lerror, "", format, m...) }
func Panicf(format string, m ...interface{}) { std.Tprintf(Lpanic, "", format, m...) }
func Fatalf(format string, m ...interface{}) { std.Tprintf(Lfatal, "", format, m...) }
func Printf(format string, m ...interface{}) { std.Tprintf(Lprint, "", format, m...) }
func Stackf(format string, m ...interface{}) { std.Tprintf(Lstack, "", format, m...) }

// Errorn check last argument, if error but nil, no print log
func Errornf(format string, m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lerror, "", format, m...)
}
func Fatalnf(format string, m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lfatal, "", format, m...)
}

// 打印日志时带上 tag
func Ttrace(tag string, m ...interface{}) { std.Tprintf(Ltrace, tag, "", m...) }
func Tdebug(tag string, m ...interface{}) { std.Tprintf(Ldebug, tag, "", m...) }
func Tinfo(tag string, m ...interface{})  { std.Tprintf(Linfo, tag, "", m...) }
func Twarn(tag string, m ...interface{})  { std.Tprintf(Lwarn, tag, "", m...) }
func Terror(tag string, m ...interface{}) { std.Tprintf(Lerror, tag, "", m...) }
func Tpanic(tag string, m ...interface{}) { std.Tprintf(Lpanic, tag, "", m...) }
func Tfatal(tag string, m ...interface{}) { std.Tprintf(Lfatal, tag, "", m...) }
func Tprint(tag string, m ...interface{}) { std.Tprintf(Lprint, tag, "", m...) }
func Tstack(tag string, m ...interface{}) { std.Tprintf(Lstack, tag, "", m...) }

// Errorn check last argument, if error but nil, no print log
func Terrorn(tag string, m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lerror, tag, "", m...)
}
func Tfataln(tag string, m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lfatal, tag, "", m...)
}

// 按一定格式打印日志，并在打印日志时带上 tag
func Ttracef(tag string, format string, m ...interface{}) {
	std.Tprintf(Ltrace, tag, format, m...)
}
func Tdebugf(tag string, format string, m ...interface{}) {
	std.Tprintf(Ldebug, tag, format, m...)
}
func Tinfof(tag string, format string, m ...interface{}) { std.Tprintf(Linfo, tag, format, m...) }
func Twarnf(tag string, format string, m ...interface{}) { std.Tprintf(Lwarn, tag, format, m...) }
func Terrorf(tag string, format string, m ...interface{}) {
	std.Tprintf(Lerror, tag, format, m...)
}
func Tpanicf(tag string, format string, m ...interface{}) {
	std.Tprintf(Lpanic, tag, format, m...)
}
func Tfatalf(tag string, format string, m ...interface{}) {
	std.Tprintf(Lfatal, tag, format, m...)
}
func Tprintf(tag string, format string, m ...interface{}) {
	std.Tprintf(Lprint, tag, format, m...)
}
func Tstackf(tag string, format string, m ...interface{}) {
	std.Tprintf(Lstack, tag, format, m...)
}

// Errorn check last argument, if error but nil, no print log
func Terrornf(tag string, format string, m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lerror, tag, format, m...)
}
func Tfatalnf(tag string, format string, m ...interface{}) {
	if m[len(m)-1] == nilerr {
		return
	}
	std.Tprintf(Lfatal, tag, format, m...)
}

func Json(m ...interface{}) {
	if v > Ldebug {
		return
	}
	js, err := json.Marshal(m)
	if err != nil {
		std.Tprintf(Ldebug, "", "%s", err)
	} else {
		std.Tprintf(Ldebug, "", "%s", js[1:len(js)-1])
	}
}

// 先转换成 JSON 格式，然后打印
func JSON(m ...interface{}) {
	if v > Ldebug {
		return
	}
	js, err := json.Marshal(m)
	if err != nil {
		std.Tprintf(Ldebug, "", "%s", err)
	} else {
		std.Tprintf(Ldebug, "", "%s", js[1:len(js)-1])
	}
}
func JsonIndent(m ...interface{}) {
	if v > Ldebug {
		return
	}
	js, err := json.MarshalIndent(m, "", "    ")
	if err != nil {
		std.Tprintf(Ldebug, "", "%s", err)
	} else {
		std.Tprintf(Ldebug, "", "%s", js)
	}
}

func JSONIndent(m ...interface{}) {
	if v > Ldebug {
		return
	}
	js, err := json.MarshalIndent(m, "", "    ")
	if err != nil {
		std.Tprintf(Ldebug, "", "%s", err)
	} else {
		std.Tprintf(Ldebug, "", "%s", js)
	}
}
<|endoftext|>


<commit_before>package gou

import (
	"fmt"
	"log"
)

const (
	NOLOGGING = -1
	FATAL     = 0
	ERROR     = 1
	WARN      = 2
	INFO      = 3
	DEBUG     = 4
)

/*
https://github.com/mewkiz/pkg/tree/master/term
RED = '\033[0;1;31m'
GREEN = '\033[0;1;32m'
YELLOW = '\033[0;1;33m'
BLUE = '\033[0;1;34m'
MAGENTA = '\033[0;1;35m'
CYAN = '\033[0;1;36m'
WHITE = '\033[0;1;37m'
DARK_MAGENTA = '\033[0;35m'
ANSI_RESET = '\033[0m'
LogColor         = map[int]string{FATAL: "\033[0m\033[37m",
	ERROR: "\033[0m\033[31m",
	WARN:  "\033[0m\033[33m",
	INFO:  "\033[0m\033[32m",
	DEBUG: "\033[0m\033[34m"}

\e]PFdedede
*/

var (
	LogLevel    int = ERROR
	ErrLogLevel int = ERROR
	logger      *log.Logger
	loggerErr   *log.Logger
	logPrefix   string = ""
	LogColor           = map[int]string{FATAL: "\033[0m\033[37m",
		ERROR: "\033[0m\033[31m",
		WARN:  "\033[0m\033[33m",
		INFO:  "\033[0m\033[35m",
		DEBUG: "\033[0m\033[34m"}
	LogLevelWords map[string]int = map[string]int{"fatal": 0, "error": 1, "warn": 2, "info": 3, "debug": 4, "none": -1}
)

// you can set a logger, and log level,most common usage is:
//
//	gou.SetLogger(log.New(os.Stdout, "", log.LstdFlags), "debug")
//
//  loglevls:   debug, info, warn, error, fatal
// Note, that you can also set a seperate Error Log Level
func SetLogger(l *log.Logger, logLevel string) {
	logger = l
	LogLevelSet(logLevel)
}
func GetLogger() *log.Logger {
	return logger
}

// you can set a logger, and log level.  this is for errors, and assumes
// you are logging to Stderr (seperate from stdout above), allowing you to seperate
// debug&info logging from errors
//
//	gou.SetLogger(log.New(os.Stderr, "", log.LstdFlags), "debug")
//
//  loglevls:   debug, info, warn, error, fatal
func SetErrLogger(l *log.Logger, logLevel string) {
	loggerErr = l
	if lvl, ok := LogLevelWords[logLevel]; ok {
		ErrLogLevel = lvl
	}
}
func GetErrLogger() *log.Logger {
	return logger
}

// you can set a logger, prefix
func SetLoggerPrefix(prefix string) {
	logPrefix = prefix
}

// sets the log level from a string
func LogLevelSet(levelWord string) {
	if lvl, ok := LogLevelWords[levelWord]; ok {
		LogLevel = lvl
	}
}

// Log at debug level
func Debug(v ...interface{}) {
	if LogLevel >= 4 {
		DoLog(3, DEBUG, fmt.Sprint(v...))
	}
}

// Debug log formatted
func Debugf(format string, v ...interface{}) {
	if LogLevel >= 4 {
		DoLog(3, DEBUG, fmt.Sprintf(format, v...))
	}
}

// Log at info level
func Info(v ...interface{}) {
	if LogLevel >= 4 {
		DoLog(3, INFO, fmt.Sprint(v...))
	}
}

// info log formatted
func Infof(format string, v ...interface{}) {
	if LogLevel >= 4 {
		DoLog(3, INFO, fmt.Sprintf(format, v...))
	}
}

// Log at warn level
func Warn(v ...interface{}) {
	if LogLevel >= 4 {
		DoLog(3, WARN, fmt.Sprint(v...))
	}
}

// Debug log formatted
func Warnf(format string, v ...interface{}) {
	if LogLevel >= 4 {
		DoLog(3, WARN, fmt.Sprintf(format, v...))
	}
}

// Log at error level
func Error(v ...interface{}) {
	if LogLevel >= 4 {
		DoLog(3, ERROR, fmt.Sprint(v...))
	}
}

// Error log formatted
func Errorf(format string, v ...interface{}) {
	if LogLevel >= 4 {
		DoLog(3, ERROR, fmt.Sprintf(format, v...))
	}
}

// Log to logger if setup
//    Log(ERROR, "message")
func Log(logLvl int, v ...interface{}) {
	if LogLevel >= logLvl {
		DoLog(3, logLvl, fmt.Sprint(v...))
	}
}

// Log to logger if setup
//    Logf(ERROR, "message %d", 20)
func Logf(logLvl int, format string, v ...interface{}) {
	if LogLevel >= logLvl {
		DoLog(3, logLvl, fmt.Sprintf(format, v...))
	}
}

// Log to logger if setup
//    LogP(ERROR, "prefix", "message", anyItems, youWant)
func LogP(logLvl int, prefix string, v ...interface{}) {
	if ErrLogLevel >= logLvl && loggerErr != nil {
		loggerErr.Output(3, prefix+LogColor[logLvl]+fmt.Sprint(v...)+"\033[0m")
	} else if LogLevel >= logLvl && logger != nil {
		logger.Output(3, prefix+LogColor[logLvl]+fmt.Sprint(v...)+"\033[0m")
	}
}

// Log to logger if setup
//    LogPf(ERROR, "prefix", "formatString %s %v", anyItems, youWant)
func LogPf(logLvl int, prefix string, format string, v ...interface{}) {
	if ErrLogLevel >= logLvl && loggerErr != nil {
		loggerErr.Output(3, prefix+LogColor[logLvl]+fmt.Sprintf(format, v...)+"\033[0m")
	} else if LogLevel >= logLvl && logger != nil {
		logger.Output(3, prefix+LogColor[logLvl]+fmt.Sprintf(format, v...)+"\033[0m")
	}
}

// When you want to use the log short filename flag, and want to use
// the lower level logginf functions (say from an *Assert* type function
// you need to modify the stack depth:
//
// 	   SetLogger(log.New(os.Stderr, "", log.Ltime|log.Lshortfile|log.Lmicroseconds), lvl)
//
//     LogD(5, DEBUG, v...)
func LogD(depth int, logLvl int, v ...interface{}) {
	if LogLevel >= logLvl {
		DoLog(depth, logLvl, fmt.Sprint(v...))
	}
}

// Low level log with depth , level, message and logger
func DoLog(depth, logLvl int, msg string) {
	if ErrLogLevel >= logLvl && loggerErr != nil {
		loggerErr.Output(depth, LogColor[logLvl]+msg+"\033[0m")
	} else if LogLevel >= logLvl && logger != nil {
		logger.Output(depth, LogColor[logLvl]+msg+"\033[0m")
	}
}
<commit_msg>revamp logging to not colorize by default<commit_after>package gou

import (
	"fmt"
	"log"
	"syscall"
	"unsafe"
)

const (
	NOLOGGING = -1
	FATAL     = 0
	ERROR     = 1
	WARN      = 2
	INFO      = 3
	DEBUG     = 4
)

/*
https://github.com/mewkiz/pkg/tree/master/term
RED = '\033[0;1;31m'
GREEN = '\033[0;1;32m'
YELLOW = '\033[0;1;33m'
BLUE = '\033[0;1;34m'
MAGENTA = '\033[0;1;35m'
CYAN = '\033[0;1;36m'
WHITE = '\033[0;1;37m'
DARK_MAGENTA = '\033[0;35m'
ANSI_RESET = '\033[0m'
LogColor         = map[int]string{FATAL: "\033[0m\033[37m",
	ERROR: "\033[0m\033[31m",
	WARN:  "\033[0m\033[33m",
	INFO:  "\033[0m\033[32m",
	DEBUG: "\033[0m\033[34m"}

\e]PFdedede
*/

var (
	LogLevel    int = ERROR
	ErrLogLevel int = ERROR
	logger      *log.Logger
	loggerErr   *log.Logger
	LogColor    = map[int]string{FATAL: "\033[0m\033[37m",
		ERROR: "\033[0m\033[31m",
		WARN:  "\033[0m\033[33m",
		INFO:  "\033[0m\033[35m",
		DEBUG: "\033[0m\033[34m"}
	LogPrefix = map[int]string{
		FATAL: "[FATAL] ",
		ERROR: "[ERROR] ",
		WARN:  "[WARN] ",
		INFO:  "[INFO] ",
		DEBUG: "[DEBUG] ",
	}
	postFix                      = "\033[0m"
	LogLevelWords map[string]int = map[string]int{"fatal": 0, "error": 1, "warn": 2, "info": 3, "debug": 4, "none": -1}
)

// you can set a logger, and log level,most common usage is:
//
//	gou.SetLogger(log.New(os.Stdout, "", log.LstdFlags), "debug")
//
//  loglevls:   debug, info, warn, error, fatal
// Note, that you can also set a seperate Error Log Level
func SetLogger(l *log.Logger, logLevel string) {
	logger = l
	LogLevelSet(logLevel)
}
func GetLogger() *log.Logger {
	return logger
}

// you can set a logger, and log level.  this is for errors, and assumes
// you are logging to Stderr (seperate from stdout above), allowing you to seperate
// debug&info logging from errors
//
//	gou.SetLogger(log.New(os.Stderr, "", log.LstdFlags), "debug")
//
//  loglevls:   debug, info, warn, error, fatal
func SetErrLogger(l *log.Logger, logLevel string) {
	loggerErr = l
	if lvl, ok := LogLevelWords[logLevel]; ok {
		ErrLogLevel = lvl
	}
}
func GetErrLogger() *log.Logger {
	return logger
}

// sets the log level from a string
func LogLevelSet(levelWord string) {
	if lvl, ok := LogLevelWords[levelWord]; ok {
		LogLevel = lvl
	}
}

// Log at debug level
func Debug(v ...interface{}) {
	if LogLevel >= 4 {
		DoLog(3, DEBUG, fmt.Sprint(v...))
	}
}

// Debug log formatted
func Debugf(format string, v ...interface{}) {
	if LogLevel >= 4 {
		DoLog(3, DEBUG, fmt.Sprintf(format, v...))
	}
}

// Log at info level
func Info(v ...interface{}) {
	if LogLevel >= 4 {
		DoLog(3, INFO, fmt.Sprint(v...))
	}
}

// info log formatted
func Infof(format string, v ...interface{}) {
	if LogLevel >= 4 {
		DoLog(3, INFO, fmt.Sprintf(format, v...))
	}
}

// Log at warn level
func Warn(v ...interface{}) {
	if LogLevel >= 4 {
		DoLog(3, WARN, fmt.Sprint(v...))
	}
}

// Debug log formatted
func Warnf(format string, v ...interface{}) {
	if LogLevel >= 4 {
		DoLog(3, WARN, fmt.Sprintf(format, v...))
	}
}

// Log at error level
func Error(v ...interface{}) {
	if LogLevel >= 4 {
		DoLog(3, ERROR, fmt.Sprint(v...))
	}
}

// Error log formatted
func Errorf(format string, v ...interface{}) {
	if LogLevel >= 4 {
		DoLog(3, ERROR, fmt.Sprintf(format, v...))
	}
}

// Log to logger if setup
//    Log(ERROR, "message")
func Log(logLvl int, v ...interface{}) {
	if LogLevel >= logLvl {
		DoLog(3, logLvl, fmt.Sprint(v...))
	}
}

// Log to logger if setup
//    Logf(ERROR, "message %d", 20)
func Logf(logLvl int, format string, v ...interface{}) {
	if LogLevel >= logLvl {
		DoLog(3, logLvl, fmt.Sprintf(format, v...))
	}
}

// Log to logger if setup
//    LogP(ERROR, "prefix", "message", anyItems, youWant)
func LogP(logLvl int, prefix string, v ...interface{}) {
	if ErrLogLevel >= logLvl && loggerErr != nil {
		loggerErr.Output(3, prefix+LogPrefix[logLvl]+fmt.Sprint(v...)+postFix)
	} else if LogLevel >= logLvl && logger != nil {
		logger.Output(3, prefix+LogPrefix[logLvl]+fmt.Sprint(v...)+postFix)
	}
}

// Log to logger if setup
//    LogPf(ERROR, "prefix", "formatString %s %v", anyItems, youWant)
func LogPf(logLvl int, prefix string, format string, v ...interface{}) {
	if ErrLogLevel >= logLvl && loggerErr != nil {
		loggerErr.Output(3, prefix+LogPrefix[logLvl]+fmt.Sprintf(format, v...)+postFix)
	} else if LogLevel >= logLvl && logger != nil {
		logger.Output(3, prefix+LogPrefix[logLvl]+fmt.Sprintf(format, v...)+postFix)
	}
}

// When you want to use the log short filename flag, and want to use
// the lower level logginf functions (say from an *Assert* type function
// you need to modify the stack depth:
//
// 	   SetLogger(log.New(os.Stderr, "", log.Ltime|log.Lshortfile|log.Lmicroseconds), lvl)
//
//     LogD(5, DEBUG, v...)
func LogD(depth int, logLvl int, v ...interface{}) {
	if LogLevel >= logLvl {
		DoLog(depth, logLvl, fmt.Sprint(v...))
	}
}

// Low level log with depth , level, message and logger
func DoLog(depth, logLvl int, msg string) {
	if ErrLogLevel >= logLvl && loggerErr != nil {
		loggerErr.Output(depth, LogPrefix[logLvl]+msg+postFix)
	} else if LogLevel >= logLvl && logger != nil {
		logger.Output(depth, LogPrefix[logLvl]+msg+postFix)
	}
}

type winsize struct {
	Row    uint16
	Col    uint16
	Xpixel uint16
	Ypixel uint16
}

const (
	_TIOCGWINSZ = 0x5413 // OSX 1074295912
)

// Determine is this process is running in a Terminal or not?
func IsTerminal() bool {
	ws := &winsize{}
	retCode, _, _ := syscall.Syscall(syscall.SYS_IOCTL,
		uintptr(syscall.Stdin),
		uintptr(_TIOCGWINSZ),
		uintptr(unsafe.Pointer(ws)))

	if int(retCode) == -1 {
		return false
	}
	return true
}
<|endoftext|>


<commit_before>package gofast

import "sync/atomic"

import "github.com/bnclabs/golog"

var logok = int64(0)

// LogComponents enable logging. By default logging is disabled,
// if applications want log information from gofast components
// call this function with "self" or "all" or "gofast" argument.
func LogComponents(components ...string) {
	for _, comp := range components {
		switch comp {
		case "gofast", "self", "all":
			atomic.StoreInt64(&logok, 1)
		}
	}
}

func debugf(format string, v ...interface{}) {
	if atomic.LoadInt64(&logok) > 0 {
		log.Debugf(format, v...)
	}
}

func errorf(format string, v ...interface{}) {
	if atomic.LoadInt64(&logok) > 0 {
		log.Errorf(format, v...)
	}
}

func fatalf(format string, v ...interface{}) {
	if atomic.LoadInt64(&logok) > 0 {
		log.Fatalf(format, v...)
	}
}

func infof(format string, v ...interface{}) {
	if atomic.LoadInt64(&logok) > 0 {
		log.Infof(format, v...)
	}
}

func tracef(format string, v ...interface{}) {
	if atomic.LoadInt64(&logok) > 0 {
		log.Tracef(format, v...)
	}
}

func verbosef(format string, v ...interface{}) {
	if atomic.LoadInt64(&logok) > 0 {
		log.Verbosef(format, v...)
	}
}

func warnf(format string, v ...interface{}) {
	if atomic.LoadInt64(&logok) > 0 {
		log.Warnf(format, v...)
	}
}
<commit_msg>godoc typo.<commit_after>package gofast

import "sync/atomic"

import "github.com/bnclabs/golog"

var logok = int64(0)

// LogComponents enable logging. By default logging is disabled,
// if applications want log information for gofast components
// call this function with "self" or "all" or "gofast" as argument.
func LogComponents(components ...string) {
	for _, comp := range components {
		switch comp {
		case "gofast", "self", "all":
			atomic.StoreInt64(&logok, 1)
		}
	}
}

func debugf(format string, v ...interface{}) {
	if atomic.LoadInt64(&logok) > 0 {
		log.Debugf(format, v...)
	}
}

func errorf(format string, v ...interface{}) {
	if atomic.LoadInt64(&logok) > 0 {
		log.Errorf(format, v...)
	}
}

func fatalf(format string, v ...interface{}) {
	if atomic.LoadInt64(&logok) > 0 {
		log.Fatalf(format, v...)
	}
}

func infof(format string, v ...interface{}) {
	if atomic.LoadInt64(&logok) > 0 {
		log.Infof(format, v...)
	}
}

func tracef(format string, v ...interface{}) {
	if atomic.LoadInt64(&logok) > 0 {
		log.Tracef(format, v...)
	}
}

func verbosef(format string, v ...interface{}) {
	if atomic.LoadInt64(&logok) > 0 {
		log.Verbosef(format, v...)
	}
}

func warnf(format string, v ...interface{}) {
	if atomic.LoadInt64(&logok) > 0 {
		log.Warnf(format, v...)
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package lang

import (
	"os"

	"fmt"

	"github.com/getgauge/gauge/api"
	"github.com/getgauge/gauge/config"
	"github.com/getgauge/gauge/conn"
	gm "github.com/getgauge/gauge/gauge_messages"
	"github.com/getgauge/gauge/logger"
	"github.com/getgauge/gauge/manifest"
	"github.com/getgauge/gauge/runner"
	"github.com/getgauge/gauge/util"
)

type langRunner struct {
	runner   runner.Runner
	killChan chan bool
}

var lRunner langRunner

func startRunner() {
	lRunner.killChan = make(chan bool)
	var err error
	lRunner.runner, err = connectToRunner(lRunner.killChan)
	if err != nil {
		logger.APILog.Infof("Unable to connect to runner : %s", err.Error())
	}
}

func connectToRunner(killChan chan bool) (runner.Runner, error) {
	logger.GaugeLog.Infof("Starting language runner")
	outfile, err := os.OpenFile(logger.GetLogFile(logger.GaugeLogFileName), os.O_APPEND|os.O_WRONLY, 0600)
	if err != nil {
		logger.APILog.Infof("%s", err.Error())
		return nil, err
	}
	runner, err := api.ConnectToRunner(killChan, false, outfile)
	if err != nil {
		logger.APILog.Infof("%s", err.Error())
		return nil, err
	}
	return runner, nil
}

func cacheFileOnRunner(uri, text string) error {
	cacheFileRequest := &gm.Message{MessageType: gm.Message_CacheFileRequest, CacheFileRequest: &gm.CacheFileRequest{Content: text, FilePath: util.ConvertURItoFilePath(uri), IsClosed: false}}
	err := sendMessageToRunner(cacheFileRequest)
	return err
}

func sendMessageToRunner(cacheFileRequest *gm.Message) error {
	err := conn.WriteGaugeMessage(cacheFileRequest, lRunner.runner.Connection())
	if err != nil {
		logger.APILog.Infof("Error while connecting to runner : %s", err.Error())
	}
	return err
}

var GetResponseFromRunner = func(message *gm.Message) (*gm.Message, error) {
	return conn.GetResponseForMessageWithTimeout(message, lRunner.runner.Connection(), config.RunnerRequestTimeout())
}

func getStepPositionResponse(uri string) (*gm.StepPositionsResponse, error) {
	stepPositionsRequest := &gm.Message{MessageType: gm.Message_StepPositionsRequest, StepPositionsRequest: &gm.StepPositionsRequest{FilePath: util.ConvertURItoFilePath(uri)}}
	response, err := GetResponseFromRunner(stepPositionsRequest)
	if err != nil {
		logger.APILog.Infof("Error while connecting to runner : %s", err.Error())
		return nil, err
	}
	stepPositionsResponse := response.GetStepPositionsResponse()
	if stepPositionsResponse.GetError() != "" {
		return nil, fmt.Errorf("error while connecting to runner : %s", stepPositionsResponse.GetError())
	}
	return stepPositionsResponse, nil
}

func getAllStepsResponse() (*gm.StepNamesResponse, error) {
	getAllStepsRequest := &gm.Message{MessageType: gm.Message_StepNamesRequest, StepNamesRequest: &gm.StepNamesRequest{}}
	response, err := GetResponseFromRunner(getAllStepsRequest)
	if err != nil {
		logger.APILog.Infof("Error while connecting to runner : %s", err.Error())
		return nil, err
	}
	return response.GetStepNamesResponse(), nil
}

func killRunner() {
	if lRunner.runner != nil {
		lRunner.runner.Kill()
	}
}

func getLanugeIdetifier() (string, error) {
	m, err := manifest.ProjectManifest()
	if err != nil {
		return "", err
	}
	info, err := runner.GetRunnerInfo(m.Language)
	if err != nil {
		return "", err
	}
	return info.LspLangId, nil
}
<commit_msg>making requests only if runner exists<commit_after>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package lang

import (
	"os"

	"fmt"

	"github.com/getgauge/gauge/api"
	"github.com/getgauge/gauge/config"
	"github.com/getgauge/gauge/conn"
	gm "github.com/getgauge/gauge/gauge_messages"
	"github.com/getgauge/gauge/logger"
	"github.com/getgauge/gauge/manifest"
	"github.com/getgauge/gauge/runner"
	"github.com/getgauge/gauge/util"
)

type langRunner struct {
	runner   runner.Runner
	killChan chan bool
}

var lRunner langRunner

func startRunner() {
	lRunner.killChan = make(chan bool)
	var err error
	lRunner.runner, err = connectToRunner(lRunner.killChan)
	if err != nil {
		logger.APILog.Infof("Unable to connect to runner : %s", err.Error())
	}
}

func connectToRunner(killChan chan bool) (runner.Runner, error) {
	logger.GaugeLog.Infof("Starting language runner")
	outfile, err := os.OpenFile(logger.GetLogFile(logger.GaugeLogFileName), os.O_APPEND|os.O_WRONLY, 0600)
	if err != nil {
		logger.APILog.Infof("%s", err.Error())
		return nil, err
	}
	runner, err := api.ConnectToRunner(killChan, false, outfile)
	if err != nil {
		logger.APILog.Infof("%s", err.Error())
		return nil, err
	}
	return runner, nil
}

func cacheFileOnRunner(uri, text string) error {
	cacheFileRequest := &gm.Message{MessageType: gm.Message_CacheFileRequest, CacheFileRequest: &gm.CacheFileRequest{Content: text, FilePath: util.ConvertURItoFilePath(uri), IsClosed: false}}
	err := sendMessageToRunner(cacheFileRequest)
	return err
}

func sendMessageToRunner(cacheFileRequest *gm.Message) error {
	err := conn.WriteGaugeMessage(cacheFileRequest, lRunner.runner.Connection())
	if err != nil {
		logger.APILog.Infof("Error while connecting to runner : %s", err.Error())
	}
	return err
}

var GetResponseFromRunner = func(message *gm.Message) (*gm.Message, error) {
	if lRunner.runner == nil {
		return nil, fmt.Errorf("Error while connecting to runner")
	}
	return conn.GetResponseForMessageWithTimeout(message, lRunner.runner.Connection(), config.RunnerRequestTimeout())
}

func getStepPositionResponse(uri string) (*gm.StepPositionsResponse, error) {
	stepPositionsRequest := &gm.Message{MessageType: gm.Message_StepPositionsRequest, StepPositionsRequest: &gm.StepPositionsRequest{FilePath: util.ConvertURItoFilePath(uri)}}
	response, err := GetResponseFromRunner(stepPositionsRequest)
	if err != nil {
		logger.APILog.Infof("Error while connecting to runner : %s", err.Error())
		return nil, err
	}
	stepPositionsResponse := response.GetStepPositionsResponse()
	if stepPositionsResponse.GetError() != "" {
		return nil, fmt.Errorf("error while connecting to runner : %s", stepPositionsResponse.GetError())
	}
	return stepPositionsResponse, nil
}

func getAllStepsResponse() (*gm.StepNamesResponse, error) {
	getAllStepsRequest := &gm.Message{MessageType: gm.Message_StepNamesRequest, StepNamesRequest: &gm.StepNamesRequest{}}
	response, err := GetResponseFromRunner(getAllStepsRequest)
	if err != nil {
		logger.APILog.Infof("Error while connecting to runner : %s", err.Error())
		return nil, err
	}
	return response.GetStepNamesResponse(), nil
}

func killRunner() {
	if lRunner.runner != nil {
		lRunner.runner.Kill()
	}
}

func getLanugeIdetifier() (string, error) {
	m, err := manifest.ProjectManifest()
	if err != nil {
		return "", err
	}
	info, err := runner.GetRunnerInfo(m.Language)
	if err != nil {
		return "", err
	}
	return info.LspLangId, nil
}
<|endoftext|>


<commit_before>package discovery

import (
	"crypto/rand"
	"encoding/hex"
	"encoding/json"
	"io/ioutil"
	"log"
	"time"

	"github.com/newrelic/bosun/healthy"
	"github.com/newrelic/bosun/service"
)

type Target struct {
	Service service.Service
	Check healthy.Check
}

type StaticDiscovery struct {
	ServiceList []*Target
}

func (d *StaticDiscovery) Services() []service.Service {
	return nil
}

func (d *StaticDiscovery) Run(quit chan bool) {

}

func (d *StaticDiscovery) ParseConfig(filename string) ([]Target, error) {
	file, err := ioutil.ReadFile(filename)
	if err != nil {
		log.Printf("Unable to read announcements file: '%s!'", err.Error())
		return nil, err
	}

	var targets []Target
	json.Unmarshal(file, &targets)

	// Have to loop with traditional for loop so we can modify entries
	for i := 0; i < len(targets); i++ {
		idBytes, err := RandomHex(14)
		if err != nil {
			log.Printf("ParseConfig(): Unable to get random bytes (%s)", err.Error())
			return nil, err
		}

		targets[i].Service.ID = string(idBytes)
		targets[i].Service.Created = time.Now().UTC()
		targets[i].Check.ID = string(idBytes)
		log.Printf("Discovered service: %s, ID: %s\n",
			targets[i].Service.Name,
			targets[i].Service.ID,
		)
	}
	return targets, nil
}

// Return a defined number of random bytes as a slice
func RandomHex(count int) ([]byte, error) {
	raw := make([]byte, count)
	_, err := rand.Read(raw)
	if err != nil {
		log.Printf("RandomBytes(): Error ", err)
		return nil, err
	}

	encoded := make([]byte, count * 2)
	hex.Encode(encoded, raw)
	return encoded, nil
}
<commit_msg>A little commentary.<commit_after>package discovery

import (
	"crypto/rand"
	"encoding/hex"
	"encoding/json"
	"io/ioutil"
	"log"
	"time"

	"github.com/newrelic/bosun/healthy"
	"github.com/newrelic/bosun/service"
)

type Target struct {
	Service service.Service
	Check healthy.Check
}

type StaticDiscovery struct {
	ServiceList []*Target
}

func (d *StaticDiscovery) Services() []service.Service {
	return nil
}

func (d *StaticDiscovery) Run(quit chan bool) {

}

// Parses a JSON config file containing an array of Targets. These are
// then augmented with a random hex ID and stamped with the current
// UTC time as the creation time. The same hex ID is applied to the Check
// and the Service to make sure that they are matched by the healthy
// package later on.
func (d *StaticDiscovery) ParseConfig(filename string) ([]Target, error) {
	file, err := ioutil.ReadFile(filename)
	if err != nil {
		log.Printf("Unable to read announcements file: '%s!'", err.Error())
		return nil, err
	}

	var targets []Target
	json.Unmarshal(file, &targets)

	// Have to loop with traditional 'for' loop so we can modify entries
	for i := 0; i < len(targets); i++ {
		idBytes, err := RandomHex(14)
		if err != nil {
			log.Printf("ParseConfig(): Unable to get random bytes (%s)", err.Error())
			return nil, err
		}

		targets[i].Service.ID = string(idBytes)
		targets[i].Service.Created = time.Now().UTC()
		targets[i].Check.ID = string(idBytes)
		log.Printf("Discovered service: %s, ID: %s\n",
			targets[i].Service.Name,
			targets[i].Service.ID,
		)
	}
	return targets, nil
}

// Return a defined number of random bytes as a slice
func RandomHex(count int) ([]byte, error) {
	raw := make([]byte, count)
	_, err := rand.Read(raw)
	if err != nil {
		log.Printf("RandomBytes(): Error ", err)
		return nil, err
	}

	encoded := make([]byte, count * 2)
	hex.Encode(encoded, raw)
	return encoded, nil
}
<|endoftext|>


<commit_before>// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package workloadidentitybinding

import (
	"context"
	"fmt"

	"github.com/GoogleContainerTools/kpt/porch/controllers/remoterootsync/pkg/applyset"
	api "github.com/GoogleContainerTools/kpt/porch/controllers/workloadidentitybinding/api/v1alpha1"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/client-go/dynamic"
	"k8s.io/klog/v2"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

// WorkloadIdentityBindingReconciler reconciles WorkloadIdentityBinding objects
type WorkloadIdentityBindingReconciler struct {
	client.Client
	// Scheme *runtime.Scheme

	dynamicClient dynamic.Interface
	restMapper    meta.RESTMapper
}

//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=workloadidentitybindings,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=workloadidentitybindings/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=workloadidentitybindings/finalizers,verbs=update

// Reconcile implements the main kubernetes reconciliation loop.
func (r *WorkloadIdentityBindingReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
	var subject api.WorkloadIdentityBinding
	if err := r.Get(ctx, req.NamespacedName, &subject); err != nil {
		return ctrl.Result{}, client.IgnoreNotFound(err)
	}
	// myFinalizerName := "config.porch.kpt.dev/finalizer"
	// if subject.ObjectMeta.DeletionTimestamp.IsZero() {
	// 	// The object is not being deleted, so if it does not have our finalizer,
	// 	// then lets add the finalizer and update the object. This is equivalent
	// 	// registering our finalizer.
	// 	if !controllerutil.ContainsFinalizer(&subject, myFinalizerName) {
	// 		controllerutil.AddFinalizer(&subject, myFinalizerName)
	// 		if err := r.Update(ctx, &subject); err != nil {
	// 			return ctrl.Result{}, err
	// 		}
	// 	}
	// } else {
	// 	// The object is being deleted
	// 	if controllerutil.ContainsFinalizer(&subject, myFinalizerName) {
	// 		// // our finalizer is present, so lets handle any external dependency
	// 		// if err := r.deleteExternalResources(ctx, &subject); err != nil {
	// 		// 	// if fail to delete the external dependency here, return with error
	// 		// 	// so that it can be retried
	// 		// 	return ctrl.Result{}, fmt.Errorf("have problem to delete external resource: %w", err)
	// 		// }
	// 		// remove our finalizer from the list and update it.
	// 		controllerutil.RemoveFinalizer(&subject, myFinalizerName)
	// 		if err := r.Update(ctx, &subject); err != nil {
	// 			return ctrl.Result{}, fmt.Errorf("failed to update %s after delete finalizer: %w", req.Name, err)
	// 		}
	// 	}
	// 	// Stop reconciliation as the item is being deleted
	// 	return ctrl.Result{}, nil
	// }

	var result ctrl.Result

	results, err := r.applyToClusterRef(ctx, &subject)
	if updateStatus(&subject, results, err) {
		if updateErr := r.Status().Update(ctx, &subject); updateErr != nil {
			if err == nil {
				return result, updateErr
			}
		}
	}

	if err != nil {
		klog.Warningf("error during apply: %v", err)
		// TODO: Post event
		return result, err
	}
	if results != nil && !(results.AllApplied() && results.AllHealthy()) {
		result.Requeue = true
	}

	return result, nil
}

func updateStatus(subject *api.WorkloadIdentityBinding, results *applyset.ApplyResults, err error) bool {
	conditions := &subject.Status.Conditions
	if err == nil {
		meta.SetStatusCondition(conditions, metav1.Condition{Type: "Ready", Status: metav1.ConditionTrue, Reason: "Ready"})
	} else {
		meta.SetStatusCondition(conditions, metav1.Condition{Type: "Ready", Status: metav1.ConditionFalse, Reason: "Error"})
	}

	// TODO: Check apply results and think about status conditions

	return true
}

func (r *WorkloadIdentityBindingReconciler) applyToClusterRef(ctx context.Context, subject *api.WorkloadIdentityBinding) (*applyset.ApplyResults, error) {

	ns := &corev1.Namespace{}
	if err := r.Get(ctx, types.NamespacedName{Name: subject.GetNamespace()}, ns); err != nil {
		return nil, fmt.Errorf("error getting namespace %q: %w", subject.GetNamespace(), err)
	}

	objects, err := r.BuildObjectsToApply(ctx, ns, subject)
	if err != nil {
		return nil, err
	}

	// TODO: Cache applyset?
	patchOptions := metav1.PatchOptions{
		FieldManager: subject.GetObjectKind().GroupVersionKind().Kind + "-" + subject.GetNamespace() + "-" + subject.GetName(),
	}

	// We force to overcome errors like: Apply failed with 1 conflict: conflict with "kubectl-client-side-apply" using apps/v1: .spec.template.spec.containers[name="porch-server"].image
	// TODO: How to handle this better
	force := true
	patchOptions.Force = &force

	applyset, err := applyset.New(applyset.Options{
		RESTMapper:   r.restMapper,
		Client:       r.dynamicClient,
		PatchOptions: patchOptions,
	})
	if err != nil {
		return nil, err
	}

	if err := applyset.ReplaceAllObjects(objects); err != nil {
		return nil, err
	}

	results, err := applyset.ApplyOnce(ctx)
	if err != nil {
		return nil, fmt.Errorf("failed to apply: %w", err)
	}

	return results, nil
}

func (r *WorkloadIdentityBindingReconciler) BuildObjectsToApply(ctx context.Context, ns *corev1.Namespace, subject *api.WorkloadIdentityBinding) ([]applyset.ApplyableObject, error) {
	var objects []applyset.ApplyableObject

	{
		u := &unstructured.Unstructured{}
		u.SetAPIVersion("iam.cnrm.cloud.google.com/v1beta1")
		u.SetKind("IAMPolicyMember")
		u.SetName("workloadidentitybinding-" + subject.GetName())
		u.SetNamespace(subject.GetNamespace())

		saRef := subject.Spec.ServiceAccountRef

		saNamespace := saRef.Namespace
		saName := saRef.Name
		if saNamespace == "" {
			saNamespace = subject.GetNamespace()
		}

		parentProjectID := ns.GetAnnotations()["cnrm.cloud.google.com/project-id"]
		if parentProjectID == "" {
			return nil, fmt.Errorf("project-id not found for namespace %q", ns.GetName())
		}
		member := "serviceAccount:" + parentProjectID + ".svc.id.goog[" + saNamespace + "/" + saName + "]"

		u.Object["spec"] = map[string]interface{}{
			"member":      member,
			"role":        "roles/iam.workloadIdentityUser",
			"resourceRef": subject.Spec.ResourceRef,
		}

		objects = append(objects, u)
	}

	for _, obj := range objects {
		ownerRefs := obj.GetOwnerReferences()

		controller := true
		ownerRefs = append(ownerRefs, metav1.OwnerReference{
			APIVersion: subject.APIVersion,
			Kind:       subject.Kind,
			Name:       subject.GetName(),
			UID:        subject.GetUID(),
			Controller: &controller,
		})
		obj.SetOwnerReferences(ownerRefs)
	}
	return objects, nil
}

// SetupWithManager sets up the controller with the Manager.
func (r *WorkloadIdentityBindingReconciler) SetupWithManager(mgr ctrl.Manager) error {
	if err := api.AddToScheme(mgr.GetScheme()); err != nil {
		return err
	}

	r.Client = mgr.GetClient()

	if err := ctrl.NewControllerManagedBy(mgr).
		For(&api.WorkloadIdentityBinding{}).
		Complete(r); err != nil {
		return err
	}

	restConfig := mgr.GetConfig()

	client, err := dynamic.NewForConfig(restConfig)
	if err != nil {
		return fmt.Errorf("failed to create a new dynamic client: %w", err)
	}
	r.dynamicClient = client

	r.restMapper = mgr.GetRESTMapper()

	return nil
}
<commit_msg>WorkloadIdentityBinding: better surface status.conditions (#3486)<commit_after>// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package workloadidentitybinding

import (
	"context"
	"fmt"

	"github.com/GoogleContainerTools/kpt/porch/controllers/remoterootsync/pkg/applyset"
	api "github.com/GoogleContainerTools/kpt/porch/controllers/workloadidentitybinding/api/v1alpha1"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/client-go/dynamic"
	"k8s.io/klog/v2"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

// WorkloadIdentityBindingReconciler reconciles WorkloadIdentityBinding objects
type WorkloadIdentityBindingReconciler struct {
	client.Client
	// Scheme *runtime.Scheme

	dynamicClient dynamic.Interface
	restMapper    meta.RESTMapper
}

//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=workloadidentitybindings,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=workloadidentitybindings/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=workloadidentitybindings/finalizers,verbs=update

// Reconcile implements the main kubernetes reconciliation loop.
func (r *WorkloadIdentityBindingReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
	var subject api.WorkloadIdentityBinding
	if err := r.Get(ctx, req.NamespacedName, &subject); err != nil {
		return ctrl.Result{}, client.IgnoreNotFound(err)
	}
	// myFinalizerName := "config.porch.kpt.dev/finalizer"
	// if subject.ObjectMeta.DeletionTimestamp.IsZero() {
	// 	// The object is not being deleted, so if it does not have our finalizer,
	// 	// then lets add the finalizer and update the object. This is equivalent
	// 	// registering our finalizer.
	// 	if !controllerutil.ContainsFinalizer(&subject, myFinalizerName) {
	// 		controllerutil.AddFinalizer(&subject, myFinalizerName)
	// 		if err := r.Update(ctx, &subject); err != nil {
	// 			return ctrl.Result{}, err
	// 		}
	// 	}
	// } else {
	// 	// The object is being deleted
	// 	if controllerutil.ContainsFinalizer(&subject, myFinalizerName) {
	// 		// // our finalizer is present, so lets handle any external dependency
	// 		// if err := r.deleteExternalResources(ctx, &subject); err != nil {
	// 		// 	// if fail to delete the external dependency here, return with error
	// 		// 	// so that it can be retried
	// 		// 	return ctrl.Result{}, fmt.Errorf("have problem to delete external resource: %w", err)
	// 		// }
	// 		// remove our finalizer from the list and update it.
	// 		controllerutil.RemoveFinalizer(&subject, myFinalizerName)
	// 		if err := r.Update(ctx, &subject); err != nil {
	// 			return ctrl.Result{}, fmt.Errorf("failed to update %s after delete finalizer: %w", req.Name, err)
	// 		}
	// 	}
	// 	// Stop reconciliation as the item is being deleted
	// 	return ctrl.Result{}, nil
	// }

	var result ctrl.Result

	results, err := r.applyToClusterRef(ctx, &subject)
	if updateStatus(&subject, results, err) {
		if updateErr := r.Status().Update(ctx, &subject); updateErr != nil {
			if err == nil {
				return result, updateErr
			}
		}
	}

	if err != nil {
		klog.Warningf("error during apply: %v", err)
		// TODO: Post event
		return result, err
	}
	if results != nil && !(results.AllApplied() && results.AllHealthy()) {
		result.Requeue = true
	}

	return result, nil
}

func updateStatus(subject *api.WorkloadIdentityBinding, results *applyset.ApplyResults, err error) bool {
	conditions := &subject.Status.Conditions
	if err != nil {
		meta.SetStatusCondition(conditions, metav1.Condition{Type: "Ready", Status: metav1.ConditionFalse, Reason: "Error"})
	} else if !results.AllApplied() {
		meta.SetStatusCondition(conditions, metav1.Condition{Type: "Ready", Status: metav1.ConditionFalse, Reason: "ApplyInProgress"})
	} else if !results.AllHealthy() {
		meta.SetStatusCondition(conditions, metav1.Condition{Type: "Ready", Status: metav1.ConditionFalse, Reason: "NotHealthy"})
	} else {
		meta.SetStatusCondition(conditions, metav1.Condition{Type: "Ready", Status: metav1.ConditionTrue, Reason: "Ready"})
	}

	// TODO: Check apply results and think about status conditions

	return true
}

func (r *WorkloadIdentityBindingReconciler) applyToClusterRef(ctx context.Context, subject *api.WorkloadIdentityBinding) (*applyset.ApplyResults, error) {

	ns := &corev1.Namespace{}
	if err := r.Get(ctx, types.NamespacedName{Name: subject.GetNamespace()}, ns); err != nil {
		return nil, fmt.Errorf("error getting namespace %q: %w", subject.GetNamespace(), err)
	}

	objects, err := r.BuildObjectsToApply(ctx, ns, subject)
	if err != nil {
		return nil, err
	}

	// TODO: Cache applyset?
	patchOptions := metav1.PatchOptions{
		FieldManager: subject.GetObjectKind().GroupVersionKind().Kind + "-" + subject.GetNamespace() + "-" + subject.GetName(),
	}

	// We force to overcome errors like: Apply failed with 1 conflict: conflict with "kubectl-client-side-apply" using apps/v1: .spec.template.spec.containers[name="porch-server"].image
	// TODO: How to handle this better
	force := true
	patchOptions.Force = &force

	applyset, err := applyset.New(applyset.Options{
		RESTMapper:   r.restMapper,
		Client:       r.dynamicClient,
		PatchOptions: patchOptions,
	})
	if err != nil {
		return nil, err
	}

	if err := applyset.ReplaceAllObjects(objects); err != nil {
		return nil, err
	}

	results, err := applyset.ApplyOnce(ctx)
	if err != nil {
		return nil, fmt.Errorf("failed to apply: %w", err)
	}

	return results, nil
}

func (r *WorkloadIdentityBindingReconciler) BuildObjectsToApply(ctx context.Context, ns *corev1.Namespace, subject *api.WorkloadIdentityBinding) ([]applyset.ApplyableObject, error) {
	var objects []applyset.ApplyableObject

	{
		u := &unstructured.Unstructured{}
		u.SetAPIVersion("iam.cnrm.cloud.google.com/v1beta1")
		u.SetKind("IAMPolicyMember")
		u.SetName("workloadidentitybinding-" + subject.GetName())
		u.SetNamespace(subject.GetNamespace())

		saRef := subject.Spec.ServiceAccountRef

		saNamespace := saRef.Namespace
		saName := saRef.Name
		if saNamespace == "" {
			saNamespace = subject.GetNamespace()
		}

		parentProjectID := ns.GetAnnotations()["cnrm.cloud.google.com/project-id"]
		if parentProjectID == "" {
			return nil, fmt.Errorf("project-id not found for namespace %q", ns.GetName())
		}
		member := "serviceAccount:" + parentProjectID + ".svc.id.goog[" + saNamespace + "/" + saName + "]"

		u.Object["spec"] = map[string]interface{}{
			"member":      member,
			"role":        "roles/iam.workloadIdentityUser",
			"resourceRef": subject.Spec.ResourceRef,
		}

		objects = append(objects, u)
	}

	for _, obj := range objects {
		ownerRefs := obj.GetOwnerReferences()

		controller := true
		ownerRefs = append(ownerRefs, metav1.OwnerReference{
			APIVersion: subject.APIVersion,
			Kind:       subject.Kind,
			Name:       subject.GetName(),
			UID:        subject.GetUID(),
			Controller: &controller,
		})
		obj.SetOwnerReferences(ownerRefs)
	}
	return objects, nil
}

// SetupWithManager sets up the controller with the Manager.
func (r *WorkloadIdentityBindingReconciler) SetupWithManager(mgr ctrl.Manager) error {
	if err := api.AddToScheme(mgr.GetScheme()); err != nil {
		return err
	}

	r.Client = mgr.GetClient()

	if err := ctrl.NewControllerManagedBy(mgr).
		For(&api.WorkloadIdentityBinding{}).
		Complete(r); err != nil {
		return err
	}

	restConfig := mgr.GetConfig()

	client, err := dynamic.NewForConfig(restConfig)
	if err != nil {
		return fmt.Errorf("failed to create a new dynamic client: %w", err)
	}
	r.dynamicClient = client

	r.restMapper = mgr.GetRESTMapper()

	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2019 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 flowcontrol

import (
	"fmt"
	"io"
	"net/http"
	"strconv"
	"strings"
	"text/tabwriter"
	"time"

	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/apiserver/pkg/server/mux"
)

const (
	queryIncludeRequestDetails = "includeRequestDetails"
)

func (cfgCtlr *configController) Install(c *mux.PathRecorderMux) {
	// TODO(yue9944882): handle "Accept" header properly
	// debugging dumps a CSV content for three levels of granularity
	// 1. row per priority-level
	c.UnlistedHandleFunc("/debug/api_priority_and_fairness/dump_priority_levels", cfgCtlr.dumpPriorityLevels)
	// 2. row per queue
	c.UnlistedHandleFunc("/debug/api_priority_and_fairness/dump_queues", cfgCtlr.dumpQueues)
	// 3. row per request
	c.UnlistedHandleFunc("/debug/api_priority_and_fairness/dump_requests", cfgCtlr.dumpRequests)
}

func (cfgCtlr *configController) dumpPriorityLevels(w http.ResponseWriter, r *http.Request) {
	cfgCtlr.lock.Lock()
	defer cfgCtlr.lock.Unlock()
	tabWriter := tabwriter.NewWriter(w, 8, 0, 1, ' ', 0)
	columnHeaders := []string{
		"PriorityLevelName", // 1
		"ActiveQueues",      // 2
		"IsIdle",            // 3
		"IsQuiescing",       // 4
		"WaitingRequests",   // 5
		"ExecutingRequests", // 6
	}
	tabPrint(tabWriter, rowForHeaders(columnHeaders))
	endLine(tabWriter)
	for _, plState := range cfgCtlr.priorityLevelStates {
		if plState.queues == nil {
			tabPrint(tabWriter, row(
				plState.pl.Name, // 1
				"<none>",        // 2
				"<none>",        // 3
				"<none>",        // 4
				"<none>",        // 5
				"<none>",        // 6
			))
			endLine(tabWriter)
			continue
		}
		queueSetDigest := plState.queues.Dump(false)
		activeQueueNum := 0
		for _, q := range queueSetDigest.Queues {
			if len(q.Requests) > 0 {
				activeQueueNum++
			}
		}

		tabPrint(tabWriter, rowForPriorityLevel(
			plState.pl.Name,          // 1
			activeQueueNum,           // 2
			plState.queues.IsIdle(),  // 3
			plState.quiescing,        // 4
			queueSetDigest.Waiting,   // 5
			queueSetDigest.Executing, // 6
		))
		endLine(tabWriter)
	}
	runtime.HandleError(tabWriter.Flush())
}

func (cfgCtlr *configController) dumpQueues(w http.ResponseWriter, r *http.Request) {
	cfgCtlr.lock.Lock()
	defer cfgCtlr.lock.Unlock()
	tabWriter := tabwriter.NewWriter(w, 8, 0, 1, ' ', 0)
	columnHeaders := []string{
		"PriorityLevelName", // 1
		"Index",             // 2
		"PendingRequests",   // 3
		"ExecutingRequests", // 4
		"VirtualStart",      // 5
	}
	tabPrint(tabWriter, rowForHeaders(columnHeaders))
	endLine(tabWriter)
	for _, plState := range cfgCtlr.priorityLevelStates {
		if plState.queues == nil {
			tabPrint(tabWriter, row(
				plState.pl.Name, // 1
				"<none>",        // 2
				"<none>",        // 3
				"<none>",        // 4
				"<none>",        // 5
			))
			endLine(tabWriter)
			continue
		}
		queueSetDigest := plState.queues.Dump(false)
		for i, q := range queueSetDigest.Queues {
			tabPrint(tabWriter, rowForQueue(
				plState.pl.Name,     // 1
				i,                   // 2
				len(q.Requests),     // 3
				q.ExecutingRequests, // 4
				q.VirtualStart,      // 5
			))
			endLine(tabWriter)
		}
	}
	runtime.HandleError(tabWriter.Flush())
}

func (cfgCtlr *configController) dumpRequests(w http.ResponseWriter, r *http.Request) {
	cfgCtlr.lock.Lock()
	defer cfgCtlr.lock.Unlock()

	includeRequestDetails := len(r.URL.Query().Get(queryIncludeRequestDetails)) > 0

	tabWriter := tabwriter.NewWriter(w, 8, 0, 1, ' ', 0)
	tabPrint(tabWriter, rowForHeaders([]string{
		"PriorityLevelName",   // 1
		"FlowSchemaName",      // 2
		"QueueIndex",          // 3
		"RequestIndexInQueue", // 4
		"FlowDistingsher",     // 5
		"ArriveTime",          // 6
	}))
	if includeRequestDetails {
		continueLine(tabWriter)
		tabPrint(tabWriter, rowForHeaders([]string{
			"UserName",    // 7
			"Verb",        // 8
			"APIPath",     // 9
			"Namespace",   // 10
			"Name",        // 11
			"APIVersion",  // 12
			"Resource",    // 13
			"SubResource", // 14
		}))
	}
	endLine(tabWriter)
	for _, plState := range cfgCtlr.priorityLevelStates {
		if plState.queues == nil {
			tabPrint(tabWriter, row(
				plState.pl.Name, // 1
				"<none>",        // 2
				"<none>",        // 3
				"<none>",        // 4
				"<none>",        // 5
				"<none>",        // 6
			))
			if includeRequestDetails {
				continueLine(tabWriter)
				tabPrint(tabWriter, row(
					"<none>", // 7
					"<none>", // 8
					"<none>", // 9
					"<none>", // 10
					"<none>", // 11
					"<none>", // 12
					"<none>", // 13
					"<none>", // 14
				))
			}
			endLine(tabWriter)
			continue
		}
		queueSetDigest := plState.queues.Dump(includeRequestDetails)
		for iq, q := range queueSetDigest.Queues {
			for ir, r := range q.Requests {
				tabPrint(tabWriter, rowForRequest(
					plState.pl.Name,     // 1
					r.MatchedFlowSchema, // 2
					iq,                  // 3
					ir,                  // 4
					r.FlowDistinguisher, // 5
					r.ArriveTime,        // 6
				))
				if includeRequestDetails {
					continueLine(tabWriter)
					tabPrint(tabWriter, rowForRequestDetails(
						r.UserName,              // 7
						r.RequestInfo.Verb,      // 8
						r.RequestInfo.Path,      // 9
						r.RequestInfo.Namespace, // 10
						r.RequestInfo.Name,      // 11
						schema.GroupVersion{
							Group:   r.RequestInfo.APIGroup,
							Version: r.RequestInfo.APIVersion,
						}.String(), // 12
						r.RequestInfo.Resource,    // 13
						r.RequestInfo.Subresource, // 14
					))
				}
				endLine(tabWriter)
			}
		}
	}
	runtime.HandleError(tabWriter.Flush())
}

func tabPrint(w io.Writer, row string) {
	_, err := fmt.Fprint(w, row)
	runtime.HandleError(err)
}

func continueLine(w io.Writer) {
	_, err := fmt.Fprint(w, ",\t")
	runtime.HandleError(err)
}
func endLine(w io.Writer) {
	_, err := fmt.Fprint(w, "\n")
	runtime.HandleError(err)
}

func rowForHeaders(headers []string) string {
	return row(headers...)
}

func rowForPriorityLevel(plName string, activeQueues int, isIdle, isQuiescing bool, waitingRequests, executingRequests int) string {
	return row(
		plName,
		strconv.Itoa(activeQueues),
		strconv.FormatBool(isIdle),
		strconv.FormatBool(isQuiescing),
		strconv.Itoa(waitingRequests),
		strconv.Itoa(executingRequests),
	)
}

func rowForQueue(plName string, index, waitingRequests, executingRequests int, virtualStart float64) string {
	return row(
		plName,
		strconv.Itoa(index),
		strconv.Itoa(waitingRequests),
		strconv.Itoa(executingRequests),
		fmt.Sprintf("%.4f", virtualStart),
	)
}

func rowForRequest(plName, fsName string, queueIndex, requestIndex int, flowDistinguisher string, arriveTime time.Time) string {
	return row(
		plName,
		fsName,
		strconv.Itoa(queueIndex),
		strconv.Itoa(requestIndex),
		flowDistinguisher,
		arriveTime.UTC().Format(time.RFC3339Nano),
	)
}

func rowForRequestDetails(username, verb, path, namespace, name, apiVersion, resource, subResource string) string {
	return row(
		username,
		verb,
		path,
		namespace,
		name,
		apiVersion,
		resource,
		subResource,
	)
}

func row(columns ...string) string {
	return strings.Join(columns, ",\t")
}
<commit_msg>Remove phantoms from dump_requests output<commit_after>/*
Copyright 2019 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 flowcontrol

import (
	"fmt"
	"io"
	"net/http"
	"strconv"
	"strings"
	"text/tabwriter"
	"time"

	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/apiserver/pkg/server/mux"
)

const (
	queryIncludeRequestDetails = "includeRequestDetails"
)

func (cfgCtlr *configController) Install(c *mux.PathRecorderMux) {
	// TODO(yue9944882): handle "Accept" header properly
	// debugging dumps a CSV content for three levels of granularity
	// 1. row per priority-level
	c.UnlistedHandleFunc("/debug/api_priority_and_fairness/dump_priority_levels", cfgCtlr.dumpPriorityLevels)
	// 2. row per queue
	c.UnlistedHandleFunc("/debug/api_priority_and_fairness/dump_queues", cfgCtlr.dumpQueues)
	// 3. row per request
	c.UnlistedHandleFunc("/debug/api_priority_and_fairness/dump_requests", cfgCtlr.dumpRequests)
}

func (cfgCtlr *configController) dumpPriorityLevels(w http.ResponseWriter, r *http.Request) {
	cfgCtlr.lock.Lock()
	defer cfgCtlr.lock.Unlock()
	tabWriter := tabwriter.NewWriter(w, 8, 0, 1, ' ', 0)
	columnHeaders := []string{
		"PriorityLevelName", // 1
		"ActiveQueues",      // 2
		"IsIdle",            // 3
		"IsQuiescing",       // 4
		"WaitingRequests",   // 5
		"ExecutingRequests", // 6
	}
	tabPrint(tabWriter, rowForHeaders(columnHeaders))
	endLine(tabWriter)
	for _, plState := range cfgCtlr.priorityLevelStates {
		if plState.queues == nil {
			tabPrint(tabWriter, row(
				plState.pl.Name, // 1
				"<none>",        // 2
				"<none>",        // 3
				"<none>",        // 4
				"<none>",        // 5
				"<none>",        // 6
			))
			endLine(tabWriter)
			continue
		}
		queueSetDigest := plState.queues.Dump(false)
		activeQueueNum := 0
		for _, q := range queueSetDigest.Queues {
			if len(q.Requests) > 0 {
				activeQueueNum++
			}
		}

		tabPrint(tabWriter, rowForPriorityLevel(
			plState.pl.Name,          // 1
			activeQueueNum,           // 2
			plState.queues.IsIdle(),  // 3
			plState.quiescing,        // 4
			queueSetDigest.Waiting,   // 5
			queueSetDigest.Executing, // 6
		))
		endLine(tabWriter)
	}
	runtime.HandleError(tabWriter.Flush())
}

func (cfgCtlr *configController) dumpQueues(w http.ResponseWriter, r *http.Request) {
	cfgCtlr.lock.Lock()
	defer cfgCtlr.lock.Unlock()
	tabWriter := tabwriter.NewWriter(w, 8, 0, 1, ' ', 0)
	columnHeaders := []string{
		"PriorityLevelName", // 1
		"Index",             // 2
		"PendingRequests",   // 3
		"ExecutingRequests", // 4
		"VirtualStart",      // 5
	}
	tabPrint(tabWriter, rowForHeaders(columnHeaders))
	endLine(tabWriter)
	for _, plState := range cfgCtlr.priorityLevelStates {
		if plState.queues == nil {
			tabPrint(tabWriter, row(
				plState.pl.Name, // 1
				"<none>",        // 2
				"<none>",        // 3
				"<none>",        // 4
				"<none>",        // 5
			))
			endLine(tabWriter)
			continue
		}
		queueSetDigest := plState.queues.Dump(false)
		for i, q := range queueSetDigest.Queues {
			tabPrint(tabWriter, rowForQueue(
				plState.pl.Name,     // 1
				i,                   // 2
				len(q.Requests),     // 3
				q.ExecutingRequests, // 4
				q.VirtualStart,      // 5
			))
			endLine(tabWriter)
		}
	}
	runtime.HandleError(tabWriter.Flush())
}

func (cfgCtlr *configController) dumpRequests(w http.ResponseWriter, r *http.Request) {
	cfgCtlr.lock.Lock()
	defer cfgCtlr.lock.Unlock()

	includeRequestDetails := len(r.URL.Query().Get(queryIncludeRequestDetails)) > 0

	tabWriter := tabwriter.NewWriter(w, 8, 0, 1, ' ', 0)
	tabPrint(tabWriter, rowForHeaders([]string{
		"PriorityLevelName",   // 1
		"FlowSchemaName",      // 2
		"QueueIndex",          // 3
		"RequestIndexInQueue", // 4
		"FlowDistingsher",     // 5
		"ArriveTime",          // 6
	}))
	if includeRequestDetails {
		continueLine(tabWriter)
		tabPrint(tabWriter, rowForHeaders([]string{
			"UserName",    // 7
			"Verb",        // 8
			"APIPath",     // 9
			"Namespace",   // 10
			"Name",        // 11
			"APIVersion",  // 12
			"Resource",    // 13
			"SubResource", // 14
		}))
	}
	endLine(tabWriter)
	for _, plState := range cfgCtlr.priorityLevelStates {
		if plState.queues == nil {
			continue
		}
		queueSetDigest := plState.queues.Dump(includeRequestDetails)
		for iq, q := range queueSetDigest.Queues {
			for ir, r := range q.Requests {
				tabPrint(tabWriter, rowForRequest(
					plState.pl.Name,     // 1
					r.MatchedFlowSchema, // 2
					iq,                  // 3
					ir,                  // 4
					r.FlowDistinguisher, // 5
					r.ArriveTime,        // 6
				))
				if includeRequestDetails {
					continueLine(tabWriter)
					tabPrint(tabWriter, rowForRequestDetails(
						r.UserName,              // 7
						r.RequestInfo.Verb,      // 8
						r.RequestInfo.Path,      // 9
						r.RequestInfo.Namespace, // 10
						r.RequestInfo.Name,      // 11
						schema.GroupVersion{
							Group:   r.RequestInfo.APIGroup,
							Version: r.RequestInfo.APIVersion,
						}.String(), // 12
						r.RequestInfo.Resource,    // 13
						r.RequestInfo.Subresource, // 14
					))
				}
				endLine(tabWriter)
			}
		}
	}
	runtime.HandleError(tabWriter.Flush())
}

func tabPrint(w io.Writer, row string) {
	_, err := fmt.Fprint(w, row)
	runtime.HandleError(err)
}

func continueLine(w io.Writer) {
	_, err := fmt.Fprint(w, ",\t")
	runtime.HandleError(err)
}
func endLine(w io.Writer) {
	_, err := fmt.Fprint(w, "\n")
	runtime.HandleError(err)
}

func rowForHeaders(headers []string) string {
	return row(headers...)
}

func rowForPriorityLevel(plName string, activeQueues int, isIdle, isQuiescing bool, waitingRequests, executingRequests int) string {
	return row(
		plName,
		strconv.Itoa(activeQueues),
		strconv.FormatBool(isIdle),
		strconv.FormatBool(isQuiescing),
		strconv.Itoa(waitingRequests),
		strconv.Itoa(executingRequests),
	)
}

func rowForQueue(plName string, index, waitingRequests, executingRequests int, virtualStart float64) string {
	return row(
		plName,
		strconv.Itoa(index),
		strconv.Itoa(waitingRequests),
		strconv.Itoa(executingRequests),
		fmt.Sprintf("%.4f", virtualStart),
	)
}

func rowForRequest(plName, fsName string, queueIndex, requestIndex int, flowDistinguisher string, arriveTime time.Time) string {
	return row(
		plName,
		fsName,
		strconv.Itoa(queueIndex),
		strconv.Itoa(requestIndex),
		flowDistinguisher,
		arriveTime.UTC().Format(time.RFC3339Nano),
	)
}

func rowForRequestDetails(username, verb, path, namespace, name, apiVersion, resource, subResource string) string {
	return row(
		username,
		verb,
		path,
		namespace,
		name,
		apiVersion,
		resource,
		subResource,
	)
}

func row(columns ...string) string {
	return strings.Join(columns, ",\t")
}
<|endoftext|>


<commit_before><commit_msg>Added sort method by follower count<commit_after><|endoftext|>