<commit_before>package main

import (
	"net/http"
	"strings"
	"time"

	"facette/backend"
	"facette/connector"
	"facette/plot"
	"facette/template"
	"facette/timerange"

	"github.com/facette/httputil"
	"github.com/facette/sqlstorage"
	"github.com/hashicorp/go-uuid"
)

const (
	defaultTimeRange = "-1h"
)

type plotQuery struct {
	query     plot.Query
	queryMap  [][2]int
	connector connector.Connector
}

func (w *httpWorker) httpHandlePlots(rw http.ResponseWriter, r *http.Request) {
	var err error

	defer r.Body.Close()

	// Get plot request from received data
	req := &plot.Request{}
	if err := httputil.BindJSON(r, req); err == httputil.ErrInvalidContentType {
		httputil.WriteJSON(rw, httpBuildMessage(err), http.StatusUnsupportedMediaType)
		return
	} else if err != nil {
		w.log.Error("unable to unmarshal JSON data: %s", err)
		httputil.WriteJSON(rw, httpBuildMessage(ErrInvalidParameter), http.StatusBadRequest)
		return
	}

	// Request item from backend
	if req.ID != "" {
		req.Graph = w.service.backend.NewGraph()

		// Check for aliased item if identifier value isn't valid
		column := "id"
		if _, err := uuid.ParseUUID(req.ID); err != nil {
			column = "alias"
		}

		if err := w.service.backend.Storage().Get(column, req.ID, req.Graph, false); err == sqlstorage.ErrItemNotFound {
			httputil.WriteJSON(rw, httpBuildMessage(err), http.StatusNotFound)
			return
		} else if err != nil {
			w.log.Error("failed to fetch item: %s", err)
			httputil.WriteJSON(rw, httpBuildMessage(ErrUnhandledError), http.StatusInternalServerError)
			return
		}
	} else if req.Graph != nil {
		// Register back-end (needed for graph expansion)
		req.Graph.Item.SetBackend(w.service.backend)
	} else {
		httputil.WriteJSON(rw, httpBuildMessage(ErrInvalidParameter), http.StatusBadRequest)
		return
	}

	// Expand graph template if linked
	if err := req.Graph.Expand(req.Attributes); req.ID == "" && err == template.ErrInvalidTemplate {
		httputil.WriteJSON(rw, httpBuildMessage(err), http.StatusBadRequest)
		return
	} else if err != nil {
		w.log.Error("%s", err)
		httputil.WriteJSON(rw, httpBuildMessage(ErrUnhandledError), http.StatusInternalServerError)
		return
	}

	// Set request time boundaries and range
	// * both start and end time must be provided, or none
	// * range can't be specified if start and end are
	if req.StartTime.IsZero() && req.EndTime.IsZero() {
		if req.Time.IsZero() {
			req.Time = time.Now().UTC()
		}

		if req.Range == "" {
			if value, ok := req.Graph.Options["range"].(string); ok {
				req.Range = value
			} else {
				req.Range = defaultTimeRange
			}
		}

		if strings.HasPrefix(req.Range, "-") {
			req.EndTime = req.Time
			if req.StartTime, err = timerange.Apply(req.Time, req.Range); err != nil {
				w.log.Warning("unable to apply time range: %s", err)
				httputil.WriteJSON(rw, httpBuildMessage(ErrInvalidParameter), http.StatusBadRequest)
				return
			}
		} else {
			req.StartTime = req.Time
			if req.EndTime, err = timerange.Apply(req.Time, req.Range); err != nil {
				w.log.Warning("unable to apply time range: %s", err)
				httputil.WriteJSON(rw, httpBuildMessage(ErrInvalidParameter), http.StatusBadRequest)
				return
			}
		}
	} else if (req.StartTime.IsZero() || req.EndTime.IsZero()) || req.Range != "" {
		httputil.WriteJSON(rw, httpBuildMessage(ErrInvalidTimerange), http.StatusBadRequest)
		return
	}

	// Set default plot sample if none provided
	if req.Sample == 0 {
		req.Sample = plot.DefaultSample
	}

	// Execute plots request
	plots := plot.Response{
		Start:   req.StartTime.Format(time.RFC3339),
		End:     req.EndTime.Format(time.RFC3339),
		Series:  w.executeRequest(req),
		Options: req.Graph.Options,
	}

	// Set fallback title to graph name if none provided
	if plots.Options == nil {
		plots.Options = make(map[string]interface{})
	}

	if _, ok := plots.Options["title"]; !ok {
		plots.Options["title"] = req.Graph.Name
	}

	httputil.WriteJSON(rw, plots, http.StatusOK)
}

func (w *httpWorker) executeRequest(req *plot.Request) []plot.SeriesResponse {
	// Expand groups series
	for _, group := range req.Graph.Groups {
		expandedSeries := []*backend.Series{}
		for _, series := range group.Series {
			expandedSeries = append(expandedSeries, w.expandSeries(series, true)...)
		}
		group.Series = expandedSeries
	}

	// Dispatch plot queries among providers
	data := make([][]plot.Series, len(req.Graph.Groups))
	for i, group := range req.Graph.Groups {
		data[i] = make([]plot.Series, len(group.Series))
	}

	for _, q := range w.dispatchQueries(req) {
		series, err := q.connector.Plots(&q.query)
		if err != nil {
			w.log.Error("unable to fetch plots: %s", err)
			continue
		}

		count := len(series)
		expected := len(q.query.Series)
		if count != expected {
			w.log.Error("unable to fetch plots: expected %d series but got %d", expected, count)
			continue
		}

		// Put back series to its original indexes
		for i, s := range series {
			data[q.queryMap[i][0]][q.queryMap[i][1]] = s
		}
	}

	// Generate plots series
	result := []plot.SeriesResponse{}
	for i, group := range req.Graph.Groups {
		var (
			consolidate int
			interpolate bool
			err         error
		)

		// Skip processing if no data
		if len(data[i]) == 0 {
			goto finalize
		}

		// Apply series scale if any
		for j, series := range group.Series {
			if v, ok := series.Options["scale"].(float64); ok {
				data[i][j].Scale(plot.Value(v))
			}
		}

		// Get group consolidation mode and interpolation options
		consolidate = plot.ConsolidateAverage
		if v, ok := group.Options["consolidate"].(int); ok {
			consolidate = v
		}

		interpolate = true
		if v, ok := group.Options["interpolate"].(bool); ok {
			interpolate = v
		}

		// Normalize series and apply operations
		data[i], err = plot.Normalize(data[i], req.StartTime, req.EndTime, req.Sample, consolidate, interpolate)
		if err != nil {
			w.log.Error("failed to normalize series: %s", err)
			continue
		}

		switch group.Operator {
		case plot.OperatorAverage, plot.OperatorSum:
			var (
				series plot.Series
				err    error
			)

			if group.Operator == plot.OperatorAverage {
				series, err = plot.Average(data[i])
			} else {
				series, err = plot.Sum(data[i])
			}

			if err != nil {
				w.log.Error("failed to apply series operation: %s", err)
				continue
			}

			// Set series name to group name
			group.Series[0].Name = group.Name

			// Replace group series with operation result
			data[i] = []plot.Series{series}

		case plot.OperatorNone:
			// noop

		default:
			w.log.Warning("unknown %d operation type", group.Operator)
			continue
		}

	finalize:
		// Get group scale value
		scale, _ := group.Options["scale"].(float64)

		for j, series := range data[i] {
			// Apply group scale if any
			if scale != 0 {
				series.Scale(plot.Value(scale))
			}

			// Summarize series
			percentiles := []float64{}
			if slice, ok := req.Graph.Options["percentiles"].([]interface{}); ok {
				for _, entry := range slice {
					if val, ok := entry.(float64); ok {
						percentiles = append(percentiles, val)
					}
				}
			}

			series.Summarize(percentiles)

			result = append(result, plot.SeriesResponse{
				Series:  series,
				Name:    group.Series[j].Name,
				Options: group.Series[j].Options,
			})
		}
	}

	return result
}

func (w *httpWorker) dispatchQueries(req *plot.Request) []plotQuery {
	providers := make(map[string]*plotQuery)

	for i, group := range req.Graph.Groups {
		for j, series := range group.Series {
			if !series.IsValid() {
				w.log.Warning("invalid series metric: %s", series)
				continue
			}

			search := w.service.searcher.Metrics(series.Origin, series.Source, series.Metric, 1)
			if len(search) == 0 {
				w.log.Warning("unable to find series metric: %s", series)
				continue
			}

			// Get series connector and provider name
			c := search[0].Connector().(connector.Connector)
			provName := c.Name()

			// Initialize provider-specific plot query
			if _, ok := providers[provName]; !ok {
				providers[provName] = &plotQuery{
					query: plot.Query{
						StartTime: req.StartTime,
						EndTime:   req.EndTime,
						Sample:    req.Sample,
						Series:    []plot.QuerySeries{},
					},
					queryMap:  [][2]int{},
					connector: c,
				}
			}

			// Append new series to plot query and save series index
			providers[provName].query.Series = append(providers[provName].query.Series, plot.QuerySeries{
				Origin: search[0].Source().Origin().OriginalName,
				Source: search[0].Source().OriginalName,
				Metric: search[0].OriginalName,
			})

			providers[provName].queryMap = append(providers[provName].queryMap, [2]int{i, j})
		}
	}

	result := []plotQuery{}
	for _, q := range providers {
		result = append(result, *q)
	}

	return result
}
<commit_msg>Skip normalization for non-stacked graphs<commit_after>package main

import (
	"net/http"
	"strings"
	"time"

	"facette/backend"
	"facette/connector"
	"facette/plot"
	"facette/template"
	"facette/timerange"

	"github.com/facette/httputil"
	"github.com/facette/sqlstorage"
	"github.com/hashicorp/go-uuid"
)

const (
	defaultTimeRange = "-1h"
)

type plotQuery struct {
	query     plot.Query
	queryMap  [][2]int
	connector connector.Connector
}

func (w *httpWorker) httpHandlePlots(rw http.ResponseWriter, r *http.Request) {
	var err error

	defer r.Body.Close()

	// Get plot request from received data
	req := &plot.Request{}
	if err := httputil.BindJSON(r, req); err == httputil.ErrInvalidContentType {
		httputil.WriteJSON(rw, httpBuildMessage(err), http.StatusUnsupportedMediaType)
		return
	} else if err != nil {
		w.log.Error("unable to unmarshal JSON data: %s", err)
		httputil.WriteJSON(rw, httpBuildMessage(ErrInvalidParameter), http.StatusBadRequest)
		return
	}

	// Request item from backend
	if req.ID != "" {
		req.Graph = w.service.backend.NewGraph()

		// Check for aliased item if identifier value isn't valid
		column := "id"
		if _, err := uuid.ParseUUID(req.ID); err != nil {
			column = "alias"
		}

		if err := w.service.backend.Storage().Get(column, req.ID, req.Graph, false); err == sqlstorage.ErrItemNotFound {
			httputil.WriteJSON(rw, httpBuildMessage(err), http.StatusNotFound)
			return
		} else if err != nil {
			w.log.Error("failed to fetch item: %s", err)
			httputil.WriteJSON(rw, httpBuildMessage(ErrUnhandledError), http.StatusInternalServerError)
			return
		}
	} else if req.Graph != nil {
		// Register back-end (needed for graph expansion)
		req.Graph.Item.SetBackend(w.service.backend)
	} else {
		httputil.WriteJSON(rw, httpBuildMessage(ErrInvalidParameter), http.StatusBadRequest)
		return
	}

	// Expand graph template if linked
	if err := req.Graph.Expand(req.Attributes); req.ID == "" && err == template.ErrInvalidTemplate {
		httputil.WriteJSON(rw, httpBuildMessage(err), http.StatusBadRequest)
		return
	} else if err != nil {
		w.log.Error("%s", err)
		httputil.WriteJSON(rw, httpBuildMessage(ErrUnhandledError), http.StatusInternalServerError)
		return
	}

	// Set request time boundaries and range
	// * both start and end time must be provided, or none
	// * range can't be specified if start and end are
	if req.StartTime.IsZero() && req.EndTime.IsZero() {
		if req.Time.IsZero() {
			req.Time = time.Now().UTC()
		}

		if req.Range == "" {
			if value, ok := req.Graph.Options["range"].(string); ok {
				req.Range = value
			} else {
				req.Range = defaultTimeRange
			}
		}

		if strings.HasPrefix(req.Range, "-") {
			req.EndTime = req.Time
			if req.StartTime, err = timerange.Apply(req.Time, req.Range); err != nil {
				w.log.Warning("unable to apply time range: %s", err)
				httputil.WriteJSON(rw, httpBuildMessage(ErrInvalidParameter), http.StatusBadRequest)
				return
			}
		} else {
			req.StartTime = req.Time
			if req.EndTime, err = timerange.Apply(req.Time, req.Range); err != nil {
				w.log.Warning("unable to apply time range: %s", err)
				httputil.WriteJSON(rw, httpBuildMessage(ErrInvalidParameter), http.StatusBadRequest)
				return
			}
		}
	} else if (req.StartTime.IsZero() || req.EndTime.IsZero()) || req.Range != "" {
		httputil.WriteJSON(rw, httpBuildMessage(ErrInvalidTimerange), http.StatusBadRequest)
		return
	}

	// Set default plot sample if none provided
	if req.Sample == 0 {
		req.Sample = plot.DefaultSample
	}

	// Execute plots request
	plots := plot.Response{
		Start:   req.StartTime.Format(time.RFC3339),
		End:     req.EndTime.Format(time.RFC3339),
		Series:  w.executeRequest(req),
		Options: req.Graph.Options,
	}

	// Set fallback title to graph name if none provided
	if plots.Options == nil {
		plots.Options = make(map[string]interface{})
	}

	if _, ok := plots.Options["title"]; !ok {
		plots.Options["title"] = req.Graph.Name
	}

	httputil.WriteJSON(rw, plots, http.StatusOK)
}

