<commit_before>package base

import (
	"encoding/csv"
	"fmt"
	"io"
	"os"
	"regexp"
	"strconv"
	"strings"
)

// ParseCSVGetRows returns the number of rows in a given file.
func ParseCSVGetRows(filepath string) (int, error) {
	file, err := os.Open(filepath)
	if err != nil {
		return 0, err
	}
	defer file.Close()

	reader := csv.NewReader(file)
	counter := 0
	for {
		_, err := reader.Read()
		if err == io.EOF {
			break
		} else if err != nil {
			return 0, err
		}
		counter++
	}
	return counter, nil
}

// ParseCSVGetAttributes returns an ordered slice of appropriate-ly typed
// and named Attributes.
func ParseCSVGetAttributes(filepath string, hasHeaders bool) []Attribute {
	attrs := ParseCSVSniffAttributeTypes(filepath, hasHeaders)
	names := ParseCSVSniffAttributeNames(filepath, hasHeaders)
	for i, attr := range attrs {
		attr.SetName(names[i])
	}
	return attrs
}

// ParseCSVSniffAttributeNames returns a slice containing the top row
// of a given CSV file, or placeholders if hasHeaders is false.
func ParseCSVSniffAttributeNames(filepath string, hasHeaders bool) []string {
	file, err := os.Open(filepath)
	if err != nil {
		panic(err)
	}
	defer file.Close()

	reader := csv.NewReader(file)
	headers, err := reader.Read()
	if err != nil {
		panic(err)
	}

	if hasHeaders {
		for i, h := range headers {
			headers[i] = strings.TrimSpace(h)
		}
		return headers
	}

	for i := range headers {
		headers[i] = fmt.Sprintf("%d", i)
	}
	return headers

}

// ParseCSVSniffAttributeTypes returns a slice of appropriately-typed Attributes.
//
// The type of a given attribute is determined by looking at the first data row
// of the CSV.
func ParseCSVSniffAttributeTypes(filepath string, hasHeaders bool) []Attribute {
	var attrs []Attribute
	// Open file
	file, err := os.Open(filepath)
	if err != nil {
		panic(err)
	}
	defer file.Close()
	// Create the CSV reader
	reader := csv.NewReader(file)
	if hasHeaders {
		// Skip the headers
		_, err := reader.Read()
		if err != nil {
			panic(err)
		}
	}
	// Read the first line of the file
	columns, err := reader.Read()
	if err != nil {
		panic(err)
	}

	for _, entry := range columns {
		// Match the Attribute type with regular expressions
		entry = strings.Trim(entry, " ")
		matched, err := regexp.MatchString("^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$", entry)
		if err != nil {
			panic(err)
		}
		if matched {
			attrs = append(attrs, NewFloatAttribute(""))
		} else {
			attrs = append(attrs, new(CategoricalAttribute))
		}
	}

	return attrs
}

// ParseCSVBuildInstances updates an [[#UpdatableDataGrid]] from a filepath in place
func ParseCSVBuildInstances(filepath string, hasHeaders bool, u UpdatableDataGrid) {

	// Read the input
	file, err := os.Open(filepath)
	if err != nil {
		panic(err)
	}
	defer file.Close()
	reader := csv.NewReader(file)

	rowCounter := 0

	specs := ResolveAttributes(u, u.AllAttributes())

	for {
		record, err := reader.Read()
		if err == io.EOF {
			break
		} else if err != nil {
			panic(err)
		}
		if rowCounter == 0 {
			if hasHeaders {
				hasHeaders = false
				continue
			}
		}
		for i, v := range record {
			u.Set(specs[i], rowCounter, specs[i].attr.GetSysValFromString(v))
		}
		rowCounter++
	}

}

// ParseCSVToInstances reads the CSV file given by filepath and returns
// the read Instances.
func ParseCSVToInstances(filepath string, hasHeaders bool) (instances *DenseInstances, err error) {

	// Read the number of rows in the file
	rowCount, err := ParseCSVGetRows(filepath)
	if err != nil {
		return nil, err
	}

	if hasHeaders {
		rowCount--
	}

	// Read the row headers
	attrs := ParseCSVGetAttributes(filepath, hasHeaders)
	specs := make([]AttributeSpec, len(attrs))
	// Allocate the Instances to return
	instances = NewDenseInstances()
	for i, a := range attrs {
		spec := instances.AddAttribute(a)
		specs[i] = spec
	}
	instances.Extend(rowCount)

	// Read the input
	file, err := os.Open(filepath)
	if err != nil {
		return nil, err
	}
	defer file.Close()
	reader := csv.NewReader(file)

	rowCounter := 0

	for {
		record, err := reader.Read()
		if err == io.EOF {
			break
		} else if err != nil {
			return nil, err
		}
		if rowCounter == 0 {
			if hasHeaders {
				hasHeaders = false
				continue
			}
		}
		for i, v := range record {
			v = strings.Trim(v, " ")
			instances.Set(specs[i], rowCounter, attrs[i].GetSysValFromString(v))
		}
		rowCounter++
	}

	instances.AddClassAttribute(attrs[len(attrs)-1])

	return instances, nil
}

//ParseCSV parses a CSV file and returns the number of columns and rows, the headers, the labels associated with
//classification, and the data that will be used for training.
func ParseCSV(filepath string, label int, columns []int) (int, int, []string, []string, []float64) {
	labels := make([]string, 0)
	data := make([]float64, 0)
	headers := make([]string, 0)
	rows := 0

	file, err := os.Open(filepath)
	if err != nil {
		fmt.Println("Error:", err)
	}
	defer file.Close()

	reader := csv.NewReader(file)

	headerrow, _ := reader.Read()

	for _, col := range columns {
		entry := headerrow[col]
		headers = append(headers, entry)
	}

	for {
		record, err := reader.Read()
		if err == io.EOF {
			break
		} else if err != nil {
			fmt.Println("Error:", err)
		}

		//
		labels = append(labels, record[label])

		//Iterate over our rows and append the values to a slice
		for _, col := range columns {
			entry := record[col]
			number, _ := strconv.ParseFloat(entry, 64)
			data = append(data, number)
		}
		rows++
	}
	cols := len(columns)
	return cols, rows, headers, labels, data
}
<commit_msg>Remove unused untested ParseCSV function<commit_after>package base

import (
	"encoding/csv"
	"fmt"
	"io"
	"os"
	"regexp"
	"strings"
)

// ParseCSVGetRows returns the number of rows in a given file.
func ParseCSVGetRows(filepath string) (int, error) {
	file, err := os.Open(filepath)
	if err != nil {
		return 0, err
	}
	defer file.Close()

	reader := csv.NewReader(file)
	counter := 0
	for {
		_, err := reader.Read()
		if err == io.EOF {
			break
		} else if err != nil {
			return 0, err
		}
		counter++
	}
	return counter, nil
}

// ParseCSVGetAttributes returns an ordered slice of appropriate-ly typed
// and named Attributes.
func ParseCSVGetAttributes(filepath string, hasHeaders bool) []Attribute {
	attrs := ParseCSVSniffAttributeTypes(filepath, hasHeaders)
	names := ParseCSVSniffAttributeNames(filepath, hasHeaders)
	for i, attr := range attrs {
		attr.SetName(names[i])
	}
	return attrs
}

// ParseCSVSniffAttributeNames returns a slice containing the top row
// of a given CSV file, or placeholders if hasHeaders is false.
func ParseCSVSniffAttributeNames(filepath string, hasHeaders bool) []string {
	file, err := os.Open(filepath)
	if err != nil {
		panic(err)
	}
	defer file.Close()

	reader := csv.NewReader(file)
	headers, err := reader.Read()
	if err != nil {
		panic(err)
	}

	if hasHeaders {
		for i, h := range headers {
			headers[i] = strings.TrimSpace(h)
		}
		return headers
	}

	for i := range headers {
		headers[i] = fmt.Sprintf("%d", i)
	}
	return headers

}

// ParseCSVSniffAttributeTypes returns a slice of appropriately-typed Attributes.
//
// The type of a given attribute is determined by looking at the first data row
// of the CSV.
func ParseCSVSniffAttributeTypes(filepath string, hasHeaders bool) []Attribute {
	var attrs []Attribute
	// Open file
	file, err := os.Open(filepath)
	if err != nil {
		panic(err)
	}
	defer file.Close()
	// Create the CSV reader
	reader := csv.NewReader(file)
	if hasHeaders {
		// Skip the headers
		_, err := reader.Read()
		if err != nil {
			panic(err)
		}
	}
	// Read the first line of the file
	columns, err := reader.Read()
	if err != nil {
		panic(err)
	}

	for _, entry := range columns {
		// Match the Attribute type with regular expressions
		entry = strings.Trim(entry, " ")
		matched, err := regexp.MatchString("^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$", entry)
		if err != nil {
			panic(err)
		}
		if matched {
			attrs = append(attrs, NewFloatAttribute(""))
		} else {
			attrs = append(attrs, new(CategoricalAttribute))
		}
	}

	return attrs
}

// ParseCSVBuildInstances updates an [[#UpdatableDataGrid]] from a filepath in place
func ParseCSVBuildInstances(filepath string, hasHeaders bool, u UpdatableDataGrid) {

	// Read the input
	file, err := os.Open(filepath)
	if err != nil {
		panic(err)
	}
	defer file.Close()
	reader := csv.NewReader(file)

	rowCounter := 0

	specs := ResolveAttributes(u, u.AllAttributes())

	for {
		record, err := reader.Read()
		if err == io.EOF {
			break
		} else if err != nil {
			panic(err)
		}
		if rowCounter == 0 {
			if hasHeaders {
				hasHeaders = false
				continue
			}
		}
		for i, v := range record {
			u.Set(specs[i], rowCounter, specs[i].attr.GetSysValFromString(v))
		}
		rowCounter++
	}

}

// ParseCSVToInstances reads the CSV file given by filepath and returns
// the read Instances.
func ParseCSVToInstances(filepath string, hasHeaders bool) (instances *DenseInstances, err error) {

	// Read the number of rows in the file
	rowCount, err := ParseCSVGetRows(filepath)
	if err != nil {
		return nil, err
	}

	if hasHeaders {
		rowCount--
	}

	// Read the row headers
	attrs := ParseCSVGetAttributes(filepath, hasHeaders)
	specs := make([]AttributeSpec, len(attrs))
	// Allocate the Instances to return
	instances = NewDenseInstances()
	for i, a := range attrs {
		spec := instances.AddAttribute(a)
		specs[i] = spec
	}
	instances.Extend(rowCount)

	// Read the input
	file, err := os.Open(filepath)
	if err != nil {
		return nil, err
	}
	defer file.Close()
	reader := csv.NewReader(file)

	rowCounter := 0

	for {
		record, err := reader.Read()
		if err == io.EOF {
			break
		} else if err != nil {
			return nil, err
		}
		if rowCounter == 0 {
			if hasHeaders {
				hasHeaders = false
				continue
			}
		}
		for i, v := range record {
			v = strings.Trim(v, " ")
			instances.Set(specs[i], rowCounter, attrs[i].GetSysValFromString(v))
		}
		rowCounter++
	}

	instances.AddClassAttribute(attrs[len(attrs)-1])

	return instances, nil
}
<|endoftext|>


<commit_before>// (c) Copyright 2015 JONNALAGADDA Srinivas
//
// 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 flow

import (
	"fmt"
	"sync"
	"time"
)

// Document represents a task in a workflow, whose life cycle it
// tracks.
//
// Documents are central to the workflow engine and its operations.
// Each document represents a task whose life cycle it tracks.  In the
// process, it accumulates various details, and tracks the times of
// its modifications.  The life cycle typically involves several state
// transitions, whose details are also tracked.
//
// Most applications should embed `Document` in their document
// structures rather than use this directly.
type Document struct {
	id     uint64 // globally-unique
	dtype  DocType
	title  string
	text   string // primary content
	author *User  // creator of the document
	ctime  time.Time

	mutex    sync.Mutex
	state    *DocState   // current state
	events   []*DocEvent // state transitions so far, tracked in order
	revision uint16
}