func (w *httpWorker) executeRequest(req *plot.Request) []plot.SeriesResponse {
	// Expand groups series
	for _, group := range req.Graph.Groups {
		expandedSeries := []*backend.Series{}
		for _, series := range group.Series {
			expandedSeries = append(expandedSeries, w.expandSeries(series, true)...)
		}
		group.Series = expandedSeries
	}

	// Dispatch plot queries among providers
	data := make([][]plot.Series, len(req.Graph.Groups))
	for i, group := range req.Graph.Groups {
		data[i] = make([]plot.Series, len(group.Series))
	}

	for _, q := range w.dispatchQueries(req) {
		series, err := q.connector.Plots(&q.query)
		if err != nil {
			w.log.Error("unable to fetch plots: %s", err)
			continue
		}

		count := len(series)
		expected := len(q.query.Series)
		if count != expected {
			w.log.Error("unable to fetch plots: expected %d series but got %d", expected, count)
			continue
		}

		// Put back series to its original indexes
		for i, s := range series {
			data[q.queryMap[i][0]][q.queryMap[i][1]] = s
		}
	}

	// Generate plots series
	result := []plot.SeriesResponse{}
	for i, group := range req.Graph.Groups {
		var (
			consolidate int
			interpolate bool
			err         error
		)

		// Skip processing if no data
		if len(data[i]) == 0 {
			goto finalize
		}

		// Apply series scale if any
		for j, series := range group.Series {
			if v, ok := series.Options["scale"].(float64); ok {
				data[i][j].Scale(plot.Value(v))
			}
		}

		// Skip normalization if operator and stack mode are not set
		if group.Operator == plot.OperatorNone {
			if group.Options == nil {
				goto finalize
			}

			if v, ok := group.Options["stack_mode"].(string); ok && v == "" {
				goto finalize
			}
		}

		// Get group consolidation mode and interpolation options
		consolidate = plot.ConsolidateAverage
		if v, ok := group.Options["consolidate"].(int); ok {
			consolidate = v
		}

		interpolate = true
		if v, ok := group.Options["interpolate"].(bool); ok {
			interpolate = v
		}

		// Normalize series and apply operations
		data[i], err = plot.Normalize(data[i], req.StartTime, req.EndTime, req.Sample, consolidate, interpolate)
		if err != nil {
			w.log.Error("failed to normalize series: %s", err)
			continue
		}

		switch group.Operator {
		case plot.OperatorAverage, plot.OperatorSum:
			var (
				series plot.Series
				err    error
			)

			if group.Operator == plot.OperatorAverage {
				series, err = plot.Average(data[i])
			} else {
				series, err = plot.Sum(data[i])
			}

			if err != nil {
				w.log.Error("failed to apply series operation: %s", err)
				continue
			}

			// Set series name to group name
			group.Series[0].Name = group.Name

			// Replace group series with operation result
			data[i] = []plot.Series{series}

		case plot.OperatorNone:
			// noop

		default:
			w.log.Warning("unknown %d operation type", group.Operator)
			continue
		}

	finalize:
		// Get group scale value
		scale, _ := group.Options["scale"].(float64)

		for j, series := range data[i] {
			// Apply group scale if any
			if scale != 0 {
				series.Scale(plot.Value(scale))
			}

			// Summarize series
			percentiles := []float64{}
			if slice, ok := req.Graph.Options["percentiles"].([]interface{}); ok {
				for _, entry := range slice {
					if val, ok := entry.(float64); ok {
						percentiles = append(percentiles, val)
					}
				}
			}

			series.Summarize(percentiles)

			result = append(result, plot.SeriesResponse{
				Series:  series,
				Name:    group.Series[j].Name,
				Options: group.Series[j].Options,
			})
		}
	}

	return result
}

func (w *httpWorker) dispatchQueries(req *plot.Request) []plotQuery {
	providers := make(map[string]*plotQuery)

	for i, group := range req.Graph.Groups {
		for j, series := range group.Series {
			if !series.IsValid() {
				w.log.Warning("invalid series metric: %s", series)
				continue
			}

			search := w.service.searcher.Metrics(series.Origin, series.Source, series.Metric, 1)
			if len(search) == 0 {
				w.log.Warning("unable to find series metric: %s", series)
				continue
			}

			// Get series connector and provider name
			c := search[0].Connector().(connector.Connector)
			provName := c.Name()

			// Initialize provider-specific plot query
			if _, ok := providers[provName]; !ok {
				providers[provName] = &plotQuery{
					query: plot.Query{
						StartTime: req.StartTime,
						EndTime:   req.EndTime,
						Sample:    req.Sample,
						Series:    []plot.QuerySeries{},
					},
					queryMap:  [][2]int{},
					connector: c,
				}
			}

			// Append new series to plot query and save series index
			providers[provName].query.Series = append(providers[provName].query.Series, plot.QuerySeries{
				Origin: search[0].Source().Origin().OriginalName,
				Source: search[0].Source().OriginalName,
				Metric: search[0].OriginalName,
			})

			providers[provName].queryMap = append(providers[provName].queryMap, [2]int{i, j})
		}
	}

	result := []plotQuery{}
	for _, q := range providers {
		result = append(result, *q)
	}

	return result
}
<|endoftext|>


<commit_before>package ITC

import (
	"testing"

	"github.com/ca-geo/go-misc/testutils"
)

func TestStringToTreeAtom(t *testing.T) {
	var id *Id = stringToId("0")
	testutils.CheckString("0", id.String(), t)
	id = stringToId("1")
	testutils.CheckString("1", id.String(), t)
}

func TestStringToTreeOneLevel(t *testing.T) {
	var id *Id = stringToId("(0, 1)")
	testutils.CheckString("(0, 1)", id.String(), t)
}

func TestStringToTreeHalves(t *testing.T) {
	var id *Id = stringToId("((1, 0), 0)")
	testutils.CheckString("((1, 0), 0)", id.String(), t)
	id = stringToId("(0, (1, 0))")
	testutils.CheckString("(0, (1, 0))", id.String(), t)
}

func TestStringToTreeTwoLevels(t *testing.T) {
	var id *Id = stringToId("((1, 0), (0, 1))")
	testutils.CheckString("((1, 0), (0, 1))", id.String(), t)
}
<commit_msg>fixing imports<commit_after>package ITC

import (
	"testing"

	"github.com/asp2insp/go-misc/testutils"
)

func TestStringToTreeAtom(t *testing.T) {
	var id *Id = stringToId("0")
	testutils.CheckString("0", id.String(), t)
	id = stringToId("1")
	testutils.CheckString("1", id.String(), t)
}

func TestStringToTreeOneLevel(t *testing.T) {
	var id *Id = stringToId("(0, 1)")
	testutils.CheckString("(0, 1)", id.String(), t)
}

func TestStringToTreeHalves(t *testing.T) {
	var id *Id = stringToId("((1, 0), 0)")
	testutils.CheckString("((1, 0), 0)", id.String(), t)
	id = stringToId("(0, (1, 0))")
	testutils.CheckString("(0, (1, 0))", id.String(), t)
}

func TestStringToTreeTwoLevels(t *testing.T) {
	var id *Id = stringToId("((1, 0), (0, 1))")
	testutils.CheckString("((1, 0), (0, 1))", id.String(), t)
}
<|endoftext|>


<commit_before>package common

import (
	"facette/utils"
	"fmt"
	"os"
	"path"
	"regexp"
)

// Config represents the main configuration system structure.
type Config struct {
	Path      string                   `json:"-"`
	BindAddr  string                   `json:"bind"`
	BaseDir   string                   `json:"base_dir"`
	DataDir   string                   `json:"data_dir"`
	OriginDir string                   `json:"origin_dir"`
	AuthFile  string                   `json:"auth_file"`
	ServerLog string                   `json:"server_log"`
	AccessLog string                   `json:"access_log"`
	Origins   map[string]*OriginConfig `json:"-"`
}

// Load loads the configuration from the filesystem using the filePath paramater as origin path.
func (config *Config) Load(filePath string) error {
	var (
		err       error
		errOutput error
		walkFunc  func(filePath string, fileInfo os.FileInfo, err error) error
	)

	if _, err = utils.JSONLoad(filePath, &config); err != nil {
		return err
	}

	// Load origin definitions
	config.Origins = make(map[string]*OriginConfig)

	walkFunc = func(filePath string, fileInfo os.FileInfo, err error) error {
		var (
			originName string
		)

		if fileInfo.IsDir() {
			return nil
		}

		_, originName = path.Split(filePath[:len(filePath)-5])

		config.Origins[originName] = &OriginConfig{}

		if fileInfo, err = utils.JSONLoad(filePath, config.Origins[originName]); err != nil {
			err = fmt.Errorf("in %s, %s", filePath, err.Error())

			if errOutput == nil {
				errOutput = err
			}

			return err
		}

		config.Origins[originName].Modified = fileInfo.ModTime()

		return nil
	}

	utils.WalkDir(config.OriginDir, walkFunc)

	if errOutput != nil {
		return errOutput
	}

	// Pre-compile Regexp items
	for _, origin := range config.Origins {
		for _, filter := range origin.Filters {
			filter.PatternRegexp = regexp.MustCompile(filter.Pattern)
		}

		for _, template := range origin.Templates {
			template.SplitRegexp = regexp.MustCompile(template.SplitPattern)
		}
	}

	config.Path = filePath

	return nil
}

// Reload reloads the configuration from the filesystem.
func (config *Config) Reload() error {
	return config.Load(config.Path)
}
<commit_msg>Fix origins load.<commit_after>package common

import (
	"facette/utils"
	"fmt"
	"os"
	"path"
	"regexp"
	"strings"
)

// Config represents the main configuration system structure.
type Config struct {
	Path      string                   `json:"-"`
	BindAddr  string                   `json:"bind"`
	BaseDir   string                   `json:"base_dir"`
	DataDir   string                   `json:"data_dir"`
	OriginDir string                   `json:"origin_dir"`
	AuthFile  string                   `json:"auth_file"`
	ServerLog string                   `json:"server_log"`
	AccessLog string                   `json:"access_log"`
	Origins   map[string]*OriginConfig `json:"-"`
}

// Load loads the configuration from the filesystem using the filePath paramater as origin path.
func (config *Config) Load(filePath string) error {
	var (
		err       error
		errOutput error
		walkFunc  func(filePath string, fileInfo os.FileInfo, err error) error
	)

	if _, err = utils.JSONLoad(filePath, &config); err != nil {
		return err
	}

	// Load origin definitions
	config.Origins = make(map[string]*OriginConfig)

	walkFunc = func(filePath string, fileInfo os.FileInfo, err error) error {
		var (
			originName string
		)

		if fileInfo.IsDir() || !strings.HasSuffix(filePath, ".json") {
			return nil
		}

		_, originName = path.Split(filePath[:len(filePath)-5])

		config.Origins[originName] = &OriginConfig{}

		if fileInfo, err = utils.JSONLoad(filePath, config.Origins[originName]); err != nil {
			err = fmt.Errorf("in %s, %s", filePath, err.Error())

			if errOutput == nil {
				errOutput = err
			}

			return err
		}

		config.Origins[originName].Modified = fileInfo.ModTime()

		return nil
	}

	utils.WalkDir(config.OriginDir, walkFunc)

	if errOutput != nil {
		return errOutput
	}

	// Pre-compile Regexp items
	for _, origin := range config.Origins {
		for _, filter := range origin.Filters {
			filter.PatternRegexp = regexp.MustCompile(filter.Pattern)
		}

		for _, template := range origin.Templates {
			template.SplitRegexp = regexp.MustCompile(template.SplitPattern)
		}
	}

	config.Path = filePath

	return nil
}

// Reload reloads the configuration from the filesystem.
func (config *Config) Reload() error {
	return config.Load(config.Path)
}
<|endoftext|>


<commit_before>package gdrive2slack

import (
	"fmt"
	"github.com/optionfactory/gdrive2slack/google/drive"
	"github.com/optionfactory/gdrive2slack/slack"
)

var actionColors = []string{
	drive.Deleted:  "#ffcccc",
	drive.Created:  "#ccffcc",
	drive.Modified: "#ccccff",
	drive.Shared:   "#ccccff",
	drive.Viewed:   "#ccccff",
}

func CreateSlackAttachment(change *drive.ChangeItem) *slack.Attachment {
	var editor string
	if len(change.File.LastModifyingUser.EmailAddress) > 0 && len(change.File.LastModifyingUser.DisplayName) > 0 {
		editor = fmt.Sprintf("<mailto:%s|%s>", change.File.LastModifyingUser.EmailAddress, change.File.LastModifyingUser.DisplayName)
	} else if len(change.File.LastModifyingUser.DisplayName) > 0 {
		editor = change.File.LastModifyingUser.DisplayName
	} else {
		editor = "Unknown"
	}
	return &slack.Attachment{
		Fallback: fmt.Sprintf("Changes Detected to file: <%s|%s>", change.File.AlternateLink, change.File.Title),
		Color:    actionColors[change.LastAction],
		Fields: []slack.Field{
			{
				Title: fmt.Sprintf("%s file:", change.LastAction.String()),
				Value: fmt.Sprintf("<%s|%s>", change.File.AlternateLink, change.File.Title),
				Short: true,
			},
			{
				Title: "Editor",
				Value: editor,
				Short: true,
			},
		},
	}
}

func CreateSlackMessage(userState *UserState) *slack.Message {

	var attachments = make([]slack.Attachment, 0, len(userState.Gdrive.ChangeSet))

	for i := 0; i != len(userState.Gdrive.ChangeSet); i++ {
		attachments = append(attachments, *CreateSlackAttachment(&userState.Gdrive.ChangeSet[i]))
	}

	return &slack.Message{
		Channel:     userState.Channel,
		Username:    "Google Drive",
		Text:        fmt.Sprintf("Activity on google drive: (hook for <mailto:%s|%s> → <@%s|%s>)", userState.GoogleUserInfo.Emails[0].Value, userState.GoogleUserInfo.DisplayName, userState.SlackUserInfo.UserId, userState.SlackUserInfo.User),
		IconUrl:     "http://gdrive2slack.optionfactory.net/gdrive2slack.png",
		Attachments: attachments,
	}
}
<commit_msg>ref: notifications (formatting)<commit_after>package gdrive2slack

import (
	"fmt"
	"github.com/optionfactory/gdrive2slack/google/drive"
	"github.com/optionfactory/gdrive2slack/slack"
)

var actionColors = []string{
	drive.Deleted:  "#ffcccc",
	drive.Created:  "#ccffcc",
	drive.Modified: "#ccccff",
	drive.Shared:   "#ccccff",
	drive.Viewed:   "#ccccff",
}

func CreateSlackAttachment(change *drive.ChangeItem) *slack.Attachment {
	var editor string
	if len(change.File.LastModifyingUser.EmailAddress) > 0 && len(change.File.LastModifyingUser.DisplayName) > 0 {
		editor = fmt.Sprintf("<mailto:%s|%s>", change.File.LastModifyingUser.EmailAddress, change.File.LastModifyingUser.DisplayName)
	} else if len(change.File.LastModifyingUser.DisplayName) > 0 {
		editor = change.File.LastModifyingUser.DisplayName
	} else {
		editor = "Unknown"
	}
	return &slack.Attachment{
		Fallback: fmt.Sprintf("Changes Detected to file <%s|%s>", change.File.AlternateLink, change.File.Title),
		Color:    actionColors[change.LastAction],
		Fields: []slack.Field{
			{
				Title: fmt.Sprintf("%s file", change.LastAction.String()),
				Value: fmt.Sprintf("<%s|%s>", change.File.AlternateLink, change.File.Title),
				Short: true,
			},
			{
				Title: "Editor",
				Value: editor,
				Short: true,
			},
		},
	}
}

func CreateSlackMessage(userState *UserState) *slack.Message {

	var attachments = make([]slack.Attachment, 0, len(userState.Gdrive.ChangeSet))

	for i := 0; i != len(userState.Gdrive.ChangeSet); i++ {
		attachments = append(attachments, *CreateSlackAttachment(&userState.Gdrive.ChangeSet[i]))
	}

	return &slack.Message{
		Channel:     userState.Channel,
		Username:    "Google Drive",
		Text:        fmt.Sprintf("Activity on google drive (hook for <mailto:%s|%s> → <@%s|%s>):", userState.GoogleUserInfo.Emails[0].Value, userState.GoogleUserInfo.DisplayName, userState.SlackUserInfo.UserId, userState.SlackUserInfo.User),
		IconUrl:     "http://gdrive2slack.optionfactory.net/gdrive2slack.png",
		Attachments: attachments,
	}
}
<|endoftext|>


<commit_before>// Copyright 2019 The Ebiten 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 convert

import (
	"io"
)

type Float32Reader interface {
	Read([]float32) (int, error)
}

func NewReaderFromFloat32Reader(r Float32Reader) io.Reader {
	return &f32Reader{r: r}
}

type f32Reader struct {
	r    Float32Reader
	eof  bool
	buf  *byte
	fbuf []float32
}

func max(a, b int) int {
	if a < b {
		return b
	}
	return a
}

func (f *f32Reader) Read(buf []byte) (int, error) {
	if f.eof {
		return 0, io.EOF
	}
	if len(buf) == 0 {
		return 0, nil
	}
	if f.buf != nil {
		buf[0] = *f.buf
		f.buf = nil
		return 1, nil
	}

	l := max(len(buf)/2, 1)
	ll := len(f.fbuf)
	if ll < 16 {
		ll = 16
	}
	for ll < l {
		ll *= 2
	}
	f.fbuf = make([]float32, ll)

	n, err := f.r.Read(f.fbuf[:l])
	if err != nil && err != io.EOF {
		return 0, err
	}
	if err == io.EOF {
		f.eof = true
	}

	b := buf
	if len(buf) == 1 && n > 0 {
		b = make([]byte, 2)
	}
	for i := 0; i < n; i++ {
		f := f.fbuf[i]
		s := int16(f * (1<<15 - 1))
		b[2*i] = uint8(s)
		b[2*i+1] = uint8(s >> 8)
	}

	if len(buf) == 1 && len(b) == 2 {
		buf[0] = b[0]
		f.buf = &b[1]
		return 1, err
	}
	return n * 2, err
}
<commit_msg>audio/internal/convert: Avoid unnecessary allocations<commit_after>// Copyright 2019 The Ebiten 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 convert

import (
	"io"
)

type Float32Reader interface {
	Read([]float32) (int, error)
}

func NewReaderFromFloat32Reader(r Float32Reader) io.Reader {
	return &f32Reader{r: r}
}

type f32Reader struct {
	r    Float32Reader
	eof  bool
	buf  *byte
	fbuf []float32
}

func max(a, b int) int {
	if a < b {
		return b
	}
	return a
}

func (f *f32Reader) Read(buf []byte) (int, error) {
	if f.eof {
		return 0, io.EOF
	}
	if len(buf) == 0 {
		return 0, nil
	}
	if f.buf != nil {
		buf[0] = *f.buf
		f.buf = nil
		return 1, nil
	}

	l := max(len(buf)/2, 1)
	ll := len(f.fbuf)
	if ll < 16 {
		ll = 16
	}
	for ll < l {
		ll *= 2
	}
	if len(f.fbuf) < ll {
		f.fbuf = make([]float32, ll)
	}

	n, err := f.r.Read(f.fbuf[:l])
	if err != nil && err != io.EOF {
		return 0, err
	}
	if err == io.EOF {
		f.eof = true
	}

	b := buf
	if len(buf) == 1 && n > 0 {
		b = make([]byte, 2)
	}
	for i := 0; i < n; i++ {
		f := f.fbuf[i]
		s := int16(f * (1<<15 - 1))
		b[2*i] = uint8(s)
		b[2*i+1] = uint8(s >> 8)
	}

	if len(buf) == 1 && len(b) == 2 {
		buf[0] = b[0]
		f.buf = &b[1]
		return 1, err
	}
	return n * 2, err
}
<|endoftext|>


<commit_before>package slackboard

const (
	Version = "0.8.0"
)
<commit_msg>bumped version to 0.8.1.<commit_after>package slackboard

const (
	Version = "0.8.1"
)
<|endoftext|>


<commit_before>package client

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"
	"strconv"
	"strings"

	"github.com/deis/deis/version"
)

// CreateHTTPClient creates a HTTP Client with proper SSL options.
func CreateHTTPClient(sslVerify bool) *http.Client {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: !sslVerify},
	}
	return &http.Client{Transport: tr}
}

// Request makes a HTTP request on the controller.
func (c Client) Request(method string, path string, body []byte) (*http.Response, error) {
	url := c.ControllerURL

	if strings.Contains(path, "?") {
		parts := strings.Split(path, "?")
		url.Path = parts[0]
		url.RawQuery = parts[1]
	} else {
		url.Path = path
	}

	req, err := http.NewRequest(method, url.String(), bytes.NewBuffer(body))

	if err != nil {
		return nil, err
	}

	req.Header.Add("Content-Type", "application/json")

	if c.Token != "" {
		req.Header.Add("Authorization", "token "+c.Token)
	}

	addUserAgent(&req.Header)

	res, err := c.HTTPClient.Do(req)

	if err != nil {
		return nil, err
	}

	checkAPICompatability(res.Header.Get("DEIS_API_VERSION"))

	return res, nil
}

// LimitedRequest allows limiting the number of responses in a request.
func (c Client) LimitedRequest(path string, results int) (string, int, error) {
	body, err := c.BasicRequest("GET", path+"?page_size="+strconv.Itoa(results), nil)

	if err != nil {
		return "", -1, err
	}

	res := make(map[string]interface{})
	if err = json.Unmarshal([]byte(body), &res); err != nil {
		return "", -1, err
	}

	out, err := json.Marshal(res["results"].([]interface{}))

	if err != nil {
		return "", -1, err
	}

	return string(out), int(res["count"].(float64)), nil
}

// BasicRequest makes a simple http request on the controller.
func (c Client) BasicRequest(method string, path string, body []byte) (string, error) {
	res, err := c.Request(method, path, body)

	if err != nil {
		return "", err
	}
	defer res.Body.Close()

	resBody, err := ioutil.ReadAll(res.Body)

	if err != nil {
		return "", err
	}
	return string(resBody), checkForErrors(res, string(resBody))
}

func checkForErrors(res *http.Response, body string) error {

	// If response is not an error, return nil.
	if res.StatusCode > 199 && res.StatusCode < 400 {
		return nil
	}

	bodyMap := make(map[string]interface{})

	if err := json.Unmarshal([]byte(body), &bodyMap); err != nil {
		return err
	}

	errorMessage := "\n"
	for key, value := range bodyMap {
		switch v := value.(type) {
		case string:
			errorMessage += key + ": " + v + "\n"
		case []interface{}:
			for _, subValue := range v {
				switch sv := subValue.(type) {
				case string:
					errorMessage += key + ": " + sv + "\n"
				default:
					fmt.Printf("Unexpected type in %s error message array. Contents: %v",
						reflect.TypeOf(value), sv)
				}
			}
		default:
			fmt.Printf("Cannot handle key %s in error message, type %s. Contents: %v",
				key, reflect.TypeOf(value), bodyMap[key])
		}
	}

	errorMessage += res.Status + "\n"
	return errors.New(errorMessage)
}