// NewDocument creates and initialises a document.
//
// The document created through this method has a life cycle that is
// associated with it through a particular workflow.
func NewDocument(id uint64, dtype DocType, title string, author *User, instate *DocState) (*Document, error) {
	if id == 0 || string(dtype) == "" || title == "" || author == nil {
		return nil, fmt.Errorf("invalid initialisation data -- id: %d, dtype: %s, title: %s, author: %s", id, dtype, title, author.Name())
	}

	d := &Document{id: id, dtype: dtype, title: title, author: author}
	d.ctime = time.Now().UTC()
	d.state = instate
	d.events = make([]*DocEvent, 1)
	d.revision = 1
	return d, nil
}

// TODO(js): OpenDocument()

// ID answers this document's globally-unique ID.
func (d *Document) ID() uint64 {
	return d.id
}

// Type answers this document's type.
func (d *Document) Type() DocType {
	return d.dtype
}

// Title answers this document's title.
func (d *Document) Title() string {
	return d.title
}

// SetText sets the primary content of this document.
func (d *Document) SetText(t string) error {
	if d.revision > 1 {
		return fmt.Errorf("document revision > 1 : %d", d.revision)
	}
	if d.text != "" {
		return fmt.Errorf("document text already set")
	}
	if t == "" {
		return fmt.Errorf("empty content given")
	}

	d.mutex.Lock()
	defer d.mutex.Unlock()

	d.text = t
	return nil
}

// Text answers this document's primary content.
func (d *Document) Text() string {
	return d.text
}

// Author answers the user who created this document.
func (d *Document) Author() *User {
	return d.author
}

// Ctime answers the creation time of this document.
func (d *Document) Ctime() time.Time {
	return d.ctime
}

// State answer this document's current state.
func (d *Document) State() *DocState {
	return d.state
}

// Mtime answers the time when this document was most-recently
// modified.  It answers the creation time, if it has not been updated
// since.
func (d *Document) Mtime() time.Time {
	l := len(d.events)
	if l == 0 {
		return d.ctime
	}

	return d.events[l-1].mtime
}

// Revision answers the current revision number of this document.
func (d *Document) Revision() uint16 {
	return d.revision
}

// Events answers a copy of the sequence of events that has
// transformed this document so far.
func (d *Document) Events() []*DocEvent {
	es := make([]*DocEvent, len(d.events))
	copy(es, d.events)
	return es
}

// applyEvent transitions this document into a new state as per the
// applied event.
//
// We perform as many validations as possible when constructing the
// event, so that we spend a minimum amount of time in this
// synchronised method.
func (d *Document) applyEvent(e *DocEvent) error {
	if e.doc.id != d.id {
		return fmt.Errorf("mismatched document IDs -- current: %d, event's: %d", d.id, e.doc.id)
	}

	d.mutex.Lock()
	defer d.mutex.Unlock()

	e.mtime = time.Now().UTC()
	d.revision++
	e.revision = d.revision
	d.state = e.state
	d.events = append(d.events, e)
	return nil
}
<commit_msg>Add synchronisation to safe guard copying document events<commit_after>// (c) Copyright 2015 JONNALAGADDA Srinivas
//
// 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 flow

import (
	"fmt"
	"sync"
	"time"
)

// Document represents a task in a workflow, whose life cycle it
// tracks.
//
// Documents are central to the workflow engine and its operations.
// Each document represents a task whose life cycle it tracks.  In the
// process, it accumulates various details, and tracks the times of
// its modifications.  The life cycle typically involves several state
// transitions, whose details are also tracked.
//
// Most applications should embed `Document` in their document
// structures rather than use this directly.
type Document struct {
	id     uint64 // globally-unique
	dtype  DocType
	title  string
	text   string // primary content
	author *User  // creator of the document
	ctime  time.Time

	mutex    sync.Mutex
	state    *DocState   // current state
	events   []*DocEvent // state transitions so far, tracked in order
	revision uint16
}

// NewDocument creates and initialises a document.
//
// The document created through this method has a life cycle that is
// associated with it through a particular workflow.
func NewDocument(id uint64, dtype DocType, title string, author *User, instate *DocState) (*Document, error) {
	if id == 0 || string(dtype) == "" || title == "" || author == nil {
		return nil, fmt.Errorf("invalid initialisation data -- id: %d, dtype: %s, title: %s, author: %s", id, dtype, title, author.Name())
	}

	d := &Document{id: id, dtype: dtype, title: title, author: author}
	d.ctime = time.Now().UTC()
	d.state = instate
	d.events = make([]*DocEvent, 1)
	d.revision = 1
	return d, nil
}

// TODO(js): OpenDocument()

// ID answers this document's globally-unique ID.
func (d *Document) ID() uint64 {
	return d.id
}

// Type answers this document's type.
func (d *Document) Type() DocType {
	return d.dtype
}

// Title answers this document's title.
func (d *Document) Title() string {
	return d.title
}

// SetText sets the primary content of this document.
func (d *Document) SetText(t string) error {
	if d.revision > 1 {
		return fmt.Errorf("document revision > 1 : %d", d.revision)
	}
	if d.text != "" {
		return fmt.Errorf("document text already set")
	}
	if t == "" {
		return fmt.Errorf("empty content given")
	}

	d.mutex.Lock()
	defer d.mutex.Unlock()

	d.text = t
	return nil
}

// Text answers this document's primary content.
func (d *Document) Text() string {
	return d.text
}

// Author answers the user who created this document.
func (d *Document) Author() *User {
	return d.author
}

// Ctime answers the creation time of this document.
func (d *Document) Ctime() time.Time {
	return d.ctime
}

// State answer this document's current state.
func (d *Document) State() *DocState {
	return d.state
}

// Mtime answers the time when this document was most-recently
// modified.  It answers the creation time, if it has not been updated
// since.
func (d *Document) Mtime() time.Time {
	l := len(d.events)
	if l == 0 {
		return d.ctime
	}

	return d.events[l-1].mtime
}

// Revision answers the current revision number of this document.
func (d *Document) Revision() uint16 {
	return d.revision
}

// Events answers a copy of the sequence of events that has
// transformed this document so far.
func (d *Document) Events() []*DocEvent {
	// Synchronised because events are dynamic.
	d.mutex.Lock()
	defer d.mutex.Unlock()

	es := make([]*DocEvent, len(d.events))
	copy(es, d.events)
	return es
}

// applyEvent transitions this document into a new state as per the
// applied event.
//
// We perform as many validations as possible when constructing the
// event, so that we spend a minimum amount of time in this
// synchronised method.
func (d *Document) applyEvent(e *DocEvent) error {
	if e.doc.id != d.id {
		return fmt.Errorf("mismatched document IDs -- current: %d, event's: %d", d.id, e.doc.id)
	}

	d.mutex.Lock()
	defer d.mutex.Unlock()

	e.mtime = time.Now().UTC()
	d.revision++
	e.revision = d.revision
	d.state = e.state
	d.events = append(d.events, e)
	return nil
}
<|endoftext|>


<commit_before>package oled96x96_test

import (
	"github.com/goiot/devices/grove/oled96x96"
	"golang.org/x/exp/io/i2c"
)

func Example() {
	bus := &i2c.Devfs{
		// change the following value if you use another bus
		Dev:  "/dev/i2c-1",
		Addr: oled96x96.Address,
	}

	display, err := oled96x96.New(bus)
	if err != nil {
		panic(err)
	}
	defer display.Close()

	display.Write("Hello World!")
}
<commit_msg>fix tests after API change<commit_after>package oled96x96_test

import (
	"github.com/goiot/devices/grove/oled96x96"
	"golang.org/x/exp/io/i2c"
)

func Example() {
	bus := &i2c.Devfs{
		// change the following value if you use another bus
		Dev:  "/dev/i2c-1",
		Addr: oled96x96.Address,
	}

	display, err := oled96x96.Open(bus)
	if err != nil {
		panic(err)
	}
	defer display.Close()

	display.Write("Hello World!")
}
<|endoftext|>


<commit_before>package paillier

import (
	"crypto/rand"
	"errors"
	"math/big"
	"reflect"
	"testing"
)

var MockGenerateSafePrimes = func() (*big.Int, *big.Int, error) {
	return big.NewInt(887), big.NewInt(443), nil
}

func TestCreateThresholdKeyGenerator(t *testing.T) {
	var tests = map[string]struct {
		keyLength                      int
		totalNumberOfDecryptionServers int
		threshold                      int
		expectedError                  error
	}{
		"generator successfully created for 20 bit key length": {
			keyLength:                      20,
			totalNumberOfDecryptionServers: 6,
			threshold:                      5,
		},
		"generator can't be created for 19 bit key length": {
			keyLength:                      19,
			totalNumberOfDecryptionServers: 4,
			threshold:                      3,
			expectedError:                  errors.New("Public key bit length must be an even number"),
		},
		"generator successfully created for 18 bit key length": {
			keyLength:                      18,
			totalNumberOfDecryptionServers: 4,
			threshold:                      3,
		},
		"generator can't be created for 17 bit key length": {
			keyLength:                      17,
			totalNumberOfDecryptionServers: 4,
			threshold:                      3,
			expectedError:                  errors.New("Public key bit length must be an even number"),
		},
		"generator can't be created for 16 bit key length": {
			keyLength:                      16,
			totalNumberOfDecryptionServers: 4,
			threshold:                      3,
			expectedError:                  errors.New("Public key bit length must be at least 18 bits"),
		},
	}

	for testName, test := range tests {
		t.Run(testName, func(t *testing.T) {
			gen, err := GetThresholdKeyGenerator(
				test.keyLength,
				test.totalNumberOfDecryptionServers,
				test.threshold,
				rand.Reader,
			)

			if !reflect.DeepEqual(test.expectedError, err) {
				t.Fatalf(
					"Unexpected error\nActual: %v\nExpected: %v",
					err,
					test.expectedError,
				)
			}

			if test.expectedError == nil {
				if gen == nil {
					t.Fatal(
						"Got nil generator, it should be successfully created",
					)
				}

				if test.keyLength != gen.PublicKeyBitLength {
					t.Fatalf(
						"Unexpected public key length\nExpected: %v\nActual: %v",
						test.keyLength,
						gen.PublicKeyBitLength,
					)
				}

				if test.threshold != gen.Threshold {
					t.Fatalf(
						"Unexpected threshold\nExpected: %v\nActual: %v",
						test.threshold,
						gen.Threshold,
					)
				}

				if test.totalNumberOfDecryptionServers != gen.TotalNumberOfDecryptionServers {
					t.Fatalf(
						"Unexpected number of decryption servers\nExpected: %v\nActual: %v",
						test.totalNumberOfDecryptionServers,
						gen.TotalNumberOfDecryptionServers,
					)
				}
			}
		})
	}
}

func TestGenerateNumbersOfCorrectBitLength(t *testing.T) {
	var tests = map[string]struct {
		keyLength             int
		expectedPrimeLength   int
		expectedModulusLength int
	}{
		"key bit length = 32, prime bit length = 16, modulus bit length = 32": {
			keyLength:             32,
			expectedPrimeLength:   16,
			expectedModulusLength: 32,
		},
		"key bit length = 64, prime bit length = 32, modulus bit length = 64": {
			keyLength:             64,
			expectedPrimeLength:   32,
			expectedModulusLength: 64,
		},
		"key bit length = 128, prime bit length = 64, modulus bit length = 128": {
			keyLength:             128,
			expectedPrimeLength:   64,
			expectedModulusLength: 128,
		},
	}

	for testName, test := range tests {
		t.Run(testName, func(t *testing.T) {
			gen, err := GetThresholdKeyGenerator(test.keyLength, 10, 6, rand.Reader)
			if err != nil {
				t.Fatal(err)
			}

			err = gen.initNumerialValues()
			if err != nil {
				t.Fatal(err)
			}

			if gen.p.BitLen() != test.expectedPrimeLength {
				t.Fatalf(
					"Unexpected prime bit length\nExpected %v\n Actual %v",
					test.expectedModulusLength,
					gen.p.BitLen(),
				)
			}

			if gen.q.BitLen() != test.expectedPrimeLength {
				t.Fatalf(
					"Unexpected prime bit length\nExpected %v\n Actual %v",
					test.expectedModulusLength,
					gen.q.BitLen(),
				)
			}

			if gen.n.BitLen() != test.expectedModulusLength {
				t.Fatalf(
					"Unexpected modulus bit length\nExpected %v\n Actual %v",
					test.expectedModulusLength,
					gen.n.BitLen(),
				)
			}

			if new(big.Int).Mul(gen.p, gen.q).Cmp(gen.n) != 0 {
				t.Fatal("n != pq")
			}
		})
	}
}