// CheckConection checks that the user is connected to a network and the URL points to a valid controller.
func CheckConection(client *http.Client, controllerURL url.URL) error {
	errorMessage := `%s does not appear to be a valid Deis controller.
Make sure that the Controller URI is correct and the server is running.`

	baseURL := controllerURL.String()

	controllerURL.Path = "/v1/"

	req, err := http.NewRequest("GET", controllerURL.String(), bytes.NewBuffer(nil))
	addUserAgent(&req.Header)

	if err != nil {
		return err
	}

	res, err := client.Do(req)

	if err != nil {
		fmt.Printf(errorMessage+"\n", baseURL)
		return err
	}
	defer res.Body.Close()

	if res.StatusCode != 401 {
		return fmt.Errorf(errorMessage, baseURL)
	}

	checkAPICompatability(res.Header.Get("DEIS_API_VERSION"))

	return nil
}

func addUserAgent(headers *http.Header) {
	headers.Add("User-Agent", "Deis Client v"+version.Version)
}
<commit_msg>fix(client-go): disable HTTP keepalives<commit_after>package client

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"
	"strconv"
	"strings"

	"github.com/deis/deis/version"
)

// CreateHTTPClient creates a HTTP Client with proper SSL options.
func CreateHTTPClient(sslVerify bool) *http.Client {
	tr := &http.Transport{
		TLSClientConfig:   &tls.Config{InsecureSkipVerify: !sslVerify},
		DisableKeepAlives: true,
	}
	return &http.Client{Transport: tr}
}

// Request makes a HTTP request on the controller.
func (c Client) Request(method string, path string, body []byte) (*http.Response, error) {
	url := c.ControllerURL

	if strings.Contains(path, "?") {
		parts := strings.Split(path, "?")
		url.Path = parts[0]
		url.RawQuery = parts[1]
	} else {
		url.Path = path
	}

	req, err := http.NewRequest(method, url.String(), bytes.NewBuffer(body))

	if err != nil {
		return nil, err
	}

	req.Header.Add("Content-Type", "application/json")

	if c.Token != "" {
		req.Header.Add("Authorization", "token "+c.Token)
	}

	addUserAgent(&req.Header)

	res, err := c.HTTPClient.Do(req)

	if err != nil {
		return nil, err
	}

	checkAPICompatability(res.Header.Get("DEIS_API_VERSION"))

	return res, nil
}

// LimitedRequest allows limiting the number of responses in a request.
func (c Client) LimitedRequest(path string, results int) (string, int, error) {
	body, err := c.BasicRequest("GET", path+"?page_size="+strconv.Itoa(results), nil)

	if err != nil {
		return "", -1, err
	}

	res := make(map[string]interface{})
	if err = json.Unmarshal([]byte(body), &res); err != nil {
		return "", -1, err
	}

	out, err := json.Marshal(res["results"].([]interface{}))

	if err != nil {
		return "", -1, err
	}

	return string(out), int(res["count"].(float64)), nil
}

// BasicRequest makes a simple http request on the controller.
func (c Client) BasicRequest(method string, path string, body []byte) (string, error) {
	res, err := c.Request(method, path, body)

	if err != nil {
		return "", err
	}
	defer res.Body.Close()

	resBody, err := ioutil.ReadAll(res.Body)

	if err != nil {
		return "", err
	}
	return string(resBody), checkForErrors(res, string(resBody))
}

func checkForErrors(res *http.Response, body string) error {

	// If response is not an error, return nil.
	if res.StatusCode > 199 && res.StatusCode < 400 {
		return nil
	}

	bodyMap := make(map[string]interface{})

	if err := json.Unmarshal([]byte(body), &bodyMap); err != nil {
		return err
	}

	errorMessage := "\n"
	for key, value := range bodyMap {
		switch v := value.(type) {
		case string:
			errorMessage += key + ": " + v + "\n"
		case []interface{}:
			for _, subValue := range v {
				switch sv := subValue.(type) {
				case string:
					errorMessage += key + ": " + sv + "\n"
				default:
					fmt.Printf("Unexpected type in %s error message array. Contents: %v",
						reflect.TypeOf(value), sv)
				}
			}
		default:
			fmt.Printf("Cannot handle key %s in error message, type %s. Contents: %v",
				key, reflect.TypeOf(value), bodyMap[key])
		}
	}

	errorMessage += res.Status + "\n"
	return errors.New(errorMessage)
}

// CheckConection checks that the user is connected to a network and the URL points to a valid controller.
func CheckConection(client *http.Client, controllerURL url.URL) error {
	errorMessage := `%s does not appear to be a valid Deis controller.
Make sure that the Controller URI is correct and the server is running.`

	baseURL := controllerURL.String()

	controllerURL.Path = "/v1/"

	req, err := http.NewRequest("GET", controllerURL.String(), bytes.NewBuffer(nil))
	addUserAgent(&req.Header)

	if err != nil {
		return err
	}

	res, err := client.Do(req)

	if err != nil {
		fmt.Printf(errorMessage+"\n", baseURL)
		return err
	}
	defer res.Body.Close()

	if res.StatusCode != 401 {
		return fmt.Errorf(errorMessage, baseURL)
	}

	checkAPICompatability(res.Header.Get("DEIS_API_VERSION"))

	return nil
}

func addUserAgent(headers *http.Header) {
	headers.Add("User-Agent", "Deis Client v"+version.Version)
}
<|endoftext|>


<commit_before>package vm

import (
	"bytes"
	"math/big"
	"strconv"
	"testing"

	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/ethdb"
	"github.com/ethereum/go-ethereum/ethutil"
	"github.com/ethereum/go-ethereum/logger"
	"github.com/ethereum/go-ethereum/state"
	"github.com/ethereum/go-ethereum/tests/helper"
)

type Account struct {
	Balance string
	Code    string
	Nonce   string
	Storage map[string]string
}

type Log struct {
	AddressF string   `json:"address"`
	DataF    string   `json:"data"`
	TopicsF  []string `json:"topics"`
	BloomF   string   `json:"bloom"`
}

func (self Log) Address() []byte      { return ethutil.Hex2Bytes(self.AddressF) }
func (self Log) Data() []byte         { return ethutil.Hex2Bytes(self.DataF) }
func (self Log) RlpData() interface{} { return nil }
func (self Log) Topics() [][]byte {
	t := make([][]byte, len(self.TopicsF))
	for i, topic := range self.TopicsF {
		t[i] = ethutil.Hex2Bytes(topic)
	}
	return t
}

func StateObjectFromAccount(db ethutil.Database, addr string, account Account) *state.StateObject {
	obj := state.NewStateObject(ethutil.Hex2Bytes(addr), db)
	obj.SetBalance(ethutil.Big(account.Balance))

	if ethutil.IsHex(account.Code) {
		account.Code = account.Code[2:]
	}
	obj.Code = ethutil.Hex2Bytes(account.Code)
	obj.Nonce = ethutil.Big(account.Nonce).Uint64()

	return obj
}

type Env struct {
	CurrentCoinbase   string
	CurrentDifficulty string
	CurrentGasLimit   string
	CurrentNumber     string
	CurrentTimestamp  interface{}
	PreviousHash      string
}

type VmTest struct {
	Callcreates interface{}
	//Env         map[string]string
	Env         Env
	Exec        map[string]string
	Transaction map[string]string
	Logs        []Log
	Gas         string
	Out         string
	Post        map[string]Account
	Pre         map[string]Account
}

func RunVmTest(p string, t *testing.T) {
	tests := make(map[string]VmTest)
	helper.CreateFileTests(t, p, &tests)

	for name, test := range tests {
		helper.Logger.SetLogLevel(4)
		if name != "TransactionNonceCheck2" {
			continue
		}
		db, _ := ethdb.NewMemDatabase()
		statedb := state.New(nil, db)
		for addr, account := range test.Pre {
			obj := StateObjectFromAccount(db, addr, account)
			statedb.SetStateObject(obj)
			for a, v := range account.Storage {
				obj.SetState(helper.FromHex(a), ethutil.NewValue(helper.FromHex(v)))
			}
		}

		// XXX Yeah, yeah...
		env := make(map[string]string)
		env["currentCoinbase"] = test.Env.CurrentCoinbase
		env["currentDifficulty"] = test.Env.CurrentDifficulty
		env["currentGasLimit"] = test.Env.CurrentGasLimit
		env["currentNumber"] = test.Env.CurrentNumber
		env["previousHash"] = test.Env.PreviousHash
		if n, ok := test.Env.CurrentTimestamp.(float64); ok {
			env["currentTimestamp"] = strconv.Itoa(int(n))
		} else {
			env["currentTimestamp"] = test.Env.CurrentTimestamp.(string)
		}

		var (
			ret  []byte
			gas  *big.Int
			err  error
			logs state.Logs
		)

		isVmTest := len(test.Exec) > 0
		if isVmTest {
			ret, logs, gas, err = helper.RunVm(statedb, env, test.Exec)
		} else {
			ret, logs, gas, err = helper.RunState(statedb, env, test.Transaction)
		}

		rexp := helper.FromHex(test.Out)
		if bytes.Compare(rexp, ret) != 0 {
			t.Errorf("%s's return failed. Expected %x, got %x\n", name, rexp, ret)
		}

		if isVmTest {
			if len(test.Gas) == 0 && err == nil {
				t.Errorf("%s's gas unspecified, indicating an error. VM returned (incorrectly) successfull", name)
			} else {
				gexp := ethutil.Big(test.Gas)
				if gexp.Cmp(gas) != 0 {
					t.Errorf("%s's gas failed. Expected %v, got %v\n", name, gexp, gas)
				}
			}
		}

		for addr, account := range test.Post {
			obj := statedb.GetStateObject(helper.FromHex(addr))
			if obj == nil {
				continue
			}

			if len(test.Exec) == 0 {
				if obj.Balance().Cmp(ethutil.Big(account.Balance)) != 0 {
					t.Errorf("%s's : (%x) balance failed. Expected %v, got %v => %v\n", name, obj.Address()[:4], account.Balance, obj.Balance(), new(big.Int).Sub(ethutil.Big(account.Balance), obj.Balance()))
				}
			}

			for addr, value := range account.Storage {
				v := obj.GetState(helper.FromHex(addr)).Bytes()
				vexp := helper.FromHex(value)

				if bytes.Compare(v, vexp) != 0 {
					t.Errorf("%s's : (%x: %s) storage failed. Expected %x, got %x (%v %v)\n", name, obj.Address()[0:4], addr, vexp, v, ethutil.BigD(vexp), ethutil.BigD(v))
				}
			}
		}

		if len(test.Logs) > 0 {
			for i, log := range test.Logs {
				genBloom := ethutil.LeftPadBytes(types.LogsBloom(state.Logs{logs[i]}).Bytes(), 64)
				if !bytes.Equal(genBloom, ethutil.Hex2Bytes(log.BloomF)) {
					t.Errorf("bloom mismatch")
				}
			}
		}
	}
	logger.Flush()
}

// I've created a new function for each tests so it's easier to identify where the problem lies if any of them fail.
func TestVMArithmetic(t *testing.T) {
	const fn = "../files/VMTests/vmArithmeticTest.json"
	RunVmTest(fn, t)
}

func TestSystemOperations(t *testing.T) {
	const fn = "../files/VMTests/vmSystemOperationsTest.json"
	RunVmTest(fn, t)
}

func TestBitwiseLogicOperation(t *testing.T) {
	const fn = "../files/VMTests/vmBitwiseLogicOperationTest.json"
	RunVmTest(fn, t)
}

func TestBlockInfo(t *testing.T) {
	const fn = "../files/VMTests/vmBlockInfoTest.json"
	RunVmTest(fn, t)
}

func TestEnvironmentalInfo(t *testing.T) {
	const fn = "../files/VMTests/vmEnvironmentalInfoTest.json"
	RunVmTest(fn, t)
}

func TestFlowOperation(t *testing.T) {
	const fn = "../files/VMTests/vmIOandFlowOperationsTest.json"
	RunVmTest(fn, t)
}

func TestPushDupSwap(t *testing.T) {
	const fn = "../files/VMTests/vmPushDupSwapTest.json"
	RunVmTest(fn, t)
}

func TestVMSha3(t *testing.T) {
	const fn = "../files/VMTests/vmSha3Test.json"
	RunVmTest(fn, t)
}

func TestVm(t *testing.T) {
	const fn = "../files/VMTests/vmtests.json"
	RunVmTest(fn, t)
}

func TestVmLog(t *testing.T) {
	const fn = "../files/VMTests/vmLogTest.json"
	RunVmTest(fn, t)
}

func TestStateSystemOperations(t *testing.T) {
	const fn = "../files/StateTests/stSystemOperationsTest.json"
	RunVmTest(fn, t)
}

func TestStatePreCompiledContracts(t *testing.T) {
	const fn = "../files/StateTests/stPreCompiledContracts.json"
	RunVmTest(fn, t)
}

func TestStateRecursiveCreate(t *testing.T) {
	const fn = "../files/StateTests/stRecursiveCreate.json"
	RunVmTest(fn, t)
}

func TestStateSpecial(t *testing.T) {
	const fn = "../files/StateTests/stSpecialTest.json"
	RunVmTest(fn, t)
}

func TestStateRefund(t *testing.T) {
	const fn = "../files/StateTests/stRefundTest.json"
	RunVmTest(fn, t)
}

func TestStateBlockHash(t *testing.T) {
	const fn = "../files/StateTests/stBlockHashTest.json"
	RunVmTest(fn, t)
}

func TestStateInitCode(t *testing.T) {
	const fn = "../files/StateTests/stInitCodeTest.json"
	RunVmTest(fn, t)
}

func TestStateLog(t *testing.T) {
	const fn = "../files/StateTests/stLogTests.json"
	RunVmTest(fn, t)
}

func TestStateTransaction(t *testing.T) {
	const fn = "../files/StateTests/stTransactionTest.json"
	RunVmTest(fn, t)
}
<commit_msg>disabled test<commit_after>package vm

import (
	"bytes"
	"math/big"
	"strconv"
	"testing"

	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/ethdb"
	"github.com/ethereum/go-ethereum/ethutil"
	"github.com/ethereum/go-ethereum/logger"
	"github.com/ethereum/go-ethereum/state"
	"github.com/ethereum/go-ethereum/tests/helper"
)

type Account struct {
	Balance string
	Code    string
	Nonce   string
	Storage map[string]string
}

type Log struct {
	AddressF string   `json:"address"`
	DataF    string   `json:"data"`
	TopicsF  []string `json:"topics"`
	BloomF   string   `json:"bloom"`
}

func (self Log) Address() []byte      { return ethutil.Hex2Bytes(self.AddressF) }
func (self Log) Data() []byte         { return ethutil.Hex2Bytes(self.DataF) }
func (self Log) RlpData() interface{} { return nil }
func (self Log) Topics() [][]byte {
	t := make([][]byte, len(self.TopicsF))
	for i, topic := range self.TopicsF {
		t[i] = ethutil.Hex2Bytes(topic)
	}
	return t
}

func StateObjectFromAccount(db ethutil.Database, addr string, account Account) *state.StateObject {
	obj := state.NewStateObject(ethutil.Hex2Bytes(addr), db)
	obj.SetBalance(ethutil.Big(account.Balance))

	if ethutil.IsHex(account.Code) {
		account.Code = account.Code[2:]
	}
	obj.Code = ethutil.Hex2Bytes(account.Code)
	obj.Nonce = ethutil.Big(account.Nonce).Uint64()

	return obj
}

type Env struct {
	CurrentCoinbase   string
	CurrentDifficulty string
	CurrentGasLimit   string
	CurrentNumber     string
	CurrentTimestamp  interface{}
	PreviousHash      string
}

type VmTest struct {
	Callcreates interface{}
	//Env         map[string]string
	Env         Env
	Exec        map[string]string
	Transaction map[string]string
	Logs        []Log
	Gas         string
	Out         string
	Post        map[string]Account
	Pre         map[string]Account
}

func RunVmTest(p string, t *testing.T) {
	tests := make(map[string]VmTest)
	helper.CreateFileTests(t, p, &tests)

	for name, test := range tests {
		helper.Logger.SetLogLevel(4)
		if name != "TransactionNonceCheck2" {
			continue
		}
		db, _ := ethdb.NewMemDatabase()
		statedb := state.New(nil, db)
		for addr, account := range test.Pre {
			obj := StateObjectFromAccount(db, addr, account)
			statedb.SetStateObject(obj)
			for a, v := range account.Storage {
				obj.SetState(helper.FromHex(a), ethutil.NewValue(helper.FromHex(v)))
			}
		}

		// XXX Yeah, yeah...
		env := make(map[string]string)
		env["currentCoinbase"] = test.Env.CurrentCoinbase
		env["currentDifficulty"] = test.Env.CurrentDifficulty
		env["currentGasLimit"] = test.Env.CurrentGasLimit
		env["currentNumber"] = test.Env.CurrentNumber
		env["previousHash"] = test.Env.PreviousHash
		if n, ok := test.Env.CurrentTimestamp.(float64); ok {
			env["currentTimestamp"] = strconv.Itoa(int(n))
		} else {
			env["currentTimestamp"] = test.Env.CurrentTimestamp.(string)
		}

		var (
			ret  []byte
			gas  *big.Int
			err  error
			logs state.Logs
		)

		isVmTest := len(test.Exec) > 0
		if isVmTest {
			ret, logs, gas, err = helper.RunVm(statedb, env, test.Exec)
		} else {
			ret, logs, gas, err = helper.RunState(statedb, env, test.Transaction)
		}

		rexp := helper.FromHex(test.Out)
		if bytes.Compare(rexp, ret) != 0 {
			t.Errorf("%s's return failed. Expected %x, got %x\n", name, rexp, ret)
		}

		if isVmTest {
			if len(test.Gas) == 0 && err == nil {
				t.Errorf("%s's gas unspecified, indicating an error. VM returned (incorrectly) successfull", name)
			} else {
				gexp := ethutil.Big(test.Gas)
				if gexp.Cmp(gas) != 0 {
					t.Errorf("%s's gas failed. Expected %v, got %v\n", name, gexp, gas)
				}
			}
		}

		for addr, account := range test.Post {
			obj := statedb.GetStateObject(helper.FromHex(addr))
			if obj == nil {
				continue
			}

			if len(test.Exec) == 0 {
				if obj.Balance().Cmp(ethutil.Big(account.Balance)) != 0 {
					t.Errorf("%s's : (%x) balance failed. Expected %v, got %v => %v\n", name, obj.Address()[:4], account.Balance, obj.Balance(), new(big.Int).Sub(ethutil.Big(account.Balance), obj.Balance()))
				}
			}

			for addr, value := range account.Storage {
				v := obj.GetState(helper.FromHex(addr)).Bytes()
				vexp := helper.FromHex(value)

				if bytes.Compare(v, vexp) != 0 {
					t.Errorf("%s's : (%x: %s) storage failed. Expected %x, got %x (%v %v)\n", name, obj.Address()[0:4], addr, vexp, v, ethutil.BigD(vexp), ethutil.BigD(v))
				}
			}
		}

		if len(test.Logs) > 0 {
			for i, log := range test.Logs {
				genBloom := ethutil.LeftPadBytes(types.LogsBloom(state.Logs{logs[i]}).Bytes(), 64)
				if !bytes.Equal(genBloom, ethutil.Hex2Bytes(log.BloomF)) {
					t.Errorf("bloom mismatch")
				}
			}
		}
	}
	logger.Flush()
}

// I've created a new function for each tests so it's easier to identify where the problem lies if any of them fail.
func TestVMArithmetic(t *testing.T) {
	const fn = "../files/VMTests/vmArithmeticTest.json"
	RunVmTest(fn, t)
}

func TestSystemOperations(t *testing.T) {
	const fn = "../files/VMTests/vmSystemOperationsTest.json"
	RunVmTest(fn, t)
}

func TestBitwiseLogicOperation(t *testing.T) {
	const fn = "../files/VMTests/vmBitwiseLogicOperationTest.json"
	RunVmTest(fn, t)
}

func TestBlockInfo(t *testing.T) {
	const fn = "../files/VMTests/vmBlockInfoTest.json"
	RunVmTest(fn, t)
}

func TestEnvironmentalInfo(t *testing.T) {
	const fn = "../files/VMTests/vmEnvironmentalInfoTest.json"
	RunVmTest(fn, t)
}

func TestFlowOperation(t *testing.T) {
	const fn = "../files/VMTests/vmIOandFlowOperationsTest.json"
	RunVmTest(fn, t)
}

func TestPushDupSwap(t *testing.T) {
	const fn = "../files/VMTests/vmPushDupSwapTest.json"
	RunVmTest(fn, t)
}

func TestVMSha3(t *testing.T) {
	const fn = "../files/VMTests/vmSha3Test.json"
	RunVmTest(fn, t)
}

func TestVm(t *testing.T) {
	const fn = "../files/VMTests/vmtests.json"
	RunVmTest(fn, t)
}

func TestVmLog(t *testing.T) {
	const fn = "../files/VMTests/vmLogTest.json"
	RunVmTest(fn, t)
}

func TestStateSystemOperations(t *testing.T) {
	const fn = "../files/StateTests/stSystemOperationsTest.json"
	RunVmTest(fn, t)
}

func TestStatePreCompiledContracts(t *testing.T) {
	const fn = "../files/StateTests/stPreCompiledContracts.json"
	RunVmTest(fn, t)
}

func TestStateRecursiveCreate(t *testing.T) {
	const fn = "../files/StateTests/stRecursiveCreate.json"
	RunVmTest(fn, t)
}

func TestStateSpecial(t *testing.T) {
	const fn = "../files/StateTests/stSpecialTest.json"
	RunVmTest(fn, t)
}

func TestStateRefund(t *testing.T) {
	const fn = "../files/StateTests/stRefundTest.json"
	RunVmTest(fn, t)
}

func TestStateBlockHash(t *testing.T) {
	const fn = "../files/StateTests/stBlockHashTest.json"
	RunVmTest(fn, t)
}

func TestStateInitCode(t *testing.T) {
	const fn = "../files/StateTests/stInitCodeTest.json"
	RunVmTest(fn, t)
}

func TestStateLog(t *testing.T) {
	const fn = "../files/StateTests/stLogTests.json"
	RunVmTest(fn, t)
}

func TestStateTransaction(t *testing.T) {
	t.Skip()
	const fn = "../files/StateTests/stTransactionTest.json"
	RunVmTest(fn, t)
}
<|endoftext|>


<commit_before>package unicode

import "fmt"

// Kode for Oppgave 4a
func Translate(expression string, language string) string {
	return ""
	fmt.Printf("\x22\x6E\x6F\x72\x20\x6F\x67\x20\x73\xF8\x72")
}
<commit_msg>fiksa på 4a<commit_after>package unicode

// Kode for Oppgave 4a
func Translate(expression string, language string) string {
	return
	//("\x22\x6E\x6F\x72\x20\x6F\x67\x20\x73\xF8\x72")
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Knative 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 v1alpha1

import (
	"github.com/knative/eventing/pkg/apis/messaging"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
)

// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: messaging.GroupName, Version: "v1alpha1"}

// Kind takes an unqualified kind and returns back a Group qualified GroupKind
func Kind(kind string) schema.GroupKind {
	return SchemeGroupVersion.WithKind(kind).GroupKind()
}

// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
	return SchemeGroupVersion.WithResource(resource).GroupResource()
}

var (
	SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
	AddToScheme   = SchemeBuilder.AddToScheme
)

// Adds the list of known types to Scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
	scheme.AddKnownTypes(SchemeGroupVersion,
		&InMemoryChannel{},
		&InMemoryChannelList{},
		&Sequence{},
		&Sequence{},
	)
	metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
	return nil
}
<commit_msg>fix SequenceList registration (#1528)<commit_after>/*
Copyright 2019 The Knative 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 v1alpha1

import (
	"github.com/knative/eventing/pkg/apis/messaging"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
)

// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: messaging.GroupName, Version: "v1alpha1"}

// Kind takes an unqualified kind and returns back a Group qualified GroupKind
func Kind(kind string) schema.GroupKind {
	return SchemeGroupVersion.WithKind(kind).GroupKind()
}

// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
	return SchemeGroupVersion.WithResource(resource).GroupResource()
}