func TestInitPandP1(t *testing.T) {
	tkh, err := GetThresholdKeyGenerator(32, 4, 3, rand.Reader)
	if err != nil {
		t.Fatal(err)
	}

	tkh.initPandP1()
	IsSafePrime(tkh.p, tkh.p1, 16, t)
}

func TestInitQandQ1(t *testing.T) {
	tkh, err := GetThresholdKeyGenerator(32, 4, 3, rand.Reader)
	if err != nil {
		t.Fatal(err)
	}

	tkh.initQandQ1()
	IsSafePrime(tkh.q, tkh.q1, 16, t)
}

func TestInitPsAndQs(t *testing.T) {
	tkh, err := GetThresholdKeyGenerator(32, 4, 3, rand.Reader)
	if err != nil {
		t.Fatal(err)
	}

	tkh.initPsAndQs()

	IsSafePrime(tkh.p, tkh.p1, 16, t)
	IsSafePrime(tkh.q, tkh.q1, 16, t)
}

func TestArePsAndQsGood(t *testing.T) {
	tkh := new(ThresholdKeyGenerator)
	tkh.p, tkh.p1, tkh.q, tkh.q1 = b(887), b(443), b(839), b(419)
	if !tkh.arePsAndQsGood() {
		t.Fail()
	}

	tkh.p, tkh.p1, tkh.q, tkh.q1 = b(887), b(443), b(887), b(443)
	if tkh.arePsAndQsGood() {
		t.Fail()
	}

	tkh.p, tkh.p1, tkh.q, tkh.q1 = b(887), b(443), b(443), b(221)
	if tkh.arePsAndQsGood() {
		t.Fail()
	}
}

func TestInitShortcuts(t *testing.T) {
	tkh := new(ThresholdKeyGenerator)
	tkh.p, tkh.p1, tkh.q, tkh.q1 = b(839), b(419), b(887), b(443)
	tkh.initShortcuts()

	if !reflect.DeepEqual(tkh.n, b(744193)) {
		t.Error("wrong n", tkh.n)
	}
	if !reflect.DeepEqual(tkh.m, b(185617)) {
		t.Error("wrong m", tkh.m)
	}
	if !reflect.DeepEqual(tkh.nm, new(big.Int).Mul(b(744193), b(185617))) {
		t.Error("wrong nm", tkh.nm)
	}
	if !reflect.DeepEqual(tkh.nSquare, new(big.Int).Mul(b(744193), b(744193))) {
		t.Error("wrong nSquare", tkh.nSquare)
	}
}

func TestInitD(t *testing.T) {
	tkh := new(ThresholdKeyGenerator)
	tkh.p, tkh.p1, tkh.q, tkh.q1 = b(863), b(431), b(839), b(419)
	tkh.initShortcuts()
	tkh.initD()
	if n(tkh.d)%n(tkh.m) != 0 {
		t.Fail()
	}
	if n(tkh.d)%n(tkh.n) != 1 {
		t.Fail()
	}
}

func TestInitNumerialValues(t *testing.T) {
	tkh, err := GetThresholdKeyGenerator(32, 4, 3, rand.Reader)
	if err != nil {
		t.Fatal(err)
	}

	if err := tkh.initNumerialValues(); err != nil {
		t.Error(err)
	}
}

func TestGenerateHidingPolynomial(t *testing.T) {
	tkh, err := GetThresholdKeyGenerator(32, 15, 10, rand.Reader)
	if err != nil {
		t.Fatal(err)
	}

	if err := tkh.initNumerialValues(); err != nil {
		t.Error(err)
	}
	if err := tkh.generateHidingPolynomial(); err != nil {
		t.Error(err)
	}
	p := tkh.polynomialCoefficients
	if len(p) != tkh.Threshold {
		t.Fail()
	}
	if n(p[0]) != n(tkh.d) {
		t.Fail()
	}
	for i := 1; i < len(p); i++ {
		if j := n(p[i]); j < 0 || j >= n(tkh.nm) {
			t.Fail()
		}
	}
}

func TestComputeShare(t *testing.T) {
	tkh, err := GetThresholdKeyGenerator(32, 5, 3, rand.Reader)
	if err != nil {
		t.Fatal(err)
	}

	tkh.nm = b(103)
	tkh.polynomialCoefficients = []*big.Int{b(29), b(88), b(51)}
	share := tkh.computeShare(2)
	if n(share) != 31 {
		t.Error("error computing a share.  ", share)
	}
}

func TestCreateShares(t *testing.T) {
	tkh, err := GetThresholdKeyGenerator(32, 100, 10, rand.Reader)
	if err != nil {
		t.Fatal(err)
	}

	if err := tkh.initNumerialValues(); err != nil {
		t.Error(err)
	}
	if err := tkh.generateHidingPolynomial(); err != nil {
		t.Error(err)
	}

	if shares := tkh.createShares(); len(shares) != 100 {
		t.Fail()
	}
}

func TestCreateViArray(t *testing.T) {
	tkh := new(ThresholdKeyGenerator)
	tkh.TotalNumberOfDecryptionServers = 10
	tkh.v = b(54)
	tkh.nSquare = b(101 * 101)
	vArr := tkh.createViArray([]*big.Int{b(12), b(90), b(103)})
	exp := []*big.Int{b(6162), b(304), b(2728)}
	if !reflect.DeepEqual(vArr, exp) {
		t.Fail()
	}
}

func TestGetThresholdKeyGenerator(t *testing.T) {
	tkh, err := GetThresholdKeyGenerator(50, 10, 6, rand.Reader)
	if err != nil {
		t.Fatal(err)
	}

	if err := tkh.initNumerialValues(); err != nil {
		t.Error(nil)
	}
}

func TestGenerate(t *testing.T) {
	tkh, err := GetThresholdKeyGenerator(32, 10, 6, rand.Reader)
	if err != nil {
		t.Fatal(err)
	}

	tpks, err := tkh.Generate()
	if err != nil {
		t.Error(err)
		return
	}
	if len(tpks) != 10 {
		t.Fail()
	}
	for i, tpk := range tpks {
		if tpk.Id != i+1 {
			t.Fail()
		}
		if len(tpk.Vi) != 10 {
			t.Fail()
		}
		if tpk.N == nil {
			t.Fail()
		}
		if tpk.Threshold != 6 || tpk.TotalNumberOfDecryptionServers != 10 {
			t.Fail()
		}
	}
}

func TestComputeV(t *testing.T) {
	tkh, err := GetThresholdKeyGenerator(32, 10, 6, rand.Reader)
	if err != nil {
		t.Fatal(err)
	}

	tkh.n = b(1907 * 1823)
	tkh.nSquare = new(big.Int).Mul(tkh.n, tkh.n)
	for i := 0; i < 100; i++ {
		if err := tkh.computeV(); err != nil {
			t.Error(err)
		}
		if tkh.v.Cmp(tkh.nSquare) > 0 {
			t.Error("v is too big")
		}
		if tkh.v.Cmp(tkh.n) > 0 {
			return
		}
	}
	t.Error(`v has never been bigger than n.  It is suspicious in the sense<
	than it was taken in the range 0...n**2 -1
	`)
}
<commit_msg>Simplified ThresholdKeyGenerator factory function tests<commit_after>package paillier

import (
	"crypto/rand"
	"errors"
	"math/big"
	"reflect"
	"testing"
)

var MockGenerateSafePrimes = func() (*big.Int, *big.Int, error) {
	return big.NewInt(887), big.NewInt(443), nil
}

func TestCreateThresholdKeyGenerator(t *testing.T) {
	var tests = map[string]struct {
		publicKeyBitLength             int
		totalNumberOfDecryptionServers int
		threshold                      int
		expectedError                  error
	}{
		"generator successfully created for 20 bit key length": {
			publicKeyBitLength:             20,
			totalNumberOfDecryptionServers: 6,
			threshold:                      5,
		},
		"generator can't be created for 19 bit key length": {
			publicKeyBitLength:             19,
			totalNumberOfDecryptionServers: 4,
			threshold:                      3,
			expectedError:                  errors.New("Public key bit length must be an even number"),
		},
		"generator successfully created for 18 bit key length": {
			publicKeyBitLength:             18,
			totalNumberOfDecryptionServers: 4,
			threshold:                      3,
		},
		"generator can't be created for 17 bit key length": {
			publicKeyBitLength:             17,
			totalNumberOfDecryptionServers: 4,
			threshold:                      3,
			expectedError:                  errors.New("Public key bit length must be an even number"),
		},
		"generator can't be created for 16 bit key length": {
			publicKeyBitLength:             16,
			totalNumberOfDecryptionServers: 4,
			threshold:                      3,
			expectedError:                  errors.New("Public key bit length must be at least 18 bits"),
		},
	}

	for testName, test := range tests {
		t.Run(testName, func(t *testing.T) {
			gen, err := GetThresholdKeyGenerator(
				test.publicKeyBitLength,
				test.totalNumberOfDecryptionServers,
				test.threshold,
				rand.Reader,
			)

			if !reflect.DeepEqual(test.expectedError, err) {
				t.Fatalf(
					"Unexpected error\nActual: %v\nExpected: %v",
					err,
					test.expectedError,
				)
			}

			if test.expectedError == nil {
				if gen == nil {
					t.Fatal(
						"Got nil generator, it should be successfully created",
					)
				}

				if test.publicKeyBitLength != gen.PublicKeyBitLength {
					t.Fatalf(
						"Unexpected public key length\nExpected: %v\nActual: %v",
						test.publicKeyBitLength,
						gen.PublicKeyBitLength,
					)
				}

				if test.threshold != gen.Threshold {
					t.Fatalf(
						"Unexpected threshold\nExpected: %v\nActual: %v",
						test.threshold,
						gen.Threshold,
					)
				}

				if test.totalNumberOfDecryptionServers != gen.TotalNumberOfDecryptionServers {
					t.Fatalf(
						"Unexpected number of decryption servers\nExpected: %v\nActual: %v",
						test.totalNumberOfDecryptionServers,
						gen.TotalNumberOfDecryptionServers,
					)
				}
			}
		})
	}
}

func TestGenerateNumbersOfCorrectBitLength(t *testing.T) {
	var tests = map[string]struct {
		publicKeyLength     int
		expectedPrimeLength int
	}{
		"public key bit length = 32, prime bit length = 16": {
			publicKeyLength:     32,
			expectedPrimeLength: 16,
		},
		"public key bit length = 64, prime bit length = 32": {
			publicKeyLength:     64,
			expectedPrimeLength: 32,
		},
	}

	for testName, test := range tests {
		t.Run(testName, func(t *testing.T) {
			gen, err := GetThresholdKeyGenerator(test.publicKeyLength, 10, 6, rand.Reader)
			if err != nil {
				t.Fatal(err)
			}

			err = gen.initNumerialValues()
			if err != nil {
				t.Fatal(err)
			}

			if gen.p.BitLen() != test.expectedPrimeLength {
				t.Fatalf(
					"Unexpected prime bit length\nExpected %v\n Actual %v",
					test.expectedPrimeLength,
					gen.p.BitLen(),
				)
			}

			if gen.q.BitLen() != test.expectedPrimeLength {
				t.Fatalf(
					"Unexpected prime bit length\nExpected %v\n Actual %v",
					test.expectedPrimeLength,
					gen.q.BitLen(),
				)
			}

			if gen.n.BitLen() != test.publicKeyLength {
				t.Fatalf(
					"Unexpected modulus bit length\nExpected %v\n Actual %v",
					test.publicKeyLength,
					gen.n.BitLen(),
				)
			}

			if new(big.Int).Mul(gen.p, gen.q).Cmp(gen.n) != 0 {
				t.Fatal("n != pq")
			}
		})
	}
}