var (
	SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
	AddToScheme   = SchemeBuilder.AddToScheme
)

// Adds the list of known types to Scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
	scheme.AddKnownTypes(SchemeGroupVersion,
		&InMemoryChannel{},
		&InMemoryChannelList{},
		&Sequence{},
		&SequenceList{},
	)
	metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
	return nil
}
<|endoftext|>


<commit_before>// Package database provides an abstraction over getting and writing a
// database file.
package database

import (
	"compress/gzip"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"time"

	"github.com/maxmind/geoipupdate/v4/pkg/geoipupdate"
	"github.com/maxmind/geoipupdate/v4/pkg/geoipupdate/internal"
	"github.com/pkg/errors"
)

// HTTPDatabaseReader is a Reader that uses an HTTP client to retrieve
// databases.
type HTTPDatabaseReader struct {
	client            *http.Client
	retryFor          time.Duration
	url               string
	licenseKey        string
	accountID         int
	preserveFileTimes bool
	verbose           bool
}

// NewHTTPDatabaseReader creates a Reader that downloads database updates via
// HTTP.
func NewHTTPDatabaseReader(client *http.Client, config *geoipupdate.Config) Reader {
	return &HTTPDatabaseReader{
		client:            client,
		retryFor:          config.RetryFor,
		url:               config.URL,
		licenseKey:        config.LicenseKey,
		accountID:         config.AccountID,
		preserveFileTimes: config.PreserveFileTimes,
		verbose:           config.Verbose,
	}
}

// Get retrieves the given edition ID using an HTTP client, writes it to the
// Writer, and validates the hash before committing.
func (reader *HTTPDatabaseReader) Get(destination Writer, editionID string) error {
	defer func() {
		if err := destination.Close(); err != nil {
			log.Println(err)
		}
	}()

	maxMindURL := fmt.Sprintf(
		"%s/geoip/databases/%s/update?db_md5=%s",
		reader.url,
		url.PathEscape(editionID),
		url.QueryEscape(destination.GetHash()),
	)

	req, err := http.NewRequest(http.MethodGet, maxMindURL, nil) // nolint: noctx
	if err != nil {
		return errors.Wrap(err, "error creating request")
	}
	req.SetBasicAuth(fmt.Sprintf("%d", reader.accountID), reader.licenseKey)

	if reader.verbose {
		log.Printf("Performing update request to %s", maxMindURL)
	}
	response, err := internal.MaybeRetryRequest(reader.client, reader.retryFor, req)
	if err != nil {
		return errors.Wrap(err, "error performing HTTP request")
	}
	defer func() {
		if err := response.Body.Close(); err != nil {
			log.Fatalf("Error closing response body: %+v", errors.Wrap(err, "closing body"))
		}
	}()

	if response.StatusCode == http.StatusNotModified {
		if reader.verbose {
			log.Printf("No new updates available for %s", editionID)
		}
		return nil
	}

	if response.StatusCode != http.StatusOK {
		buf, err := ioutil.ReadAll(io.LimitReader(response.Body, 256))
		if err == nil {
			return errors.Errorf("unexpected HTTP status code: %s: %s", response.Status, buf)
		}
		return errors.Errorf("unexpected HTTP status code: %s", response.Status)
	}

	gzReader, err := gzip.NewReader(response.Body)
	if err != nil {
		return errors.Wrap(err, "encountered an error creating GZIP reader")
	}
	defer func() {
		if err := gzReader.Close(); err != nil {
			log.Printf("error closing gzip reader: %s", err)
		}
	}()

	if _, err = io.Copy(destination, gzReader); err != nil { //nolint:gosec
		return errors.Wrap(err, "error writing response")
	}

	newMD5 := response.Header.Get("X-Database-MD5")
	if newMD5 == "" {
		return errors.New("no X-Database-MD5 header found")
	}
	if err := destination.ValidHash(newMD5); err != nil {
		return err
	}

	if err := destination.Commit(); err != nil {
		return errors.Wrap(err, "encountered an issue committing database update")
	}

	if reader.preserveFileTimes {
		modificationTime, err := lastModified(response.Header.Get("Last-Modified"))
		if err != nil {
			return errors.Wrap(err, "unable to get last modified time")
		}
		err = destination.SetFileModificationTime(modificationTime)
		if err != nil {
			return errors.Wrap(err, "unable to set modification time")
		}
	}

	return nil
}

// LastModified retrieves the date that the MaxMind database was last modified.
func lastModified(lastModified string) (time.Time, error) {
	if lastModified == "" {
		return time.Time{}, errors.New("no Last-Modified header found")
	}

	t, err := time.ParseInLocation(time.RFC1123, lastModified, time.UTC)
	if err != nil {
		return time.Time{}, errors.Wrap(err, "error parsing time")
	}

	return t, nil
}
<commit_msg>Move log call up<commit_after>// Package database provides an abstraction over getting and writing a
// database file.
package database

import (
	"compress/gzip"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"time"

	"github.com/maxmind/geoipupdate/v4/pkg/geoipupdate"
	"github.com/maxmind/geoipupdate/v4/pkg/geoipupdate/internal"
	"github.com/pkg/errors"
)

// HTTPDatabaseReader is a Reader that uses an HTTP client to retrieve
// databases.
type HTTPDatabaseReader struct {
	client            *http.Client
	retryFor          time.Duration
	url               string
	licenseKey        string
	accountID         int
	preserveFileTimes bool
	verbose           bool
}

// NewHTTPDatabaseReader creates a Reader that downloads database updates via
// HTTP.
func NewHTTPDatabaseReader(client *http.Client, config *geoipupdate.Config) Reader {
	return &HTTPDatabaseReader{
		client:            client,
		retryFor:          config.RetryFor,
		url:               config.URL,
		licenseKey:        config.LicenseKey,
		accountID:         config.AccountID,
		preserveFileTimes: config.PreserveFileTimes,
		verbose:           config.Verbose,
	}
}

// Get retrieves the given edition ID using an HTTP client, writes it to the
// Writer, and validates the hash before committing.
func (reader *HTTPDatabaseReader) Get(destination Writer, editionID string) error {
	defer func() {
		if err := destination.Close(); err != nil {
			log.Println(err)
		}
	}()

	maxMindURL := fmt.Sprintf(
		"%s/geoip/databases/%s/update?db_md5=%s",
		reader.url,
		url.PathEscape(editionID),
		url.QueryEscape(destination.GetHash()),
	)

	if reader.verbose {
		log.Printf("Performing update request to %s", maxMindURL)
	}

	req, err := http.NewRequest(http.MethodGet, maxMindURL, nil) // nolint: noctx
	if err != nil {
		return errors.Wrap(err, "error creating request")
	}
	req.SetBasicAuth(fmt.Sprintf("%d", reader.accountID), reader.licenseKey)

	response, err := internal.MaybeRetryRequest(reader.client, reader.retryFor, req)
	if err != nil {
		return errors.Wrap(err, "error performing HTTP request")
	}
	defer func() {
		if err := response.Body.Close(); err != nil {
			log.Fatalf("Error closing response body: %+v", errors.Wrap(err, "closing body"))
		}
	}()

	if response.StatusCode == http.StatusNotModified {
		if reader.verbose {
			log.Printf("No new updates available for %s", editionID)
		}
		return nil
	}

	if response.StatusCode != http.StatusOK {
		buf, err := ioutil.ReadAll(io.LimitReader(response.Body, 256))
		if err == nil {
			return errors.Errorf("unexpected HTTP status code: %s: %s", response.Status, buf)
		}
		return errors.Errorf("unexpected HTTP status code: %s", response.Status)
	}

	gzReader, err := gzip.NewReader(response.Body)
	if err != nil {
		return errors.Wrap(err, "encountered an error creating GZIP reader")
	}
	defer func() {
		if err := gzReader.Close(); err != nil {
			log.Printf("error closing gzip reader: %s", err)
		}
	}()

	if _, err = io.Copy(destination, gzReader); err != nil { //nolint:gosec
		return errors.Wrap(err, "error writing response")
	}

	newMD5 := response.Header.Get("X-Database-MD5")
	if newMD5 == "" {
		return errors.New("no X-Database-MD5 header found")
	}
	if err := destination.ValidHash(newMD5); err != nil {
		return err
	}

	if err := destination.Commit(); err != nil {
		return errors.Wrap(err, "encountered an issue committing database update")
	}

	if reader.preserveFileTimes {
		modificationTime, err := lastModified(response.Header.Get("Last-Modified"))
		if err != nil {
			return errors.Wrap(err, "unable to get last modified time")
		}
		err = destination.SetFileModificationTime(modificationTime)
		if err != nil {
			return errors.Wrap(err, "unable to set modification time")
		}
	}

	return nil
}

// LastModified retrieves the date that the MaxMind database was last modified.
func lastModified(lastModified string) (time.Time, error) {
	if lastModified == "" {
		return time.Time{}, errors.New("no Last-Modified header found")
	}

	t, err := time.ParseInLocation(time.RFC1123, lastModified, time.UTC)
	if err != nil {
		return time.Time{}, errors.Wrap(err, "error parsing time")
	}

	return t, nil
}
<|endoftext|>


<commit_before>// Package database provides an abstraction over getting and writing a
// database file.
package database

import (
	"compress/gzip"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"time"

	"github.com/maxmind/geoipupdate/v4/pkg/geoipupdate"
	"github.com/maxmind/geoipupdate/v4/pkg/geoipupdate/internal"
)

// HTTPDatabaseReader is a Reader that uses an HTTP client to retrieve
// databases.
type HTTPDatabaseReader struct {
	client            *http.Client
	retryFor          time.Duration
	url               string
	licenseKey        string
	accountID         int
	preserveFileTimes bool
	verbose           bool
}

// NewHTTPDatabaseReader creates a Reader that downloads database updates via
// HTTP.
func NewHTTPDatabaseReader(client *http.Client, config *geoipupdate.Config) Reader {
	return &HTTPDatabaseReader{
		client:            client,
		retryFor:          config.RetryFor,
		url:               config.URL,
		licenseKey:        config.LicenseKey,
		accountID:         config.AccountID,
		preserveFileTimes: config.PreserveFileTimes,
		verbose:           config.Verbose,
	}
}

// Get retrieves the given edition ID using an HTTP client, writes it to the
// Writer, and validates the hash before committing.
func (reader *HTTPDatabaseReader) Get(destination Writer, editionID string) error {
	defer func() {
		if err := destination.Close(); err != nil {
			log.Println(err)
		}
	}()

	updateURL := fmt.Sprintf(
		"%s/geoip/databases/%s/update?db_md5=%s",
		reader.url,
		url.PathEscape(editionID),
		url.QueryEscape(destination.GetHash()),
	)

	var modified bool
	// It'd be nice to not use a temporary file here. However the Writer API does
	// not currently support multiple attempts to download the file (it assumes
	// we'll begin writing once). Using a temporary file here should be a less
	// disruptive alternative to changing the API. If we change that API in the
	// future, adding something like Reset() may be desirable.
	tempFile, err := ioutil.TempFile("", "geoipupdate")
	if err != nil {
		return fmt.Errorf("error opening temporary file: %w", err)
	}
	defer func() {
		if err := tempFile.Close(); err != nil {
			log.Printf("error closing temporary file: %s", err)
		}
		if err := os.Remove(tempFile.Name()); err != nil {
			log.Printf("error removing temporary file: %s", err)
		}
	}()
	var newMD5 string
	var modificationTime time.Time
	err = internal.RetryWithBackoff(
		func() error {
			if reader.verbose {
				log.Printf("Performing update request to %s", updateURL)
			}

			newMD5, modificationTime, modified, err = reader.download(
				updateURL,
				editionID,
				tempFile,
			)
			return err
		},
		reader.retryFor,
	)
	if err != nil {
		return err
	}

	if !modified {
		return nil
	}

	if _, err := tempFile.Seek(0, 0); err != nil {
		return fmt.Errorf("error seeking: %w", err)
	}

	if _, err = io.Copy(destination, tempFile); err != nil {
		return fmt.Errorf("error writing response: %w", err)
	}

	if err := destination.ValidHash(newMD5); err != nil {
		return err
	}

	if err := destination.Commit(); err != nil {
		return fmt.Errorf("encountered an issue committing database update: %w", err)
	}

	if reader.preserveFileTimes {
		err = destination.SetFileModificationTime(modificationTime)
		if err != nil {
			return fmt.Errorf("unable to set modification time: %w", err)
		}
	}

	return nil
}

func (reader *HTTPDatabaseReader) download(
	updateURL,
	editionID string,
	tempFile *os.File,
) (string, time.Time, bool, error) {
	// Prepare a clean slate for this download attempt.

	if err := tempFile.Truncate(0); err != nil {
		return "", time.Time{}, false, fmt.Errorf("error truncating: %w", err)
	}
	if _, err := tempFile.Seek(0, 0); err != nil {
		return "", time.Time{}, false, fmt.Errorf("error seeking: %w", err)
	}

	// Perform the download.
	//nolint: noctx // using the context would require an API change
	req, err := http.NewRequest(http.MethodGet, updateURL, nil)
	if err != nil {
		return "", time.Time{}, false, fmt.Errorf("error creating request: %w", err)
	}
	req.Header.Add("User-Agent", "geoipupdate/"+geoipupdate.Version)
	req.SetBasicAuth(fmt.Sprintf("%d", reader.accountID), reader.licenseKey)

	response, err := reader.client.Do(req)
	if err != nil {
		return "", time.Time{}, false, fmt.Errorf("error performing HTTP request: %w", err)
	}

	defer response.Body.Close()

	if response.StatusCode == http.StatusNotModified {
		if reader.verbose {
			log.Printf("No new updates available for %s", editionID)
		}
		return "", time.Time{}, false, nil
	}

	if response.StatusCode != http.StatusOK {
		buf, err := ioutil.ReadAll(io.LimitReader(response.Body, 256))
		if err == nil {
			err := internal.HTTPError{
				Body:       string(buf),
				StatusCode: response.StatusCode,
			}
			return "", time.Time{}, false, fmt.Errorf("unexpected HTTP status code: %w", err)
		}
		err = internal.HTTPError{
			Body:       string(buf),
			StatusCode: response.StatusCode,
		}
		return "", time.Time{}, false, fmt.Errorf("unexpected HTTP status code: %w", err)
	}

	gzReader, err := gzip.NewReader(response.Body)
	if err != nil {
		return "", time.Time{}, false, fmt.Errorf("encountered an error creating GZIP reader: %w", err)
	}
	defer func() {
		if err := gzReader.Close(); err != nil {
			log.Printf("error closing gzip reader: %s", err)
		}
	}()

	//nolint:gosec // A decompression bomb is unlikely here
	if _, err := io.Copy(tempFile, gzReader); err != nil {
		return "", time.Time{}, false, fmt.Errorf("error writing response: %w", err)
	}

	newMD5 := response.Header.Get("X-Database-MD5")
	if newMD5 == "" {
		return "", time.Time{}, false, errors.New("no X-Database-MD5 header found")
	}

	modificationTime, err := lastModified(response.Header.Get("Last-Modified"))
	if err != nil {
		return "", time.Time{}, false, fmt.Errorf("unable to get last modified time: %w", err)
	}

	return newMD5, modificationTime, true, nil
}

// LastModified retrieves the date that the MaxMind database was last modified.
func lastModified(lastModified string) (time.Time, error) {
	if lastModified == "" {
		return time.Time{}, errors.New("no Last-Modified header found")
	}

	t, err := time.ParseInLocation(time.RFC1123, lastModified, time.UTC)
	if err != nil {
		return time.Time{}, fmt.Errorf("error parsing time: %w", err)
	}

	return t, nil
}
<commit_msg>Combine and Simplify branches<commit_after>// Package database provides an abstraction over getting and writing a
// database file.
package database

import (
	"compress/gzip"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"time"

	"github.com/maxmind/geoipupdate/v4/pkg/geoipupdate"
	"github.com/maxmind/geoipupdate/v4/pkg/geoipupdate/internal"
)

// HTTPDatabaseReader is a Reader that uses an HTTP client to retrieve
// databases.
type HTTPDatabaseReader struct {
	client            *http.Client
	retryFor          time.Duration
	url               string
	licenseKey        string
	accountID         int
	preserveFileTimes bool
	verbose           bool
}

// NewHTTPDatabaseReader creates a Reader that downloads database updates via
// HTTP.
func NewHTTPDatabaseReader(client *http.Client, config *geoipupdate.Config) Reader {
	return &HTTPDatabaseReader{
		client:            client,
		retryFor:          config.RetryFor,
		url:               config.URL,
		licenseKey:        config.LicenseKey,
		accountID:         config.AccountID,
		preserveFileTimes: config.PreserveFileTimes,
		verbose:           config.Verbose,
	}
}

// Get retrieves the given edition ID using an HTTP client, writes it to the
// Writer, and validates the hash before committing.
func (reader *HTTPDatabaseReader) Get(destination Writer, editionID string) error {
	defer func() {
		if err := destination.Close(); err != nil {
			log.Println(err)
		}
	}()

	updateURL := fmt.Sprintf(
		"%s/geoip/databases/%s/update?db_md5=%s",
		reader.url,
		url.PathEscape(editionID),
		url.QueryEscape(destination.GetHash()),
	)

	var modified bool
	// It'd be nice to not use a temporary file here. However the Writer API does
	// not currently support multiple attempts to download the file (it assumes
	// we'll begin writing once). Using a temporary file here should be a less
	// disruptive alternative to changing the API. If we change that API in the
	// future, adding something like Reset() may be desirable.
	tempFile, err := ioutil.TempFile("", "geoipupdate")
	if err != nil {
		return fmt.Errorf("error opening temporary file: %w", err)
	}
	defer func() {
		if err := tempFile.Close(); err != nil {
			log.Printf("error closing temporary file: %s", err)
		}
		if err := os.Remove(tempFile.Name()); err != nil {
			log.Printf("error removing temporary file: %s", err)
		}
	}()
	var newMD5 string
	var modificationTime time.Time
	err = internal.RetryWithBackoff(
		func() error {
			if reader.verbose {
				log.Printf("Performing update request to %s", updateURL)
			}

			newMD5, modificationTime, modified, err = reader.download(
				updateURL,
				editionID,
				tempFile,
			)
			return err
		},
		reader.retryFor,
	)
	if err != nil {
		return err
	}

	if !modified {
		return nil
	}

	if _, err := tempFile.Seek(0, 0); err != nil {
		return fmt.Errorf("error seeking: %w", err)
	}

	if _, err = io.Copy(destination, tempFile); err != nil {
		return fmt.Errorf("error writing response: %w", err)
	}

	if err := destination.ValidHash(newMD5); err != nil {
		return err
	}

	if err := destination.Commit(); err != nil {
		return fmt.Errorf("encountered an issue committing database update: %w", err)
	}

	if reader.preserveFileTimes {
		err = destination.SetFileModificationTime(modificationTime)
		if err != nil {
			return fmt.Errorf("unable to set modification time: %w", err)
		}
	}

	return nil
}

func (reader *HTTPDatabaseReader) download(
	updateURL,
	editionID string,
	tempFile *os.File,
) (string, time.Time, bool, error) {
	// Prepare a clean slate for this download attempt.

	if err := tempFile.Truncate(0); err != nil {
		return "", time.Time{}, false, fmt.Errorf("error truncating: %w", err)
	}
	if _, err := tempFile.Seek(0, 0); err != nil {
		return "", time.Time{}, false, fmt.Errorf("error seeking: %w", err)
	}

	// Perform the download.
	//nolint: noctx // using the context would require an API change
	req, err := http.NewRequest(http.MethodGet, updateURL, nil)
	if err != nil {
		return "", time.Time{}, false, fmt.Errorf("error creating request: %w", err)
	}
	req.Header.Add("User-Agent", "geoipupdate/"+geoipupdate.Version)
	req.SetBasicAuth(fmt.Sprintf("%d", reader.accountID), reader.licenseKey)

	response, err := reader.client.Do(req)
	if err != nil {
		return "", time.Time{}, false, fmt.Errorf("error performing HTTP request: %w", err)
	}

	defer response.Body.Close()

	if response.StatusCode == http.StatusNotModified {
		if reader.verbose {
			log.Printf("No new updates available for %s", editionID)
		}
		return "", time.Time{}, false, nil
	}

	if response.StatusCode != http.StatusOK {
		buf, _ := ioutil.ReadAll(io.LimitReader(response.Body, 256))
		httpErr := internal.HTTPError{
			Body:       string(buf),
			StatusCode: response.StatusCode,
		}
		return "", time.Time{}, false, fmt.Errorf("unexpected HTTP status code: %w", httpErr)
	}

	gzReader, err := gzip.NewReader(response.Body)
	if err != nil {
		return "", time.Time{}, false, fmt.Errorf("encountered an error creating GZIP reader: %w", err)
	}
	defer func() {
		if err := gzReader.Close(); err != nil {
			log.Printf("error closing gzip reader: %s", err)
		}
	}()

	//nolint:gosec // A decompression bomb is unlikely here
	if _, err := io.Copy(tempFile, gzReader); err != nil {
		return "", time.Time{}, false, fmt.Errorf("error writing response: %w", err)
	}

	newMD5 := response.Header.Get("X-Database-MD5")
	if newMD5 == "" {
		return "", time.Time{}, false, errors.New("no X-Database-MD5 header found")
	}

	modificationTime, err := lastModified(response.Header.Get("Last-Modified"))
	if err != nil {
		return "", time.Time{}, false, fmt.Errorf("unable to get last modified time: %w", err)
	}

	return newMD5, modificationTime, true, nil
}

// LastModified retrieves the date that the MaxMind database was last modified.
func lastModified(lastModified string) (time.Time, error) {
	if lastModified == "" {
		return time.Time{}, errors.New("no Last-Modified header found")
	}

	t, err := time.ParseInLocation(time.RFC1123, lastModified, time.UTC)
	if err != nil {
		return time.Time{}, fmt.Errorf("error parsing time: %w", err)
	}

	return t, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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 hyperkit

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"syscall"
	"time"

	"github.com/docker/machine/libmachine/drivers"
	"github.com/docker/machine/libmachine/log"
	"github.com/docker/machine/libmachine/mcnflag"
	"github.com/docker/machine/libmachine/mcnutils"
	"github.com/docker/machine/libmachine/ssh"
	"github.com/docker/machine/libmachine/state"
	hyperkit "github.com/moby/hyperkit/go"
	"github.com/pborman/uuid"
	vmnet "github.com/zchee/go-vmnet"
	commonutil "k8s.io/minikube/pkg/util"
)

const (
	isoFilename     = "boot2docker.iso"
	pidFileName     = "hyperkit.pid"
	machineFileName = "hyperkit.json"
)

type Driver struct {
	*drivers.BaseDriver
	Boot2DockerURL string
	DiskSize       int
	CPU            int
	Memory         int
	Cmdline        string
}

func NewDriver(hostName, storePath string) *Driver {
	return &Driver{
		BaseDriver: &drivers.BaseDriver{
			SSHUser: "docker",
		},
	}
}

func (d *Driver) Create() error {
	b2dutils := mcnutils.NewB2dUtils(d.StorePath)

	if err := ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil {
		return err
	}

	if err := b2dutils.CopyIsoToMachineDir(d.Boot2DockerURL, d.MachineName); err != nil {
		return err
	}
	isoPath := d.ResolveStorePath(isoFilename)
	if err := d.extractKernel(isoPath); err != nil {
		return err
	}

	return d.Start()
}

// DriverName returns the name of the driver
func (d *Driver) DriverName() string {
	return "hyperkit"
}

// GetCreateFlags returns the mcnflag.Flag slice representing the flags
// that can be set, their descriptions and defaults.
func (d *Driver) GetCreateFlags() []mcnflag.Flag {
	return nil
}

// GetSSHHostname returns hostname for use with ssh
func (d *Driver) GetSSHHostname() (string, error) {
	return d.IPAddress, nil
}

// GetURL returns a Docker compatible host URL for connecting to this host
// e.g. tcp://1.2.3.4:2376
func (d *Driver) GetURL() (string, error) {
	ip, err := d.GetIP()
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("tcp://%s:2376", ip), nil
}