func TestInitPandP1(t *testing.T) {
	tkh, err := GetThresholdKeyGenerator(32, 4, 3, rand.Reader)
	if err != nil {
		t.Fatal(err)
	}

	tkh.initPandP1()
	IsSafePrime(tkh.p, tkh.p1, 16, t)
}

func TestInitQandQ1(t *testing.T) {
	tkh, err := GetThresholdKeyGenerator(32, 4, 3, rand.Reader)
	if err != nil {
		t.Fatal(err)
	}

	tkh.initQandQ1()
	IsSafePrime(tkh.q, tkh.q1, 16, t)
}

func TestInitPsAndQs(t *testing.T) {
	tkh, err := GetThresholdKeyGenerator(32, 4, 3, rand.Reader)
	if err != nil {
		t.Fatal(err)
	}

	tkh.initPsAndQs()

	IsSafePrime(tkh.p, tkh.p1, 16, t)
	IsSafePrime(tkh.q, tkh.q1, 16, t)
}

func TestArePsAndQsGood(t *testing.T) {
	tkh := new(ThresholdKeyGenerator)
	tkh.p, tkh.p1, tkh.q, tkh.q1 = b(887), b(443), b(839), b(419)
	if !tkh.arePsAndQsGood() {
		t.Fail()
	}

	tkh.p, tkh.p1, tkh.q, tkh.q1 = b(887), b(443), b(887), b(443)
	if tkh.arePsAndQsGood() {
		t.Fail()
	}

	tkh.p, tkh.p1, tkh.q, tkh.q1 = b(887), b(443), b(443), b(221)
	if tkh.arePsAndQsGood() {
		t.Fail()
	}
}

func TestInitShortcuts(t *testing.T) {
	tkh := new(ThresholdKeyGenerator)
	tkh.p, tkh.p1, tkh.q, tkh.q1 = b(839), b(419), b(887), b(443)
	tkh.initShortcuts()

	if !reflect.DeepEqual(tkh.n, b(744193)) {
		t.Error("wrong n", tkh.n)
	}
	if !reflect.DeepEqual(tkh.m, b(185617)) {
		t.Error("wrong m", tkh.m)
	}
	if !reflect.DeepEqual(tkh.nm, new(big.Int).Mul(b(744193), b(185617))) {
		t.Error("wrong nm", tkh.nm)
	}
	if !reflect.DeepEqual(tkh.nSquare, new(big.Int).Mul(b(744193), b(744193))) {
		t.Error("wrong nSquare", tkh.nSquare)
	}
}

func TestInitD(t *testing.T) {
	tkh := new(ThresholdKeyGenerator)
	tkh.p, tkh.p1, tkh.q, tkh.q1 = b(863), b(431), b(839), b(419)
	tkh.initShortcuts()
	tkh.initD()
	if n(tkh.d)%n(tkh.m) != 0 {
		t.Fail()
	}
	if n(tkh.d)%n(tkh.n) != 1 {
		t.Fail()
	}
}

func TestInitNumerialValues(t *testing.T) {
	tkh, err := GetThresholdKeyGenerator(32, 4, 3, rand.Reader)
	if err != nil {
		t.Fatal(err)
	}

	if err := tkh.initNumerialValues(); err != nil {
		t.Error(err)
	}
}

func TestGenerateHidingPolynomial(t *testing.T) {
	tkh, err := GetThresholdKeyGenerator(32, 15, 10, rand.Reader)
	if err != nil {
		t.Fatal(err)
	}

	if err := tkh.initNumerialValues(); err != nil {
		t.Error(err)
	}
	if err := tkh.generateHidingPolynomial(); err != nil {
		t.Error(err)
	}
	p := tkh.polynomialCoefficients
	if len(p) != tkh.Threshold {
		t.Fail()
	}
	if n(p[0]) != n(tkh.d) {
		t.Fail()
	}
	for i := 1; i < len(p); i++ {
		if j := n(p[i]); j < 0 || j >= n(tkh.nm) {
			t.Fail()
		}
	}
}

func TestComputeShare(t *testing.T) {
	tkh, err := GetThresholdKeyGenerator(32, 5, 3, rand.Reader)
	if err != nil {
		t.Fatal(err)
	}

	tkh.nm = b(103)
	tkh.polynomialCoefficients = []*big.Int{b(29), b(88), b(51)}
	share := tkh.computeShare(2)
	if n(share) != 31 {
		t.Error("error computing a share.  ", share)
	}
}

func TestCreateShares(t *testing.T) {
	tkh, err := GetThresholdKeyGenerator(32, 100, 10, rand.Reader)
	if err != nil {
		t.Fatal(err)
	}

	if err := tkh.initNumerialValues(); err != nil {
		t.Error(err)
	}
	if err := tkh.generateHidingPolynomial(); err != nil {
		t.Error(err)
	}

	if shares := tkh.createShares(); len(shares) != 100 {
		t.Fail()
	}
}

func TestCreateViArray(t *testing.T) {
	tkh := new(ThresholdKeyGenerator)
	tkh.TotalNumberOfDecryptionServers = 10
	tkh.v = b(54)
	tkh.nSquare = b(101 * 101)
	vArr := tkh.createViArray([]*big.Int{b(12), b(90), b(103)})
	exp := []*big.Int{b(6162), b(304), b(2728)}
	if !reflect.DeepEqual(vArr, exp) {
		t.Fail()
	}
}

func TestGetThresholdKeyGenerator(t *testing.T) {
	tkh, err := GetThresholdKeyGenerator(50, 10, 6, rand.Reader)
	if err != nil {
		t.Fatal(err)
	}

	if err := tkh.initNumerialValues(); err != nil {
		t.Error(nil)
	}
}

func TestGenerate(t *testing.T) {
	tkh, err := GetThresholdKeyGenerator(32, 10, 6, rand.Reader)
	if err != nil {
		t.Fatal(err)
	}

	tpks, err := tkh.Generate()
	if err != nil {
		t.Error(err)
		return
	}
	if len(tpks) != 10 {
		t.Fail()
	}
	for i, tpk := range tpks {
		if tpk.Id != i+1 {
			t.Fail()
		}
		if len(tpk.Vi) != 10 {
			t.Fail()
		}
		if tpk.N == nil {
			t.Fail()
		}
		if tpk.Threshold != 6 || tpk.TotalNumberOfDecryptionServers != 10 {
			t.Fail()
		}
	}
}