// GetState returns the state that the host is in (running, stopped, etc)
func (d *Driver) GetState() (state.State, error) {
	pid := d.getPid()
	if pid == 0 {
		return state.Stopped, nil
	}
	p, err := os.FindProcess(pid)
	if err != nil {
		return state.Error, err
	}

	// Sending a signal of 0 can be used to check the existence of a process.
	if err := p.Signal(syscall.Signal(0)); err != nil {
		return state.Stopped, nil
	}
	if p == nil {
		return state.Stopped, nil
	}
	return state.Running, nil
}

// Kill stops a host forcefully
func (d *Driver) Kill() error {
	return d.sendSignal(syscall.SIGKILL)
}

// PreCreateCheck allows for pre-create operations to make sure a driver is ready for creation
func (d *Driver) PreCreateCheck() error {
	return nil
}

// Remove a host
func (d *Driver) Remove() error {
	s, err := d.GetState()
	if err != nil || s == state.Error {
		log.Infof("Error checking machine status: %s, assuming it has been removed already", err)
	}
	if s == state.Running {
		if err := d.Stop(); err != nil {
			return err
		}
	}
	return nil
}

// Restart a host. This may just call Stop(); Start() if the provider does not
// have any special restart behaviour.
func (d *Driver) Restart() error {
	for _, f := range []func() error{d.Stop, d.Start} {
		if err := f(); err != nil {
			return err
		}
	}
	return nil
}

// SetConfigFromFlags configures the driver with the object that was returned
// by RegisterCreateFlags
func (d *Driver) SetConfigFromFlags(opts drivers.DriverOptions) error {
	return nil
}

// Start a host
func (d *Driver) Start() error {

	// TODO: handle different disk types.
	diskPath := filepath.Join(d.ResolveStorePath("."), d.MachineName+".rawdisk")
	if _, err := os.Stat(diskPath); os.IsNotExist(err) {
		if err := createDiskImage(d.publicSSHKeyPath(), diskPath, d.DiskSize); err != nil {
			return err
		}
		if err := fixPermissions(d.ResolveStorePath(".")); err != nil {
			return err
		}
	}

	h, err := hyperkit.New("", "", filepath.Join(d.StorePath, "machines", d.MachineName))
	if err != nil {
		return err
	}

	// TODO: handle the rest of our settings.
	h.Kernel = d.ResolveStorePath("bzimage")
	h.Initrd = d.ResolveStorePath("initrd")
	h.VMNet = true
	h.ISOImage = d.ResolveStorePath(isoFilename)
	h.Console = hyperkit.ConsoleFile
	h.CPUs = d.CPU
	h.Memory = d.Memory

	// Set UUID
	h.UUID = uuid.NewUUID().String()
	log.Infof("Generated UUID %s", h.UUID)
	mac, err := vmnet.GetMACAddressFromUUID(h.UUID)
	if err != nil {
		return err
	}

	// Need to strip 0's
	mac = trimMacAddress(mac)
	log.Infof("Generated MAC %s", mac)

	h.Disks = []hyperkit.DiskConfig{
		{
			Path:   diskPath,
			Size:   d.DiskSize,
			Driver: "virtio-blk",
		},
	}
	log.Infof("Starting with cmdline: %s", d.Cmdline)
	if err := h.Start(d.Cmdline); err != nil {
		return err
	}

	getIP := func() error {
		var err error
		d.IPAddress, err = GetIPAddressByMACAddress(mac)
		if err != nil {
			return &commonutil.RetriableError{Err: err}
		}
		return nil
	}

	if err := commonutil.RetryAfter(30, getIP, 2*time.Second); err != nil {
		return fmt.Errorf("IP address never found in dhcp leases file %v", err)
	}
	return nil
}

// Stop a host gracefully
func (d *Driver) Stop() error {
	return d.sendSignal(syscall.SIGTERM)
}

func (d *Driver) extractKernel(isoPath string) error {
	for _, f := range []struct {
		pathInIso string
		destPath  string
	}{
		{"/boot/bzimage", "bzimage"},
		{"/boot/initrd", "initrd"},
		{"/isolinux/isolinux.cfg", "isolinux.cfg"},
	} {
		fullDestPath := d.ResolveStorePath(f.destPath)
		if err := ExtractFile(isoPath, f.pathInIso, fullDestPath); err != nil {
			return err
		}
	}
	return nil
}

func (d *Driver) publicSSHKeyPath() string {
	return d.GetSSHKeyPath() + ".pub"
}

func (d *Driver) sendSignal(s os.Signal) error {
	pid := d.getPid()
	proc, err := os.FindProcess(pid)
	if err != nil {
		return err
	}

	return proc.Signal(s)
}

func (d *Driver) getPid() int {
	pidPath := d.ResolveStorePath(machineFileName)

	f, err := os.Open(pidPath)
	if err != nil {
		log.Warnf("Error reading pid file: %s", err)
		return 0
	}
	dec := json.NewDecoder(f)
	config := hyperkit.HyperKit{}
	if err := dec.Decode(&config); err != nil {
		log.Warnf("Error decoding pid file: %s", err)
		return 0
	}

	return config.Pid
}
<commit_msg>Add darwin build tag.<commit_after>// +build darwin

/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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 hyperkit

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"syscall"
	"time"

	"github.com/docker/machine/libmachine/drivers"
	"github.com/docker/machine/libmachine/log"
	"github.com/docker/machine/libmachine/mcnflag"
	"github.com/docker/machine/libmachine/mcnutils"
	"github.com/docker/machine/libmachine/ssh"
	"github.com/docker/machine/libmachine/state"
	hyperkit "github.com/moby/hyperkit/go"
	"github.com/pborman/uuid"
	vmnet "github.com/zchee/go-vmnet"
	commonutil "k8s.io/minikube/pkg/util"
)

const (
	isoFilename     = "boot2docker.iso"
	pidFileName     = "hyperkit.pid"
	machineFileName = "hyperkit.json"
)

type Driver struct {
	*drivers.BaseDriver
	Boot2DockerURL string
	DiskSize       int
	CPU            int
	Memory         int
	Cmdline        string
}

func NewDriver(hostName, storePath string) *Driver {
	return &Driver{
		BaseDriver: &drivers.BaseDriver{
			SSHUser: "docker",
		},
	}
}

func (d *Driver) Create() error {
	b2dutils := mcnutils.NewB2dUtils(d.StorePath)

	if err := ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil {
		return err
	}

	if err := b2dutils.CopyIsoToMachineDir(d.Boot2DockerURL, d.MachineName); err != nil {
		return err
	}
	isoPath := d.ResolveStorePath(isoFilename)
	if err := d.extractKernel(isoPath); err != nil {
		return err
	}

	return d.Start()
}

// DriverName returns the name of the driver
func (d *Driver) DriverName() string {
	return "hyperkit"
}

// GetCreateFlags returns the mcnflag.Flag slice representing the flags
// that can be set, their descriptions and defaults.
func (d *Driver) GetCreateFlags() []mcnflag.Flag {
	return nil
}

// GetSSHHostname returns hostname for use with ssh
func (d *Driver) GetSSHHostname() (string, error) {
	return d.IPAddress, nil
}

// GetURL returns a Docker compatible host URL for connecting to this host
// e.g. tcp://1.2.3.4:2376
func (d *Driver) GetURL() (string, error) {
	ip, err := d.GetIP()
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("tcp://%s:2376", ip), nil
}

// GetState returns the state that the host is in (running, stopped, etc)
func (d *Driver) GetState() (state.State, error) {
	pid := d.getPid()
	if pid == 0 {
		return state.Stopped, nil
	}
	p, err := os.FindProcess(pid)
	if err != nil {
		return state.Error, err
	}

	// Sending a signal of 0 can be used to check the existence of a process.
	if err := p.Signal(syscall.Signal(0)); err != nil {
		return state.Stopped, nil
	}
	if p == nil {
		return state.Stopped, nil
	}
	return state.Running, nil
}

// Kill stops a host forcefully
func (d *Driver) Kill() error {
	return d.sendSignal(syscall.SIGKILL)
}

// PreCreateCheck allows for pre-create operations to make sure a driver is ready for creation
func (d *Driver) PreCreateCheck() error {
	return nil
}

// Remove a host
func (d *Driver) Remove() error {
	s, err := d.GetState()
	if err != nil || s == state.Error {
		log.Infof("Error checking machine status: %s, assuming it has been removed already", err)
	}
	if s == state.Running {
		if err := d.Stop(); err != nil {
			return err
		}
	}
	return nil
}

// Restart a host. This may just call Stop(); Start() if the provider does not
// have any special restart behaviour.
func (d *Driver) Restart() error {
	for _, f := range []func() error{d.Stop, d.Start} {
		if err := f(); err != nil {
			return err
		}
	}
	return nil
}

// SetConfigFromFlags configures the driver with the object that was returned
// by RegisterCreateFlags
func (d *Driver) SetConfigFromFlags(opts drivers.DriverOptions) error {
	return nil
}

// Start a host
func (d *Driver) Start() error {

	// TODO: handle different disk types.
	diskPath := filepath.Join(d.ResolveStorePath("."), d.MachineName+".rawdisk")
	if _, err := os.Stat(diskPath); os.IsNotExist(err) {
		if err := createDiskImage(d.publicSSHKeyPath(), diskPath, d.DiskSize); err != nil {
			return err
		}
		if err := fixPermissions(d.ResolveStorePath(".")); err != nil {
			return err
		}
	}

	h, err := hyperkit.New("", "", filepath.Join(d.StorePath, "machines", d.MachineName))
	if err != nil {
		return err
	}

	// TODO: handle the rest of our settings.
	h.Kernel = d.ResolveStorePath("bzimage")
	h.Initrd = d.ResolveStorePath("initrd")
	h.VMNet = true
	h.ISOImage = d.ResolveStorePath(isoFilename)
	h.Console = hyperkit.ConsoleFile
	h.CPUs = d.CPU
	h.Memory = d.Memory

	// Set UUID
	h.UUID = uuid.NewUUID().String()
	log.Infof("Generated UUID %s", h.UUID)
	mac, err := vmnet.GetMACAddressFromUUID(h.UUID)
	if err != nil {
		return err
	}

	// Need to strip 0's
	mac = trimMacAddress(mac)
	log.Infof("Generated MAC %s", mac)

	h.Disks = []hyperkit.DiskConfig{
		{
			Path:   diskPath,
			Size:   d.DiskSize,
			Driver: "virtio-blk",
		},
	}
	log.Infof("Starting with cmdline: %s", d.Cmdline)
	if err := h.Start(d.Cmdline); err != nil {
		return err
	}

	getIP := func() error {
		var err error
		d.IPAddress, err = GetIPAddressByMACAddress(mac)
		if err != nil {
			return &commonutil.RetriableError{Err: err}
		}
		return nil
	}

	if err := commonutil.RetryAfter(30, getIP, 2*time.Second); err != nil {
		return fmt.Errorf("IP address never found in dhcp leases file %v", err)
	}
	return nil
}

// Stop a host gracefully
func (d *Driver) Stop() error {
	return d.sendSignal(syscall.SIGTERM)
}

func (d *Driver) extractKernel(isoPath string) error {
	for _, f := range []struct {
		pathInIso string
		destPath  string
	}{
		{"/boot/bzimage", "bzimage"},
		{"/boot/initrd", "initrd"},
		{"/isolinux/isolinux.cfg", "isolinux.cfg"},
	} {
		fullDestPath := d.ResolveStorePath(f.destPath)
		if err := ExtractFile(isoPath, f.pathInIso, fullDestPath); err != nil {
			return err
		}
	}
	return nil
}

func (d *Driver) publicSSHKeyPath() string {
	return d.GetSSHKeyPath() + ".pub"
}

func (d *Driver) sendSignal(s os.Signal) error {
	pid := d.getPid()
	proc, err := os.FindProcess(pid)
	if err != nil {
		return err
	}

	return proc.Signal(s)
}

func (d *Driver) getPid() int {
	pidPath := d.ResolveStorePath(machineFileName)

	f, err := os.Open(pidPath)
	if err != nil {
		log.Warnf("Error reading pid file: %s", err)
		return 0
	}
	dec := json.NewDecoder(f)
	config := hyperkit.HyperKit{}
	if err := dec.Decode(&config); err != nil {
		log.Warnf("Error decoding pid file: %s", err)
		return 0
	}

	return config.Pid
}
<|endoftext|>