func TestComputeV(t *testing.T) {
	tkh, err := GetThresholdKeyGenerator(32, 10, 6, rand.Reader)
	if err != nil {
		t.Fatal(err)
	}

	tkh.n = b(1907 * 1823)
	tkh.nSquare = new(big.Int).Mul(tkh.n, tkh.n)
	for i := 0; i < 100; i++ {
		if err := tkh.computeV(); err != nil {
			t.Error(err)
		}
		if tkh.v.Cmp(tkh.nSquare) > 0 {
			t.Error("v is too big")
		}
		if tkh.v.Cmp(tkh.n) > 0 {
			return
		}
	}
	t.Error(`v has never been bigger than n.  It is suspicious in the sense<
	than it was taken in the range 0...n**2 -1
	`)
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package main

import (
	"strings"

	"github.com/samuel/go-thrift/parser"
)

// State is global Thrift state for a file with type information.
type State struct {
	// typedefs is a map from a typedef name to the underlying type.
	typedefs map[string]*parser.Type

	// includes is a map from Thrift base name to the include.
	includes map[string]*Include

	// all is used for includes.
	all map[string]parseState
}

// newState parses the type information for a parsed Thrift file and returns the state.
func newState(v *parser.Thrift, all map[string]parseState) *State {
	typedefs := make(map[string]*parser.Type)
	for k, v := range v.Typedefs {
		typedefs[k] = v
	}

	// Enums are typedefs to an int64.
	i64Type := &parser.Type{Name: "i64"}
	for k := range v.Enums {
		typedefs[k] = i64Type
	}

	return &State{typedefs, createIncludes(v), all}
}

func (s *State) isBasicType(thriftType string) bool {
	_, ok := thriftToGo[thriftType]
	return ok
}

// rootType recurses through typedefs and returns the underlying type.
func (s *State) rootType(thriftType *parser.Type) *parser.Type {
	if state, newType, _, include := s.checkInclude(thriftType); include {
		return state.rootType(newType)
	}

	if v, ok := s.typedefs[thriftType.Name]; ok {
		return s.rootType(v)
	}
	return thriftType
}

// checkInclude will check if the type is an included type, and if so, return the
// state and type from the state for that file.
func (s *State) checkInclude(thriftType *parser.Type) (*State, *parser.Type, string, bool) {
	parts := strings.SplitN(thriftType.Name, ".", 2)
	if len(parts) < 2 {
		return nil, nil, "", false
	}

	newType := *thriftType
	newType.Name = parts[1]

	include := s.includes[parts[0]]
	state := s.all[include.file]
	return state.global, &newType, parts[0], true
}

// isResultPointer returns whether the result for this method is a pointer.
func (s *State) isResultPointer(thriftType *parser.Type) bool {
	_, basicGoType := thriftToGo[s.rootType(thriftType).Name]
	return !basicGoType
}

// goType returns the Go type name for the given thrift type.
func (s *State) goType(thriftType *parser.Type) string {
	return s.goTypePrefix("", thriftType)
}

// goTypePrefix returns the Go type name for the given thrift type with the prefix.
func (s *State) goTypePrefix(prefix string, thriftType *parser.Type) string {
	switch thriftType.Name {
	case "binary":
		return "[]byte"
	case "list":
		return "[]" + s.goType(thriftType.ValueType)
	case "set":
		return "map[" + s.goType(thriftType.ValueType) + "]bool"
	case "map":
		return "map[" + s.goType(thriftType.KeyType) + "]" + s.goType(thriftType.ValueType)
	}

	// If the type is imported, then ignore the package.
	if state, newType, prefix, include := s.checkInclude(thriftType); include {
		return state.goTypePrefix(prefix+".", newType)
	}

	// If the type is a direct Go type, use that.
	if goType, ok := thriftToGo[thriftType.Name]; ok {
		return goType
	}

	goThriftName := goPublicFieldName(thriftType.Name)
	goThriftName = prefix + goThriftName

	// Check if the type has a typedef to the direct Go type.
	rootType := s.rootType(thriftType)
	if _, ok := thriftToGo[rootType.Name]; ok {
		return goThriftName
	}
	if rootType.Name == "list" ||
		rootType.Name == "set" ||
		rootType.Name == "map" {
		return goThriftName
	}

	// If it's a typedef to another struct, then the typedef is defined as a pointer
	// so we do not want the pointer type here.
	if rootType != thriftType {
		return goThriftName
	}

	// If it's not a typedef for a basic type, we use a pointer.
	return "*" + goThriftName
}
<commit_msg>Fix compatibility with latest go-thrift<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package main

import (
	"strings"

	"github.com/samuel/go-thrift/parser"
)

// State is global Thrift state for a file with type information.
type State struct {
	// typedefs is a map from a typedef name to the underlying type.
	typedefs map[string]*parser.Type

	// includes is a map from Thrift base name to the include.
	includes map[string]*Include

	// all is used for includes.
	all map[string]parseState
}

// newState parses the type information for a parsed Thrift file and returns the state.
func newState(v *parser.Thrift, all map[string]parseState) *State {
	typedefs := make(map[string]*parser.Type)
	for k, v := range v.Typedefs {
		typedefs[k] = v.Type
	}

	// Enums are typedefs to an int64.
	i64Type := &parser.Type{Name: "i64"}
	for k := range v.Enums {
		typedefs[k] = i64Type
	}

	return &State{typedefs, createIncludes(v), all}
}

func (s *State) isBasicType(thriftType string) bool {
	_, ok := thriftToGo[thriftType]
	return ok
}

// rootType recurses through typedefs and returns the underlying type.
func (s *State) rootType(thriftType *parser.Type) *parser.Type {
	if state, newType, _, include := s.checkInclude(thriftType); include {
		return state.rootType(newType)
	}

	if v, ok := s.typedefs[thriftType.Name]; ok {
		return s.rootType(v)
	}
	return thriftType
}

// checkInclude will check if the type is an included type, and if so, return the
// state and type from the state for that file.
func (s *State) checkInclude(thriftType *parser.Type) (*State, *parser.Type, string, bool) {
	parts := strings.SplitN(thriftType.Name, ".", 2)
	if len(parts) < 2 {
		return nil, nil, "", false
	}

	newType := *thriftType
	newType.Name = parts[1]

	include := s.includes[parts[0]]
	state := s.all[include.file]
	return state.global, &newType, parts[0], true
}

// isResultPointer returns whether the result for this method is a pointer.
func (s *State) isResultPointer(thriftType *parser.Type) bool {
	_, basicGoType := thriftToGo[s.rootType(thriftType).Name]
	return !basicGoType
}

// goType returns the Go type name for the given thrift type.
func (s *State) goType(thriftType *parser.Type) string {
	return s.goTypePrefix("", thriftType)
}

// goTypePrefix returns the Go type name for the given thrift type with the prefix.
func (s *State) goTypePrefix(prefix string, thriftType *parser.Type) string {
	switch thriftType.Name {
	case "binary":
		return "[]byte"
	case "list":
		return "[]" + s.goType(thriftType.ValueType)
	case "set":
		return "map[" + s.goType(thriftType.ValueType) + "]bool"
	case "map":
		return "map[" + s.goType(thriftType.KeyType) + "]" + s.goType(thriftType.ValueType)
	}

	// If the type is imported, then ignore the package.
	if state, newType, prefix, include := s.checkInclude(thriftType); include {
		return state.goTypePrefix(prefix+".", newType)
	}

	// If the type is a direct Go type, use that.
	if goType, ok := thriftToGo[thriftType.Name]; ok {
		return goType
	}

	goThriftName := goPublicFieldName(thriftType.Name)
	goThriftName = prefix + goThriftName

	// Check if the type has a typedef to the direct Go type.
	rootType := s.rootType(thriftType)
	if _, ok := thriftToGo[rootType.Name]; ok {
		return goThriftName
	}
	if rootType.Name == "list" ||
		rootType.Name == "set" ||
		rootType.Name == "map" {
		return goThriftName
	}

	// If it's a typedef to another struct, then the typedef is defined as a pointer
	// so we do not want the pointer type here.
	if rootType != thriftType {
		return goThriftName
	}

	// If it's not a typedef for a basic type, we use a pointer.
	return "*" + goThriftName
}
<|endoftext|>


<commit_before>package detailed

import (
	"strings"

	"github.com/weaveworks/scope/probe/docker"
	"github.com/weaveworks/scope/probe/host"
	"github.com/weaveworks/scope/probe/kubernetes"
	"github.com/weaveworks/scope/probe/overlay"
	"github.com/weaveworks/scope/probe/process"
	"github.com/weaveworks/scope/render"
)

var labels = map[string]string{
	docker.CPUTotalUsage:         "CPU",
	docker.ContainerCommand:      "Command",
	docker.ContainerCreated:      "Created",
	docker.ContainerHostname:     "Hostname",
	docker.ContainerID:           "ID",
	docker.ContainerIPs:          "IPs",
	docker.ContainerPorts:        "Ports",
	docker.ContainerRestartCount: "Restart #",
	docker.ContainerState:        "State",
	docker.ContainerUptime:       "Uptime",
	docker.ImageID:               "Image ID",
	docker.MemoryUsage:           "Memory",
	host.CPUUsage:                "CPU",
	host.HostName:                "Hostname",
	host.KernelVersion:           "Kernel version",
	host.Load15:                  "Load (15m)",
	host.Load1:                   "Load (1m)",
	host.Load5:                   "Load (5m)",
	host.LocalNetworks:           "Local Networks",
	host.MemoryUsage:             "Memory",
	host.OS:                      "Operating system",
	host.Uptime:                  "Uptime",
	kubernetes.Namespace:         "Namespace",
	kubernetes.PodCreated:        "Created",
	kubernetes.PodID:             "ID",
	overlay.WeaveDNSHostname:     "Weave DNS Hostname",
	overlay.WeaveMACAddress:      "Weave MAC",
	process.CPUUsage:             "CPU",
	process.Cmdline:              "Command",
	process.MemoryUsage:          "Memory",
	process.PID:                  "PID",
	process.PPID:                 "Parent PID",
	process.Threads:              "# Threads",
	render.ContainersKey:         "# Containers",
}

// Label maps from the internal keys to the human-readable label for a piece
// of metadata/set/etc. If none is found the raw key will be returned.
func Label(key string) string {
	if label, ok := labels[key]; ok {
		return label
	}
	if strings.HasPrefix(key, "label_") {
		return strings.TrimPrefix(key, "label_")
	}
	return key
}
<commit_msg>shorten some labels which were truncated<commit_after>package detailed

import (
	"strings"

	"github.com/weaveworks/scope/probe/docker"
	"github.com/weaveworks/scope/probe/host"
	"github.com/weaveworks/scope/probe/kubernetes"
	"github.com/weaveworks/scope/probe/overlay"
	"github.com/weaveworks/scope/probe/process"
	"github.com/weaveworks/scope/render"
)

var labels = map[string]string{
	docker.CPUTotalUsage:         "CPU",
	docker.ContainerCommand:      "Command",
	docker.ContainerCreated:      "Created",
	docker.ContainerHostname:     "Hostname",
	docker.ContainerID:           "ID",
	docker.ContainerIPs:          "IPs",
	docker.ContainerPorts:        "Ports",
	docker.ContainerRestartCount: "Restart #",
	docker.ContainerState:        "State",
	docker.ContainerUptime:       "Uptime",
	docker.ImageID:               "Image ID",
	docker.MemoryUsage:           "Memory",
	host.CPUUsage:                "CPU",
	host.HostName:                "Hostname",
	host.KernelVersion:           "Kernel version",
	host.Load15:                  "Load (15m)",
	host.Load1:                   "Load (1m)",
	host.Load5:                   "Load (5m)",
	host.LocalNetworks:           "Local Networks",
	host.MemoryUsage:             "Memory",
	host.OS:                      "OS",
	host.Uptime:                  "Uptime",
	kubernetes.Namespace:         "Namespace",
	kubernetes.PodCreated:        "Created",
	kubernetes.PodID:             "ID",
	overlay.WeaveDNSHostname:     "Weave DNS Name",
	overlay.WeaveMACAddress:      "Weave MAC",
	process.CPUUsage:             "CPU",
	process.Cmdline:              "Command",
	process.MemoryUsage:          "Memory",
	process.PID:                  "PID",
	process.PPID:                 "Parent PID",
	process.Threads:              "# Threads",
	render.ContainersKey:         "# Containers",
}

// Label maps from the internal keys to the human-readable label for a piece
// of metadata/set/etc. If none is found the raw key will be returned.
func Label(key string) string {
	if label, ok := labels[key]; ok {
		return label
	}
	if strings.HasPrefix(key, "label_") {
		return strings.TrimPrefix(key, "label_")
	}
	return key
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	"database/sql"
	"encoding/hex"
	"fmt"
	"io"
	"os/exec"
	"strconv"
	"strings"
	"sync"

	"golang.org/x/crypto/scrypt"
	log "gopkg.in/inconshreveable/log15.v2"

	"github.com/lxc/lxd/shared"
)

var daemonConfigLock sync.Mutex
var daemonConfig map[string]*daemonConfigKey

type daemonConfigKey struct {
	valueType    string
	defaultValue string
	validValues  []string
	currentValue string
	hiddenValue  bool

	validator func(d *Daemon, key string, value string) error
	setter    func(d *Daemon, key string, value string) (string, error)
	trigger   func(d *Daemon, key string, value string)
}

func (k *daemonConfigKey) name() string {
	name := ""

	// Look for a matching entry in daemonConfig
	daemonConfigLock.Lock()
	for key, value := range daemonConfig {
		if value == k {
			name = key
			break
		}
	}
	daemonConfigLock.Unlock()

	return name
}

func (k *daemonConfigKey) Validate(d *Daemon, value string) error {
	// No need to validate when unsetting
	if value == "" {
		return nil
	}

	// Validate booleans
	if k.valueType == "bool" && !shared.StringInSlice(strings.ToLower(value), []string{"true", "false", "1", "0", "yes", "no", "on", "off"}) {
		return fmt.Errorf("Invalid value for a boolean: %s", value)
	}

	// Validate integers
	if k.valueType == "int" {
		_, err := strconv.ParseInt(value, 10, 64)
		if err != nil {
			return err
		}
	}

	// Check against valid values
	if k.validValues != nil && !shared.StringInSlice(value, k.validValues) {
		return fmt.Errorf("Invalid value, only the following values are allowed: %s", k.validValues)
	}

	// Run external validation function
	if k.validator != nil {
		err := k.validator(d, k.name(), value)
		if err != nil {
			return err
		}
	}

	return nil
}

func (k *daemonConfigKey) Set(d *Daemon, value string) error {
	var name string

	// Check if we are actually changing things
	oldValue := k.currentValue
	if oldValue == value {
		return nil
	}

	// Validate the new value
	err := k.Validate(d, value)
	if err != nil {
		return err
	}

	// Run external setting function
	if k.setter != nil {
		value, err = k.setter(d, k.name(), value)
		if err != nil {
			return err
		}
	}

	// Get the configuration key and make sure daemonConfig is sane
	name = k.name()
	if name == "" {
		return fmt.Errorf("Corrupted configuration cache")
	}

	// Actually apply the change
	daemonConfigLock.Lock()
	k.currentValue = value
	daemonConfigLock.Unlock()

	err = dbConfigValueSet(d.db, name, value)
	if err != nil {
		return err
	}

	return nil
}

func (k *daemonConfigKey) Get() string {
	value := k.currentValue

	// Get the default value if not set
	if value == "" {
		value = k.defaultValue
	}

	return value
}

func (k *daemonConfigKey) GetBool() bool {
	value := k.currentValue

	// Get the default value if not set
	if value == "" {
		value = k.defaultValue
	}

	// Convert to boolean
	return shared.IsTrue(value)
}

func (k *daemonConfigKey) GetInt64() int64 {
	value := k.currentValue

	// Get the default value if not set
	if value == "" {
		value = k.defaultValue
	}

	// Convert to int64
	ret, _ := strconv.ParseInt(value, 10, 64)
	return ret
}

func daemonConfigInit(db *sql.DB) error {
	// Set all the keys
	daemonConfig = map[string]*daemonConfigKey{
		"core.https_address":             &daemonConfigKey{valueType: "string", setter: daemonConfigSetAddress},
		"core.https_allowed_headers":     &daemonConfigKey{valueType: "string"},
		"core.https_allowed_methods":     &daemonConfigKey{valueType: "string"},
		"core.https_allowed_origin":      &daemonConfigKey{valueType: "string"},
		"core.https_allowed_credentials": &daemonConfigKey{valueType: "bool"},
		"core.proxy_http":                &daemonConfigKey{valueType: "string", setter: daemonConfigSetProxy},
		"core.proxy_https":               &daemonConfigKey{valueType: "string", setter: daemonConfigSetProxy},
		"core.proxy_ignore_hosts":        &daemonConfigKey{valueType: "string", setter: daemonConfigSetProxy},
		"core.trust_password":            &daemonConfigKey{valueType: "string", hiddenValue: true, setter: daemonConfigSetPassword},

		"images.auto_update_cached":    &daemonConfigKey{valueType: "bool", defaultValue: "true"},
		"images.auto_update_interval":  &daemonConfigKey{valueType: "int", defaultValue: "6"},
		"images.compression_algorithm": &daemonConfigKey{valueType: "string", validator: daemonConfigValidateCompression, defaultValue: "gzip"},
		"images.remote_cache_expiry":   &daemonConfigKey{valueType: "int", defaultValue: "10", trigger: daemonConfigTriggerExpiry},

		"storage.lvm_fstype":           &daemonConfigKey{valueType: "string", defaultValue: "ext4", validValues: []string{"ext4", "xfs"}},
		"storage.lvm_thinpool_name":    &daemonConfigKey{valueType: "string", defaultValue: "LXDPool", validator: storageLVMValidateThinPoolName},
		"storage.lvm_vg_name":          &daemonConfigKey{valueType: "string", validator: storageLVMValidateVolumeGroupName, setter: daemonConfigSetStorage},
		"storage.lvm_volume_size":      &daemonConfigKey{valueType: "string", defaultValue: "10GiB"},
		"storage.zfs_pool_name":        &daemonConfigKey{valueType: "string", validator: storageZFSValidatePoolName, setter: daemonConfigSetStorage},
		"storage.zfs_remove_snapshots": &daemonConfigKey{valueType: "bool"},
		"storage.zfs_use_refquota":     &daemonConfigKey{valueType: "bool"},
	}

	// Load the values from the DB
	dbValues, err := dbConfigValuesGet(db)
	if err != nil {
		return err
	}

	daemonConfigLock.Lock()
	for k, v := range dbValues {
		_, ok := daemonConfig[k]
		if !ok {
			shared.Log.Error("Found invalid configuration key in database", log.Ctx{"key": k})
		}

		daemonConfig[k].currentValue = v
	}
	daemonConfigLock.Unlock()

	return nil
}

func daemonConfigRender() map[string]interface{} {
	config := map[string]interface{}{}

	// Turn the config into a JSON-compatible map
	for k, v := range daemonConfig {
		value := v.Get()
		if value != v.defaultValue {
			if v.hiddenValue {
				config[k] = true
			} else {
				config[k] = value
			}
		}
	}

	return config
}

func daemonConfigSetPassword(d *Daemon, key string, value string) (string, error) {
	// Nothing to do on unset
	if value == "" {
		return value, nil
	}

	// Hash the password
	buf := make([]byte, 32)
	_, err := io.ReadFull(rand.Reader, buf)
	if err != nil {
		return "", err
	}

	hash, err := scrypt.Key([]byte(value), buf, 1<<14, 8, 1, 64)
	if err != nil {
		return "", err
	}

	buf = append(buf, hash...)
	value = hex.EncodeToString(buf)

	return value, nil
}

func daemonConfigSetStorage(d *Daemon, key string, value string) (string, error) {
	// The storage driver looks at daemonConfig so just set it temporarily
	daemonConfigLock.Lock()
	oldValue := daemonConfig[key].Get()
	daemonConfig[key].currentValue = value
	daemonConfigLock.Unlock()

	defer func() {
		daemonConfigLock.Lock()
		daemonConfig[key].currentValue = oldValue
		daemonConfigLock.Unlock()
	}()

	// Update the current storage driver
	err := d.SetupStorageDriver()
	if err != nil {
		return "", err
	}

	return value, nil
}

func daemonConfigSetAddress(d *Daemon, key string, value string) (string, error) {
	// Update the current https address
	err := d.UpdateHTTPsPort(value)
	if err != nil {
		return "", err
	}

	return value, nil
}

func daemonConfigSetProxy(d *Daemon, key string, value string) (string, error) {
	// Get the current config
	config := map[string]string{}
	config["core.proxy_https"] = daemonConfig["core.proxy_https"].Get()
	config["core.proxy_http"] = daemonConfig["core.proxy_http"].Get()
	config["core.proxy_ignore_hosts"] = daemonConfig["core.proxy_ignore_hosts"].Get()

	// Apply the change
	config[key] = value

	// Update the cached proxy function
	d.proxy = shared.ProxyFromConfig(
		config["core.proxy_https"],
		config["core.proxy_http"],
		config["core.proxy_ignore_hosts"],
	)

	// Clear the simplestreams cache as it's tied to the old proxy config
	imageStreamCacheLock.Lock()
	for k, _ := range imageStreamCache {
		delete(imageStreamCache, k)
	}
	imageStreamCacheLock.Unlock()

	return value, nil
}

func daemonConfigTriggerExpiry(d *Daemon, key string, value string) {
	// Trigger an image pruning run
	d.pruneChan <- true
}

func daemonConfigValidateCompression(d *Daemon, key string, value string) error {
	if value == "none" {
		return nil
	}

	_, err := exec.LookPath(value)
	return err
}
<commit_msg>lxd/daemon_config: switch to new logging functions<commit_after>package main

import (
	"crypto/rand"
	"database/sql"
	"encoding/hex"
	"fmt"
	"io"
	"os/exec"
	"strconv"
	"strings"
	"sync"

	"golang.org/x/crypto/scrypt"
	log "gopkg.in/inconshreveable/log15.v2"

	"github.com/lxc/lxd/shared"
)

var daemonConfigLock sync.Mutex
var daemonConfig map[string]*daemonConfigKey

type daemonConfigKey struct {
	valueType    string
	defaultValue string
	validValues  []string
	currentValue string
	hiddenValue  bool

	validator func(d *Daemon, key string, value string) error
	setter    func(d *Daemon, key string, value string) (string, error)
	trigger   func(d *Daemon, key string, value string)
}

func (k *daemonConfigKey) name() string {
	name := ""

	// Look for a matching entry in daemonConfig
	daemonConfigLock.Lock()
	for key, value := range daemonConfig {
		if value == k {
			name = key
			break
		}
	}
	daemonConfigLock.Unlock()

	return name
}

func (k *daemonConfigKey) Validate(d *Daemon, value string) error {
	// No need to validate when unsetting
	if value == "" {
		return nil
	}

	// Validate booleans
	if k.valueType == "bool" && !shared.StringInSlice(strings.ToLower(value), []string{"true", "false", "1", "0", "yes", "no", "on", "off"}) {
		return fmt.Errorf("Invalid value for a boolean: %s", value)
	}

	// Validate integers
	if k.valueType == "int" {
		_, err := strconv.ParseInt(value, 10, 64)
		if err != nil {
			return err
		}
	}

	// Check against valid values
	if k.validValues != nil && !shared.StringInSlice(value, k.validValues) {
		return fmt.Errorf("Invalid value, only the following values are allowed: %s", k.validValues)
	}

	// Run external validation function
	if k.validator != nil {
		err := k.validator(d, k.name(), value)
		if err != nil {
			return err
		}
	}

	return nil
}

func (k *daemonConfigKey) Set(d *Daemon, value string) error {
	var name string

	// Check if we are actually changing things
	oldValue := k.currentValue
	if oldValue == value {
		return nil
	}

	// Validate the new value
	err := k.Validate(d, value)
	if err != nil {
		return err
	}

	// Run external setting function
	if k.setter != nil {
		value, err = k.setter(d, k.name(), value)
		if err != nil {
			return err
		}
	}

	// Get the configuration key and make sure daemonConfig is sane
	name = k.name()
	if name == "" {
		return fmt.Errorf("Corrupted configuration cache")
	}

	// Actually apply the change
	daemonConfigLock.Lock()
	k.currentValue = value
	daemonConfigLock.Unlock()

	err = dbConfigValueSet(d.db, name, value)
	if err != nil {
		return err
	}

	return nil
}

func (k *daemonConfigKey) Get() string {
	value := k.currentValue

	// Get the default value if not set
	if value == "" {
		value = k.defaultValue
	}

	return value
}

func (k *daemonConfigKey) GetBool() bool {
	value := k.currentValue

	// Get the default value if not set
	if value == "" {
		value = k.defaultValue
	}

	// Convert to boolean
	return shared.IsTrue(value)
}

func (k *daemonConfigKey) GetInt64() int64 {
	value := k.currentValue

	// Get the default value if not set
	if value == "" {
		value = k.defaultValue
	}

	// Convert to int64
	ret, _ := strconv.ParseInt(value, 10, 64)
	return ret
}

func daemonConfigInit(db *sql.DB) error {
	// Set all the keys
	daemonConfig = map[string]*daemonConfigKey{
		"core.https_address":             &daemonConfigKey{valueType: "string", setter: daemonConfigSetAddress},
		"core.https_allowed_headers":     &daemonConfigKey{valueType: "string"},
		"core.https_allowed_methods":     &daemonConfigKey{valueType: "string"},
		"core.https_allowed_origin":      &daemonConfigKey{valueType: "string"},
		"core.https_allowed_credentials": &daemonConfigKey{valueType: "bool"},
		"core.proxy_http":                &daemonConfigKey{valueType: "string", setter: daemonConfigSetProxy},
		"core.proxy_https":               &daemonConfigKey{valueType: "string", setter: daemonConfigSetProxy},
		"core.proxy_ignore_hosts":        &daemonConfigKey{valueType: "string", setter: daemonConfigSetProxy},
		"core.trust_password":            &daemonConfigKey{valueType: "string", hiddenValue: true, setter: daemonConfigSetPassword},

		"images.auto_update_cached":    &daemonConfigKey{valueType: "bool", defaultValue: "true"},
		"images.auto_update_interval":  &daemonConfigKey{valueType: "int", defaultValue: "6"},
		"images.compression_algorithm": &daemonConfigKey{valueType: "string", validator: daemonConfigValidateCompression, defaultValue: "gzip"},
		"images.remote_cache_expiry":   &daemonConfigKey{valueType: "int", defaultValue: "10", trigger: daemonConfigTriggerExpiry},

		"storage.lvm_fstype":           &daemonConfigKey{valueType: "string", defaultValue: "ext4", validValues: []string{"ext4", "xfs"}},
		"storage.lvm_thinpool_name":    &daemonConfigKey{valueType: "string", defaultValue: "LXDPool", validator: storageLVMValidateThinPoolName},
		"storage.lvm_vg_name":          &daemonConfigKey{valueType: "string", validator: storageLVMValidateVolumeGroupName, setter: daemonConfigSetStorage},
		"storage.lvm_volume_size":      &daemonConfigKey{valueType: "string", defaultValue: "10GiB"},
		"storage.zfs_pool_name":        &daemonConfigKey{valueType: "string", validator: storageZFSValidatePoolName, setter: daemonConfigSetStorage},
		"storage.zfs_remove_snapshots": &daemonConfigKey{valueType: "bool"},
		"storage.zfs_use_refquota":     &daemonConfigKey{valueType: "bool"},
	}

	// Load the values from the DB
	dbValues, err := dbConfigValuesGet(db)
	if err != nil {
		return err
	}

	daemonConfigLock.Lock()
	for k, v := range dbValues {
		_, ok := daemonConfig[k]
		if !ok {
			shared.LogError("Found invalid configuration key in database", log.Ctx{"key": k})
		}

		daemonConfig[k].currentValue = v
	}
	daemonConfigLock.Unlock()

	return nil
}

func daemonConfigRender() map[string]interface{} {
	config := map[string]interface{}{}

	// Turn the config into a JSON-compatible map
	for k, v := range daemonConfig {
		value := v.Get()
		if value != v.defaultValue {
			if v.hiddenValue {
				config[k] = true
			} else {
				config[k] = value
			}
		}
	}

	return config
}

func daemonConfigSetPassword(d *Daemon, key string, value string) (string, error) {
	// Nothing to do on unset
	if value == "" {
		return value, nil
	}

	// Hash the password
	buf := make([]byte, 32)
	_, err := io.ReadFull(rand.Reader, buf)
	if err != nil {
		return "", err
	}

	hash, err := scrypt.Key([]byte(value), buf, 1<<14, 8, 1, 64)
	if err != nil {
		return "", err
	}

	buf = append(buf, hash...)
	value = hex.EncodeToString(buf)

	return value, nil
}

func daemonConfigSetStorage(d *Daemon, key string, value string) (string, error) {
	// The storage driver looks at daemonConfig so just set it temporarily
	daemonConfigLock.Lock()
	oldValue := daemonConfig[key].Get()
	daemonConfig[key].currentValue = value
	daemonConfigLock.Unlock()

	defer func() {
		daemonConfigLock.Lock()
		daemonConfig[key].currentValue = oldValue
		daemonConfigLock.Unlock()
	}()

	// Update the current storage driver
	err := d.SetupStorageDriver()
	if err != nil {
		return "", err
	}

	return value, nil
}

func daemonConfigSetAddress(d *Daemon, key string, value string) (string, error) {
	// Update the current https address
	err := d.UpdateHTTPsPort(value)
	if err != nil {
		return "", err
	}

	return value, nil
}

func daemonConfigSetProxy(d *Daemon, key string, value string) (string, error) {
	// Get the current config
	config := map[string]string{}
	config["core.proxy_https"] = daemonConfig["core.proxy_https"].Get()
	config["core.proxy_http"] = daemonConfig["core.proxy_http"].Get()
	config["core.proxy_ignore_hosts"] = daemonConfig["core.proxy_ignore_hosts"].Get()

	// Apply the change
	config[key] = value

	// Update the cached proxy function
	d.proxy = shared.ProxyFromConfig(
		config["core.proxy_https"],
		config["core.proxy_http"],
		config["core.proxy_ignore_hosts"],
	)

	// Clear the simplestreams cache as it's tied to the old proxy config
	imageStreamCacheLock.Lock()
	for k, _ := range imageStreamCache {
		delete(imageStreamCache, k)
	}
	imageStreamCacheLock.Unlock()

	return value, nil
}

func daemonConfigTriggerExpiry(d *Daemon, key string, value string) {
	// Trigger an image pruning run
	d.pruneChan <- true
}

func daemonConfigValidateCompression(d *Daemon, key string, value string) error {
	if value == "none" {
		return nil
	}

	_, err := exec.LookPath(value)
	return err
}
<|endoftext|>


<commit_before>package types

import (
	"database/sql/driver"
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
	"strings"
	"time"
)

// DateTime хранит дату-время и шаблон для преобразования при сериализации
type DateTime struct {
	time.Time
	Layout string
}

// Date хранит дату и шаблон для преобразования при сериализации
type Date struct {
	time.Time
	Layout string
}

// timeModifier это интерфейс для обобщённых функций scan() и unmarshalJSON()
// для объектов Date и DateTime
type timeModifier interface {
	setTime(time.Time)
	setDefaultLayoutIfEmpty()
	parse(string) error
}

// Шаблоны для сериализации
const (
	DateTimeLayout        = "2006-01-02 15:04:05"
	DateLayout            = "2006-01-02"
	GraphsDateLayout      = "02.01.2006"
	GraphsDateShortLayout = "02.01"
)

// defaultLocation хранит значение по умолчанию для Location
var defaultLocation *time.Location

// Задаёт часовой пояс по умолчанию
func init() {
	var err error
	defaultLocation, err = time.LoadLocation("Europe/Moscow")
	if err != nil {
		fmt.Println("Ошибка time.LoadLocation")
	}
}

// ToDateTime формирует объект типа DateTime на основе времени t и шаблона DateTimeLayout
func ToDateTime(t time.Time) DateTime {
	return DateTime{t.In(defaultLocation), DateTimeLayout}
}

// ToDate формирует объект типа Date на основе времени t и шаблона DateLayout
func ToDate(t time.Time) Date {
	dS := fmt.Sprintf("%s %02d:%02d:%02d", t.Format(DateLayout), 0, 0, 0)
	d, _ := time.ParseInLocation(DateTimeLayout, dS, defaultLocation)
	return Date{d.In(defaultLocation), DateLayout}
}

// DaysBefore возвращает количество полных дней, прошедших от d до endDate
// Например, если d было вчера, endDate - сегодня, то возвращается 1
// Если endDate было раньше чем d, то возвращается отрицательное число.
func (d Date) DaysBefore(endDate Date) int {
	return int(endDate.Time.Sub(d.Time).Hours() / 24)
}

// StringToDateTime формирует объект типа DateTime на основе строки s,
// заданной по шаблону DateTimeLayout
func StringToDateTime(s string) (DateTime, error) {
	t, err := time.ParseInLocation(DateTimeLayout, s, defaultLocation)
	if err != nil {
		return DateTime{}, err
	}
	return ToDateTime(t), nil
}

// StringDateToDateTimeHMS формирует объект типа DateTime на основе строки s,
// заданной по шаблону DateTimeLayout, и значений часов, минут и секунд,
// заданных параметрами hours, mins, secs соответственно.
func StringDateToDateTimeHMS(s string, hours int, mins int, secs int) (DateTime, error) {
	t, err := time.ParseInLocation(DateLayout, s, defaultLocation)
	if err != nil {
		return DateTime{}, err
	}
	d := ToDateTime(t)
	d = d.SetHMS(hours, mins, secs)
	return d, nil
}

// StringToDate формирует объект типа Date на основе строки s, заданной по шаблону DateLayout
func StringToDate(s string) (Date, error) {
	t, err := time.ParseInLocation(DateLayout, s, defaultLocation)
	if err != nil {
		return Date{}, err
	}
	return ToDate(t), nil
}

// NeverDate возвращает объект Date, соответствующий дате в далёком прошлом
func NeverDate() Date {
	t, _ := time.ParseInLocation(DateLayout, "1990-01-01", defaultLocation)
	return ToDate(t)
}

// DateNow возвращает объект Date, соответствующий дате сегодня
func DateNow() Date {
	return ToDate(time.Now())
}

// DateTimeNow возвращает объект DateTime, соответствующий дате-времени сейчас
func DateTimeNow() DateTime {
	return ToDateTime(time.Now())
}

// DateTimeTodayHMS возвращает объект DateTime, соответствующий дате сегодня,
// с установленными значениями часов, минут, секунд согласно заданным параметрам
// hours, mins, secs соответственно.
func DateTimeTodayHMS(hours int, mins int, secs int) DateTime {
	d := ToDateTime(time.Now())
	return d.SetHMS(hours, mins, secs)
}

// NeverTime возвращает объект DateTime, соответствующий дате-времени в далёком прошлом
func NeverTime() DateTime {
	t, _ := time.ParseInLocation(DateTimeLayout, "1990-01-01 00:00:00", defaultLocation)
	return ToDateTime(t)
}

// setDefaultLayoutIfEmpty устанавливает в объекте DateTime шаблон вывода даты-времени
// по умолчанию DateTimeLayout, если шаблон не установлен
func (d *DateTime) setDefaultLayoutIfEmpty() {
	if strings.TrimSpace(d.Layout) == "" {
		d.Layout = DateTimeLayout
	}
}

// setDefaultLayoutIfEmpty устанавливает в объекте Date шаблон вывода даты
// по умолчанию DateLayout, если шаблон не установлен
func (d *Date) setDefaultLayoutIfEmpty() {
	if strings.TrimSpace(d.Layout) == "" {
		d.Layout = DateLayout
	}
}

// setTime устанавливает время в объекте Date без учёта Location
func (d *Date) setTime(t time.Time) {
	d.Time = t
}

// setTime устанавливает время в объекте DateTime без учёта Location
func (d *DateTime) setTime(t time.Time) {
	d.Time = t
}

// parse устанавливает время в объекте Date на основе строки s и
// Location defaultLocation
func (d *Date) parse(s string) error {
	t, err := time.ParseInLocation(d.Layout, s, defaultLocation)
	if err == nil {
		d.setTime(t)
	}
	return err
}

// parse устанавливает время в объекте DateTime на основе строки s и
// Location defaultLocation
func (d *DateTime) parse(s string) error {
	t, err := time.ParseInLocation(d.Layout, s, defaultLocation)
	if err == nil {
		d.setTime(t)
	}
	return err
}

// SetHMS возвращает новый объект DateTime на основе объекта d,
// с заданными значениями часов, минут, секунд в параметрах
// hours, mins, secs соответственно.
func (d DateTime) SetHMS(hours int, mins int, secs int) DateTime {
	t := d.Time
	dS := fmt.Sprintf("%s %02d:%02d:%02d", t.Format(DateLayout), hours, mins, secs)
	dt, _ := time.ParseInLocation(DateTimeLayout, dS, defaultLocation)
	d.Time = dt
	return d
}

// ConvertToDate преобразует объект DateTime в объект Date
func (d DateTime) ConvertToDate() Date {
	dS := d.Time.Format(DateLayout)
	t, _ := time.ParseInLocation(DateLayout, dS, defaultLocation)
	return ToDate(t)
}

// ConvertToDateTimeHMS преобразует объект Date в объект DateTime
// с учётом заданных часов, минут, секунд в параметрах hours, mind, secs соответственно.
func (d Date) ConvertToDateTimeHMS(hours int, mins int, secs int) DateTime {
	dt := DateTime{
		Time:   d.Time,
		Layout: d.Layout,
	}
	dt = dt.SetHMS(hours, mins, secs)

	return dt
}

// After возвращает true если дата d позднее d1, иначе false
// Сравнение происходит с точностью до дня.
func (d Date) After(d1 Date) bool {
	return d.Time.After(d1.Time)
}

// Before возвращает true если дата d ранее d1, иначе false
// Сравнение происходит с точностью до дня.
func (d Date) Before(d1 Date) bool {
	return d.Time.Before(d1.Time)
}

// Between возвращает true если дата d находится в интервале дат (d1; d2), иначе false
// Сравнение происходит с точностью до дня.
func (d Date) Between(d1, d2 Date) bool {
	return d.After(d1) && d.Before(d2)
}

// After возвращает true если дата-время d позднее d1, иначе false
func (d DateTime) After(d1 DateTime) bool {
	return d.Time.After(d1.Time)
}

// Before возвращает true если дата-время d ранее d1, иначе false
func (d DateTime) Before(d1 DateTime) bool {
	return d.Time.Before(d1.Time)
}

// Between возвращает true если дата-время d находится в интервале
// даты-времени (d1; d2), иначе false
func (d DateTime) Between(d1, d2 DateTime) bool {
	return d.After(d1) && d.Before(d2)
}

func unmarshalJSON(data []byte, to timeModifier) error {
	to.setDefaultLayoutIfEmpty()
	var s string
	if err := json.Unmarshal(data, &s); err != nil {
		return err
	}
	return to.parse(s)
}

// UnmarshalJSON - реализует интерфейс json.Unmarshaler для объекта DateTime
// десериализация происходит с учётом шаблона, заданного в свойстве Layout
func (d *DateTime) UnmarshalJSON(data []byte) error {
	return unmarshalJSON(data, d)
}

// MarshalJSON - реализует интерфейс json.Marshaler для объекта DateTime
// сериализация происходит с учётом шаблона, заданного в свойстве Layout
func (d DateTime) MarshalJSON() ([]byte, error) {
	d.setDefaultLayoutIfEmpty()
	return []byte(strconv.Quote(d.String())), nil
}

// UnmarshalJSON - реализует интерфейс json.Unmarshaler для объекта Date
// десериализация происходит с учётом шаблона, заданного в свойстве Layout
func (d *Date) UnmarshalJSON(data []byte) error {
	return unmarshalJSON(data, d)
}

// MarshalJSON - реализует интерфейс json.Marshaler для объекта Date
// сериализация происходит с учётом шаблона, заданного в свойстве Layout
func (d Date) MarshalJSON() ([]byte, error) {
	d.setDefaultLayoutIfEmpty()
	return []byte(strconv.Quote(d.String())), nil
}

// String преобразует объект DateTime в строку согласно шаблона в свойстве Layout
func (d DateTime) String() string {
	d.setDefaultLayoutIfEmpty()
	return d.Time.Format(d.Layout)
}

// String преобразует объект Date в строку согласно шаблона в свойстве Layout
func (d Date) String() string {
	d.setDefaultLayoutIfEmpty()
	return d.Time.Format(d.Layout)
}

func scan(from interface{}, to timeModifier) error {
	if from == nil {
		return nil
	}

	t := time.Time{}
	t, ok := from.(time.Time)
	if !ok {
		return errors.New("Ошибка преобразования значения к типу time.Time")
	}

	to.setTime(t.In(defaultLocation))
	to.setDefaultLayoutIfEmpty()
	return nil
}

// Scan преобразует значение времени в БД к типу DateTime
// Реализует интерфейс sql.Scanner
func (d *DateTime) Scan(value interface{}) error {
	return scan(value, d)
}

// Value преобразует значение типа DateTime к значению в БД
// Реализует интерфейс driver.Valuer
func (d DateTime) Value() (driver.Value, error) {
	return d.Time.In(defaultLocation).Format(DateTimeLayout), nil
}

// Scan преобразует значение времени в БД к типу Date
// Реализует интерфейс sql.Scanner
func (d *Date) Scan(value interface{}) error {
	return scan(value, d)
}

// Value преобразует значение типа Date к значению в БД
// Реализует интерфейс driver.Valuer
func (d Date) Value() (driver.Value, error) {
	return d.Time.In(defaultLocation).Format(DateLayout), nil
}
<commit_msg>Добавил функцию getLayout, изменил parse<commit_after>package types

import (
	"database/sql/driver"
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
	"strings"
	"time"
)

// DateTime хранит дату-время и шаблон для преобразования при сериализации
type DateTime struct {
	time.Time
	Layout string
}

// Date хранит дату и шаблон для преобразования при сериализации
type Date struct {
	time.Time
	Layout string
}

type timeSetter interface {
	setTime(time.Time)
	setDefaultLayoutIfEmpty()
	getLayout() string
}

// Шаблоны для сериализации
const (
	DateTimeLayout        = "2006-01-02 15:04:05"
	DateLayout            = "2006-01-02"
	GraphsDateLayout      = "02.01.2006"
	GraphsDateShortLayout = "02.01"
)

// defaultLocation хранит значение по умолчанию для Location
var defaultLocation *time.Location

// Задаёт часовой пояс по умолчанию
func init() {
	var err error
	defaultLocation, err = time.LoadLocation("Europe/Moscow")
	if err != nil {
		fmt.Println("Ошибка time.LoadLocation")
	}
}

// ToDateTime формирует объект типа DateTime на основе времени t и шаблона DateTimeLayout
func ToDateTime(t time.Time) DateTime {
	return DateTime{t.In(defaultLocation), DateTimeLayout}
}

// ToDate формирует объект типа Date на основе времени t и шаблона DateLayout
func ToDate(t time.Time) Date {
	dS := fmt.Sprintf("%s %02d:%02d:%02d", t.Format(DateLayout), 0, 0, 0)
	d, _ := time.ParseInLocation(DateTimeLayout, dS, defaultLocation)
	return Date{d.In(defaultLocation), DateLayout}
}

// DaysBefore возвращает количество полных дней, прошедших от d до endDate
// Например, если d было вчера, endDate - сегодня, то возвращается 1
// Если endDate было раньше чем d, то возвращается отрицательное число.
func (d Date) DaysBefore(endDate Date) int {
	return int(endDate.Time.Sub(d.Time).Hours() / 24)
}

// StringToDateTime формирует объект типа DateTime на основе строки s,
// заданной по шаблону DateTimeLayout
func StringToDateTime(s string) (DateTime, error) {
	t, err := time.ParseInLocation(DateTimeLayout, s, defaultLocation)
	if err != nil {
		return DateTime{}, err
	}
	return ToDateTime(t), nil
}

// StringDateToDateTimeHMS формирует объект типа DateTime на основе строки s,
// заданной по шаблону DateTimeLayout, и значений часов, минут и секунд,
// заданных параметрами hours, mins, secs соответственно.
func StringDateToDateTimeHMS(s string, hours int, mins int, secs int) (DateTime, error) {
	t, err := time.ParseInLocation(DateLayout, s, defaultLocation)
	if err != nil {
		return DateTime{}, err
	}
	d := ToDateTime(t)
	d = d.SetHMS(hours, mins, secs)
	return d, nil
}

// StringToDate формирует объект типа Date на основе строки s, заданной по шаблону DateLayout
func StringToDate(s string) (Date, error) {
	t, err := time.ParseInLocation(DateLayout, s, defaultLocation)
	if err != nil {
		return Date{}, err
	}
	return ToDate(t), nil
}

// NeverDate возвращает объект Date, соответствующий дате в далёком прошлом
func NeverDate() Date {
	t, _ := time.ParseInLocation(DateLayout, "1990-01-01", defaultLocation)
	return ToDate(t)
}

// DateNow возвращает объект Date, соответствующий дате сегодня
func DateNow() Date {
	return ToDate(time.Now())
}

// DateTimeNow возвращает объект DateTime, соответствующий дате-времени сейчас
func DateTimeNow() DateTime {
	return ToDateTime(time.Now())
}

// DateTimeTodayHMS возвращает объект DateTime, соответствующий дате сегодня,
// с установленными значениями часов, минут, секунд согласно заданным параметрам
// hours, mins, secs соответственно.
func DateTimeTodayHMS(hours int, mins int, secs int) DateTime {
	d := ToDateTime(time.Now())
	return d.SetHMS(hours, mins, secs)
}

// NeverTime возвращает объект DateTime, соответствующий дате-времени в далёком прошлом
func NeverTime() DateTime {
	t, _ := time.ParseInLocation(DateTimeLayout, "1990-01-01 00:00:00", defaultLocation)
	return ToDateTime(t)
}

// setDefaultLayoutIfEmpty устанавливает в объекте DateTime шаблон вывода даты-времени
// по умолчанию DateTimeLayout, если шаблон не установлен
func (d *DateTime) setDefaultLayoutIfEmpty() {
	if strings.TrimSpace(d.Layout) == "" {
		d.Layout = DateTimeLayout
	}
}

// setDefaultLayoutIfEmpty устанавливает в объекте Date шаблон вывода даты
// по умолчанию DateLayout, если шаблон не установлен
func (d *Date) setDefaultLayoutIfEmpty() {
	if strings.TrimSpace(d.Layout) == "" {
		d.Layout = DateLayout
	}
}

// setTime устанавливает время в объекте Date без учёта Location
func (d *Date) setTime(t time.Time) {
	d.Time = t
}

// setTime устанавливает время в объекте DateTime без учёта Location
func (d *DateTime) setTime(t time.Time) {
	d.Time = t
}

// getLayout возвращает строку шаблона вывода в объекте Date
func (d Date) getLayout() string {
	return d.Layout
}

// getLayout возвращает строку шаблона вывода в объекте DateTime
func (d DateTime) getLayout() string {
	return d.Layout
}

// parse устанавливает время в объекте, реализующем интерфейс timeSetter
// на основе строки s и Location defaultLocation
func parse(d timeSetter, s string) error {
	t, err := time.ParseInLocation(d.getLayout(), s, defaultLocation)
	if err == nil {
		d.setTime(t)
	}
	return err
}

// SetHMS возвращает новый объект DateTime на основе объекта d,
// с заданными значениями часов, минут, секунд в параметрах
// hours, mins, secs соответственно.
func (d DateTime) SetHMS(hours int, mins int, secs int) DateTime {
	t := d.Time
	dS := fmt.Sprintf("%s %02d:%02d:%02d", t.Format(DateLayout), hours, mins, secs)
	dt, _ := time.ParseInLocation(DateTimeLayout, dS, defaultLocation)
	d.Time = dt
	return d
}

// ConvertToDate преобразует объект DateTime в объект Date
func (d DateTime) ConvertToDate() Date {
	dS := d.Time.Format(DateLayout)
	t, _ := time.ParseInLocation(DateLayout, dS, defaultLocation)
	return ToDate(t)
}

// ConvertToDateTimeHMS преобразует объект Date в объект DateTime
// с учётом заданных часов, минут, секунд в параметрах hours, mind, secs соответственно.
func (d Date) ConvertToDateTimeHMS(hours int, mins int, secs int) DateTime {
	dt := DateTime{
		Time:   d.Time,
		Layout: d.Layout,
	}
	dt = dt.SetHMS(hours, mins, secs)

	return dt
}

// After возвращает true если дата d позднее d1, иначе false
// Сравнение происходит с точностью до дня.
func (d Date) After(d1 Date) bool {
	return d.Time.After(d1.Time)
}

// Before возвращает true если дата d ранее d1, иначе false
// Сравнение происходит с точностью до дня.
func (d Date) Before(d1 Date) bool {
	return d.Time.Before(d1.Time)
}

// Between возвращает true если дата d находится в интервале дат (d1; d2), иначе false
// Сравнение происходит с точностью до дня.
func (d Date) Between(d1, d2 Date) bool {
	return d.After(d1) && d.Before(d2)
}

// After возвращает true если дата-время d позднее d1, иначе false
func (d DateTime) After(d1 DateTime) bool {
	return d.Time.After(d1.Time)
}

// Before возвращает true если дата-время d ранее d1, иначе false
func (d DateTime) Before(d1 DateTime) bool {
	return d.Time.Before(d1.Time)
}

// Between возвращает true если дата-время d находится в интервале
// даты-времени (d1; d2), иначе false
func (d DateTime) Between(d1, d2 DateTime) bool {
	return d.After(d1) && d.Before(d2)
}

func unmarshalJSON(data []byte, to timeSetter) error {
	to.setDefaultLayoutIfEmpty()
	var s string
	if err := json.Unmarshal(data, &s); err != nil {
		return err
	}
	return parse(to, s)
}

// UnmarshalJSON - реализует интерфейс json.Unmarshaler для объекта DateTime
// десериализация происходит с учётом шаблона, заданного в свойстве Layout
func (d *DateTime) UnmarshalJSON(data []byte) error {
	return unmarshalJSON(data, d)
}

// MarshalJSON - реализует интерфейс json.Marshaler для объекта DateTime
// сериализация происходит с учётом шаблона, заданного в свойстве Layout
func (d DateTime) MarshalJSON() ([]byte, error) {
	d.setDefaultLayoutIfEmpty()
	return []byte(strconv.Quote(d.String())), nil
}

// UnmarshalJSON - реализует интерфейс json.Unmarshaler для объекта Date
// десериализация происходит с учётом шаблона, заданного в свойстве Layout
func (d *Date) UnmarshalJSON(data []byte) error {
	return unmarshalJSON(data, d)
}

// MarshalJSON - реализует интерфейс json.Marshaler для объекта Date
// сериализация происходит с учётом шаблона, заданного в свойстве Layout
func (d Date) MarshalJSON() ([]byte, error) {
	d.setDefaultLayoutIfEmpty()
	return []byte(strconv.Quote(d.String())), nil
}

// String преобразует объект DateTime в строку согласно шаблона в свойстве Layout
func (d DateTime) String() string {
	d.setDefaultLayoutIfEmpty()
	return d.Time.Format(d.Layout)
}

// String преобразует объект Date в строку согласно шаблона в свойстве Layout
func (d Date) String() string {
	d.setDefaultLayoutIfEmpty()
	return d.Time.Format(d.Layout)
}

func scan(from interface{}, to timeSetter) error {
	if from == nil {
		return nil
	}

	t := time.Time{}
	t, ok := from.(time.Time)
	if !ok {
		return errors.New("Ошибка преобразования значения к типу time.Time")
	}

	to.setTime(t.In(defaultLocation))
	to.setDefaultLayoutIfEmpty()
	return nil
}

// Scan преобразует значение времени в БД к типу DateTime
// Реализует интерфейс sql.Scanner
func (d *DateTime) Scan(value interface{}) error {
	return scan(value, d)
}

// Value преобразует значение типа DateTime к значению в БД
// Реализует интерфейс driver.Valuer
func (d DateTime) Value() (driver.Value, error) {
	return d.Time.In(defaultLocation).Format(DateTimeLayout), nil
}

// Scan преобразует значение времени в БД к типу Date
// Реализует интерфейс sql.Scanner
func (d *Date) Scan(value interface{}) error {
	return scan(value, d)
}

// Value преобразует значение типа Date к значению в БД
// Реализует интерфейс driver.Valuer
func (d Date) Value() (driver.Value, error) {
	return d.Time.In(defaultLocation).Format(DateLayout), nil
}
<|endoftext|>